U3DFrameWorkDemo:六、网络

发布时间 2023-05-29 17:29:57作者: 寡人正在Coding

代码参考

代码文件参考下述详解的类图,工程参考第零章工程说明

概述

在多人联机游戏中,大多采用前、后台的架构,前台多表现相关,后台则多交互、资产相关。网络消息的传递其实是由系统内核完成的,大多语言封装了Socket库面向开发者提供网络消息传递的接口,而这里的网络模块是对网络消息传递包含编码、发送、接收、解码、广播等行为的进一步封装,以方便业务上的使用。

关键

  • 前后台约定一种编码、解码的格式(即协议),用于切割解释数据字节流包含的信息。协议应包含(消息名、消息名长度在某些编码中可以省略,例如直接发送json可以固定某个字段为消息名,则只需要消息长度,消息体即可):
    • 整个消息长度:系统内核发送消息不是一个一个发送的,多个消息的数据块可能会粘贴在一起,需要知道消息长度才能把连续的消息分割出来。
    • 消息名:用于响应网络消息的key,例如是登录还是登出等等。
    • 消息名长度:用于分割这条消息消息名和消息体
    • 消息体:消息数据
  • 消息的发送、接收是非阻塞的,否则会阻塞进程造成玩家卡顿(另外一种思路是多线程阻塞处理,可能是要考虑线程切换/阻塞的消耗,至今未见过如此处理)。发送和消息处理使用生产-消费模式,即建立任务,每帧处理一定量的任务尽量避免卡顿。

细节

客户端网络模块

image

  • NetMgr:对Socket库进一步进行了封装,是面对其他开发者处理网络消息的接口。完成消息编码、发送、接收、解码、分发等工作。
  • RWBuffer:维护一个byte数组,用于读写数据
  • MsgBase:消息继承自该类,提供编码解码方法

协议编码

image
使用消息长度+消息名长度+消息名+消息体进行编码,消息长度和消息名长度各占两位占据整体消息的前四位,来确定消息分割。

长度编码

image
采用两位确定长度,使用移位可以提升些许性能。

消息传递

image
其他开发者给勾兑好消息调用发送请求接口,网络模块进行消息编码后推推入发送消息队列。Socket库的发送循环取出配置的数量消息写入系统的发送缓冲区,未来某时内核系统发送字节数据流(此时可能会粘包,即不同个消息可能会一起发送,首末尾的消息可能不完整),数据包经网络路由到达指定IP设备,Socket库响应用户处理网络消息的方法根据协议约定分包拆包推入消息处理队列。主循环取出配置量消息分发并响应。

备注

  • Demo这里注重的它的核心思想自定的协议,大型商业项目协议一般会使用protobuf或者sproto,它们会有(或者自己拓展)相对完整的工具链,在编码方面会更加快速,压缩成更少的数据量,在解包速度和网络流量上更具优势。当然,直接使用json或者其他自定协议格式都是可以实现的,开发者可以权衡利弊。