Unity Socket网络处理

先声明用于网络练接的Socket,以及用于接收网络数据的缓存区

//用于网络连接的Socket
private Socket _socket;
//缓冲区大小
private const int buffSize = 1024*1024;
//用户存放接收到的网络数据
private readonly byte[] packBuffer = new byte[buffSize];

连接方法。
iport 是服务器的ip与端口

	/// <summary>
    /// 连接
    /// </summary>
    public void Connection(IPEndPoint iport)
    {
        _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

        try
        {
            //连接服务器
            _socket.Connect(iport);
            //开始接收数据
            _socket.BeginReceive(packBuffer, 0, buffSize, SocketFlags.None, OnReceived, _socket);
        }
        catch (Exception e)
        {
            Debug.LogError("链接失败!" + e.ToString());
            _socket = null;
        }
        finally
        {
        }
    }

接收网络数据,如果接收到网络数据将会自动调用 OnReceived方法。
OnRecived方法不是主线程执行,而是子线程执行的,所以要注意变量的使用

    /// <summary>
    /// 接收到数据
    /// </summary>
    /// <param name="ia"></param>
    public void OnReceived(IAsyncResult ia)
    {
        //接收到的数据长度
        int len = 0;
        try
        {
            len = _socket.EndReceive(ia);
            if (len <= 0)  //如果接收到的长度小于等于0
            {
                DisConnection(true);  //主动断开连接
                Debug.LogWarning("网络中断!");
                return;
            }

            //packStrBuffer 是接收缓冲区StringBuilder对象。
            //把接收到的数据拷贝到 packStrBuffer 中等待处理
            packStrBuffer.Append(Encoding.UTF8.GetString(packBuffer, 0, len));

            string message = packStrBuffer.ToString();
			//注意一次OnRecived的调用并不意味着接收到一个网络数据包。
			//1.可能是两个网络数据包   粘包现象
			//2.可能是一个完整的包
			//3.可能是一个包的一部分。
			//一般来说会在每个包的前面描述出包的数据大小,用于分割包裹。
			//此处我用换行符来分割每一个包 newline = ' \r\n'; 如果你跟我一样设计的话,那么数据包中不能出现换行符,否则将会导致包解析错误。

            //找到换行符位置
            int pidx = message.IndexOf(newline);

            while (pidx >= 0) //有换行符,表明接收到一个完整的包
            {
            	//对数据进行分割出一个完整的包裹也就是 packMessage;
            	//应把 packMessage 放入队列中留待处理,此处就不作处理了
            	//此处不宜直接把包裹拿来解析,因为此处是子线程,应缓存到队列中,主线程获取后再作处理。
                string packMessage = message.Substring(0, pidx);

                //把数据从缓冲区中移除,方便下次包数据解析
                packStrBuffer.Remove(0, pidx + newline.Length);

                message = packStrBuffer.ToString();

                pidx = message.IndexOf(newline);
            }
           
           //包数据处理完成后,继续去接收数据
            _socket.BeginReceive(packBuffer, 0, buffSize, SocketFlags.None, OnReceived, _socket);
        }
        catch (Exception e)
        {
            Debug.LogError("网络连接中断:" + e.Message);
        }
        finally
        {
        }
    }

主动断开连接

public void DisConnect(){
			  if(_socket == null) return;
				_socket.Disconnect(true);
                _socket.Close();
                _socket = null;
}

发送数据

	///<summary>
    /// 发包
    /// </summary>
    /// <param name="message"></param>
    private void SendPack(string message)
    {
        try
        {
                //此处增加newline 是因为我的设计是以换行符来进行包裹分割
                _socket.Send(Encoding.UTF8.GetBytes(message + newline));
        }
        catch (Exception e)
        {
            Debug.LogError("网络已中断!");
        }
    }

以上是Unity Socket TCP 网络链接的简单实现。
应用在游戏中还需要考虑到
1.自动重连的问题。
2.网络中断检测问题,游戏时候客户端网络中断,服务端是无法知道客户端的断开。所以会加入心跳包的设计,客户端每隔一段时间就向服务器发送一个心跳包,服务器如果有一段时间未接收到客户端发送过来的心跳包,则认为客户端连接中断。关闭与客户端的连接。
3.数据量的问题,此处base64的设计并不好,因为进行base64编码后,数据量会增大,并且多一层转换,效率也有所损耗。在进行收发时,一般需要对发送的数据进行压缩处理,接收到数据包后再进行解压处理,这样可以减少服务器带宽,提升网络传输速率。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值