Unity网络编程(二)TCP 1V1聊天室

服务端

先做个同步的

// 这种通常用于socket的复制
public Socket(SocketInformation socketInformation);
// 后面两种通常用于新创建的socket
public Socket(SocketType socketType, ProtocolType protocolType);
//指定 Socket 类的实例可以使用的寻址方案(通常IPv4 也有IPv6)  Socket类的实例表示的套接字类型  指定 Socket 类支持的协议
public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType);

搭配不当就出异常
常用组合

// Udp通信
Socket socket = new Socket(SocketType.Dgram, ProtocolType.Udp);
// Tcp通信
Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp);

用VS窗口控制台

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;


namespace TalkRoomTCP
{
    class Program
    {
        static void Main(string[] args)
        {
            //创建socket using 代替Close 用完不关闭会占用端口
            using (Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp))
            {
                //绑定IP 端口号
                //IPAddress.Any:相当于"0.0.0.0"的IP地址侦听本地所有网络接口上的客户端活动 有几个侦听几个
                //IPAddress.Broadcast:相当于"255.255.255.255"的IP地址,通常用于Udp的数据包广播。
                //IPAddress.Loopback:相当于"127.0.0.1"的IP地址,用于指代本机。监听"127.0.0.1"时,只能从本机连接到服务端。
                socket.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9999));
                //开启监听 参数是最大接受队列的长度 多于这个就只响应100个 其他拒绝
                socket.Listen(100);

                //accept客户端同步连接 如果客户端不连接,服务器程序阻塞(挂起)这个位置
                using (var clientSocket = socket.Accept())
                {
                    //客户端接收消息 如果客户端不发送数据 服务器程序阻塞(挂起)这个位置
                    var buffer = new byte[1024];
                    int length = clientSocket.Receive(buffer);

                    Console.WriteLine($"接收到客户端消息:{Encoding.UTF8.GetString(buffer)}");
                    //接受的消息再发回去
                    clientSocket.Send(buffer);
                }
            }
            // 接收一个键盘输入的字符,目的是不让命令行自动关闭
            Console.ReadKey();
        }
    }
}


客户端

unity创建个项目

/**
 *Copyright(C) 2019 by #COMPANY#
 *All rights reserved.
 *FileName:     #SCRIPTFULLNAME#
 *Author:       #AUTHOR#
 *Version:      #VERSION#
 *UnityVersion:#UNITYVERSION#
 *Date:         #DATE#
 *Description:   
 *History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Net;
using System.Net.Sockets;
using System.Text;

public class TalkClient : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
        //连接服务器
        socket.Connect("127.0.0.1", 9999);
        //发送数据
        socket.Send(Encoding.UTF8.GetBytes("你好"));

        //接受数据
        var buffer = new byte[1024];
        int length = socket.Receive(buffer);
        print(Encoding.UTF8.GetString(buffer));
    }
}

先运行服务器 再拖动脚本到物体上运行启动客户端

image.png

image.png

然后客户端改个界面


image.png

text差不多大就行

/**
 *Copyright(C) 2019 by #COMPANY#
 *All rights reserved.
 *FileName:     #SCRIPTFULLNAME#
 *Author:       #AUTHOR#
 *Version:      #VERSION#
 *UnityVersion:#UNITYVERSION#
 *Date:         #DATE#
 *Description:   
 *History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Net;
using System.Net.Sockets;
using System.Text;
using UnityEngine.UI;
public class TalkClient : MonoBehaviour
{
    public InputField input;
    public Text text;
    public Button btn;
    byte[] buffer = new byte[1024];
    Socket socket;
    // Start is called before the first frame update
    void Start()
    {
        socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
        //连接服务器
        socket.Connect("127.0.0.1", 9999);
        btn.onClick.AddListener(Send);
    }
    void Send()
    {
        //发送数据
        socket.Send(Encoding.UTF8.GetBytes(input.text));

        //接受数据
        int length = socket.Receive(buffer);
        text.text += Encoding.UTF8.GetString(buffer, 0, length) + "\n";

    }
}
image.png

改为异步服务器

一般项目都是源源不断请求的
所以要开线程异步完成
socket封装的有方便我们写了
先升级服务端
每次Accept 或者Receive 关闭之后都要重新调用

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;


namespace TalkRoomTCP
{
    class Program
    {
        static void Main(string[] args)
        {
            //创建socket using 代替Close 用完不关闭会占用端口
            Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp);

            //绑定IP 端口号
            //IPAddress.Any:相当于"0.0.0.0"的IP地址侦听本地所有网络接口上的客户端活动 有几个侦听几个
            //IPAddress.Broadcast:相当于"255.255.255.255"的IP地址,通常用于Udp的数据包广播。
            //IPAddress.Loopback:相当于"127.0.0.1"的IP地址,用于指代本机。监听"127.0.0.1"时,只能从本机连接到服务端。
            socket.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9999));
            //开启监听 参数是最大接受队列的长度 多于这个就只响应100个 其他拒绝
            socket.Listen(100);

            //开启异步 第二个参数用于传递一些数据
            socket.BeginAccept(AcceptCallBack, socket);
            Console.WriteLine("服务器启动");
            // 接收一个键盘输入的字符,目的是不让命令行自动关闭
            Console.ReadKey();
        }

        private static void AcceptCallBack(IAsyncResult ar)
        {
            var socket = ar.AsyncState as Socket;
            var clientSocket = socket.EndAccept(ar);
            Console.WriteLine($"{clientSocket.RemoteEndPoint}客户端连接");

            //客户端接收消息 如果客户端不发送数据 服务器程序阻塞(挂起)这个位置
            var buffer = new byte[1024];
            clientSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallBack, (clientSocket, buffer));
            int length = clientSocket.Receive(buffer);

            // 递归继续Accept
            socket.BeginAccept(AcceptCallBack, socket);
        }

        private static void ReceiveCallBack(IAsyncResult ar)
        {
            //这种是元组 匿名的结构体
            //这里的buffer数组只在新连接进来的时候,给每个新连接创建了一次,
            //后续与客户端通信的socket会绑定这个buffer数据,
            //通过复用这个buffer可以减少内存的申请和释放,提高性能。
            (var clientSocket, var buffer) = ((Socket, byte[]))ar.AsyncState;
            int length = clientSocket.EndReceive(ar);
            //小于0客户端就关闭了
            if (length>0)
            {
                Console.WriteLine($"接收到客户端的消息:{Encoding.UTF8.GetString(buffer, 0, length)}");
                clientSocket.Send(buffer, length, SocketFlags.None);
                //递归重新开始接收
                clientSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallBack, (clientSocket, buffer));
            }
            else
            {
                Console.WriteLine($"{clientSocket.RemoteEndPoint}断开连接");
                clientSocket.Close();
            }
        }
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353

推荐阅读更多精彩内容