Unity【Multiplayer 多人在线】- Socket 通用服务端框架(六)、单点发送和广播数据

举报
CoderZ1010 发表于 2022/09/25 04:48:19 2022/09/25
1.2k+ 0 0
【摘要】 介绍         在阅读了罗培羽著作的Unity3D网络游戏实战一书后,博主综合自己的开发经验与考虑进行部分修改和调整,将通用的客户端网络模块和通用的服务端框架进行提取,形成专栏,介绍Socket网络编程,希望对其他人有所帮助。目录如下: 一、通用服...

介绍

        在阅读了罗培羽著作的Unity3D网络游戏实战一书后,博主综合自己的开发经验与考虑进行部分修改和调整,将通用的客户端网络模块和通用的服务端框架进行提取,形成专栏,介绍Socket网络编程,希望对其他人有所帮助。目录如下:

一、通用服务端框架

        (一)、定义套接字和多路复用​​​​​​

        (二)、客户端信息类和通用缓冲区结构

        (三)、Protobuf 通信协议

        (四)、数据处理和关闭连接

        (五)、Messenger 事件发布、订阅系统

        (六)、单点发送和广播数据

        (七)、时间戳和心跳机制

 二、通用客户端网络模块

        (一)、Connect 连接服务端

        (二)、Receive 接收并处理数据

        (三)、Send 发送数据

        (四)、Close 关闭连接

本篇内容:

单点发送:

定义写入队列:


       //写入队列
       private readonly static Queue<ByteArray> writeQueue = new Queue<ByteArray>();
   
  

发送方法Send接受两个参数:第一个参数为客户端信息对象,代表要将协议发送给哪个客户端;第二个参数proto代表要发送的协议对象。发送之前先进行状态判断,确保客户端连接有效。代码如下:


       /// <summary>
       /// 向客户端发送协议(单点发送)
       /// </summary>
       /// <param name="client">客户端</param>
       /// <param name="proto">协议</param>
       public static void Send(Client client, IExtensible proto)
       {
          //状态判断
          if (client == null || !client.socket.Connected) return;
          //数据编码
          byte[] nameBytes = ProtoUtility.EncodeName(proto);
          byte[] bodyBytes = ProtoUtility.Encode(proto);
          int length = nameBytes.Length + bodyBytes.Length;
          byte[] sendBytes = new byte[2 + length];
          //组装长度
           sendBytes[0] = (byte)(length % 256);
           sendBytes[1] = (byte)(length / 256);
          //组装名字
           Array.Copy(nameBytes, 0, sendBytes, 2, nameBytes.Length);
          //组装消息体
           Array.Copy(bodyBytes, 0, sendBytes, 2 + nameBytes.Length, bodyBytes.Length);
          //写入队列
           ByteArray byteArray = new ByteArray(sendBytes);
          lock (writeQueue)
           {
               writeQueue.Enqueue(byteArray);
           }
          if (writeQueue.Count == 1)
           {
              //发送
               client.socket.BeginSend(sendBytes, 0, sendBytes.Length, 0, SendCallback, client.socket);
           }
       }
   
  

Send回调:


       //发送回调
       private static void SendCallback(IAsyncResult ar)
       {
           Socket socket = ar.AsyncState as Socket;
          //状态判断
          if (socket == null || !socket.Connected) return;
          //结束发送
          int length = socket.EndSend(ar);
           ByteArray? byteArray;
          lock (writeQueue)
           {
               byteArray = writeQueue.First();
           }
          //完整发送
           byteArray.readIdx += length;
          if (byteArray.length == 0)
           {
              lock (writeQueue)
               {
                   writeQueue.Dequeue();
                   byteArray = writeQueue.Count > 0 ? writeQueue.First() : null;
               }
           }
          //继续发送
          if (byteArray != null)
           {
               socket.BeginSend(byteArray.bytes, byteArray.readIdx, byteArray.remain, 0, SendCallback, socket);
           }
       }
   
  

广播数据:

向所有客户端发送数据:


       /// <summary>
       /// 向所有客户端发送协议(广播)
       /// </summary>
       /// <param name="proto">协议</param>
       public static void Send(IExtensible proto)
       {
          foreach (Client client in clients.Values)
           {
               Send(client, proto);
           }
       }
   
  

参考资料:《Unity3D网络游戏实战》(第2版)罗培羽 著

文章来源: coderz.blog.csdn.net,作者:CoderZ1010,版权归原作者所有,如需转载,请联系作者。

原文链接:coderz.blog.csdn.net/article/details/124055482

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

作者其他文章

评论(0

抱歉,系统识别当前为高风险访问,暂不支持该操作

    全部回复

    上滑加载中

    设置昵称

    在此一键设置昵称,即可参与社区互动!

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。