Unity【Multiplayer 多人在线】- Socket 通用服务端框架(二)、客户端信息类和通用缓冲区结构

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

介绍

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

    一、通用服务端框架

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

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

        (三)、Protobuf 通信协议

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

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

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

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

 二、通用客户端网络模块

        (一)、Connect 连接服务端

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

        (三)、Send 发送数据

        (四)、Close 关闭连接

本篇内容:

客户端信息类Client:

每一个客户端都会包含一个与服务器连接的Socket套接字和字节数据读写缓冲区,定义相关内容如下:


      using System.Net.Sockets;
      namespace SK.Framework.Sockets
      {
         /// <summary>
         /// 客户端信息类
         /// </summary>
         public class Client
          {
             /// <summary>
             /// 套接字
             /// </summary>
             public Socket socket;
             /// <summary>
             /// 缓冲区
             /// </summary>
             public ByteArray readBuff;
             /// <summary>
             /// 构造函数
             /// </summary>
             /// <param name="socket">套接字</param>
             public Client(Socket socket)
              {
                 this.socket = socket;
                  readBuff = new ByteArray();
              }
          }
      }
  
 

通用缓冲区结构ByteArray:

作为通用的缓冲区结构,ByteArray支持自动拓展,例如写入的数据长度大于缓冲区剩余长度时,缓冲区的容量会自动扩充。核心变量:readIdx读取位置、writeIdx写入位置、length缓冲区中数据长度、remain缓冲区中剩余空间。代码如下:


      namespace SK.Framework.Sockets
      {
         public class ByteArray
          {
             //默认大小
             private const int DEFAULT_SIZE = 1024;
             //初始大小
             private readonly int initSize = 0;
             //缓冲区
             public byte[] bytes;
             //读取位置
             public int readIdx = 0;
             //写入位置
             public int writeIdx = 0;
             //容量
             private int capacity = 0;
             //剩余空间
             public int remain { get { return capacity - writeIdx; } }
             //数据长度
             public int length { get { return writeIdx - readIdx; } }
             //构造函数
             public ByteArray(int size = DEFAULT_SIZE)
              {
                  bytes = new byte[size];
                  capacity = size;
                  initSize = size;
                  writeIdx = 0;
                  readIdx = 0;
              }
             //构造函数
             public ByteArray(byte[] defaultBytes)
              {
                  bytes = defaultBytes;
                  capacity = defaultBytes.Length;
                  initSize = defaultBytes.Length;
                  readIdx = 0;
                  writeIdx = defaultBytes.Length;
              }
             //重设尺寸
             public void ReSize(int size)
              {
                 if (size < length) return;
                 if (size < initSize) return;
                 int n = 1;
                 while (n < size)
                  {
                      n *= 2;
                  }
                  capacity = n;
                 byte[] newBytes = new byte[capacity];
                  Array.Copy(bytes, readIdx, newBytes, 0, writeIdx - readIdx);
                  bytes = newBytes;
                  writeIdx = length;
                  readIdx = 0;
              }
             //检查并移动数据
             public void CheckAndMoveBytes()
              {
                 if (length < 8)
                  {
                      MoveBytes();
                  }
              }
             //移动数据
             public void MoveBytes()
              {
                 if (length > 0)
                  {
                      Array.Copy(bytes, readIdx, bytes, 0, length);
                  }
                  writeIdx = length;
                  readIdx = 0;
              }
             //写入数据
             public int Write(byte[] bs, int offset, int count)
              {
                 if (remain < count)
                  {
                      ReSize(length + count);
                  }
                  Array.Copy(bs, offset, bytes, writeIdx, count);
                  writeIdx += count;
                 return count;
              }
             //读取数据
             public int Read(byte[] bs, int offset, int count)
              {
                  count = Math.Min(count, length);
                  Array.Copy(bytes, readIdx, bs, offset, count);
                  readIdx += count;
                  CheckAndMoveBytes();
                 return count;
              }
             //读取Int16
             public Int16 ReadInt16()
              {
                 if (length < 2) return 0;
                  Int16 ret = (Int16)((bytes[readIdx + 1]) << 8 | bytes[readIdx]);
                  readIdx += 2;
                  CheckAndMoveBytes();
                 return ret;
              }
             //读取Int32
             public Int32 ReadInt32()
              {
                 if (length < 4) return 0;
                  Int32 ret = (Int32)((bytes[readIdx + 3] << 24) |
                                      (bytes[readIdx + 2] << 16) |
                                      (bytes[readIdx + 1] << 8) |
                                      bytes[readIdx + 0]);
                  readIdx += 4;
                  CheckAndMoveBytes();
                 return ret;
              }
          }
      }
  
 

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

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

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

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

作者其他文章

评论(0

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

    全部回复

    上滑加载中

    设置昵称

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

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

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