加入收藏 | 设为首页 | 会员中心 | 我要投稿 应用网_丽江站长网 (http://www.0888zz.com/)- 科技、建站、数据工具、云上网络、机器学习!
当前位置: 首页 > 站长资讯 > 外闻 > 正文

教你从头写游戏服务器框架

发布时间:2019-02-23 14:24:51 所属栏目:外闻 来源:腾讯游戏学院
导读:副标题#e# 1.需求 由于越通用的代码,就是越没用的代码,所以在设计之初,我就认为应该使用分层的模式来构建整个系统。按照游戏服务器的一般需求划分,最基本的可以分为两层: 底层基础功能:包括通信、持久化等非常通用的部分,关注的是性能、易用性、扩展

对于通信“协议”来说,其实包含了许许多多的含义。在众多的需求中,我所定义的这个协议层,只希望完成四个最基本的能力:

  1. 分包:从流式传输层切分出一个个单独的数据单元,或者把多个“碎片”数据拼合成一个完整的数据单元的能力。一般解决这个问题,需要在协议头部添加一个“长度”字段。
  2. 请求响应对应:这对于异步非阻塞的通信模式下,是非常重要的功能。因为可能在一瞬间发出了很多个请求,而回应则会不分先后的到达。协议头部如果有一个不重复的“序列号”字段,就可以对应起哪个回应是属于哪个请求的。
  3. 会话保持:由于游戏的底层网络,可能会使用 UDP 或者 HTTP 这种非长连接的传输方式,所以要在逻辑上保持一个会话,就不能单纯的依靠传输层。加上我们都希望程序有抗网络抖动、断线重连的能力,所以保持会话成为一个常见的需求。我参考在 Web 服务领域的会话功能,设计了一个 Session 功能,在协议中加上 Session ID 这样的数据,就能比较简单的保持会话。
  4. 分发:游戏服务器必定会包含多个不同的业务逻辑,因此需要多种不同数据格式的协议包,为了把对应格式的数据转发。

除了以上三个功能,实际上希望在协议层处理的能力,还有很多,最典型的就是对象序列化的功能,还有压缩、加密功能等等。我之所以没有把对象序列化的能力放在 Protocol 中,原因是对象序列化中的“对象”本身是一个业务逻辑关联性非常强的概念。在 C++ 中,并没有完整的“对象”模型,也缺乏原生的反射支持,所以无法很简单的把代码层次通过“对象”这个抽象概念划分开来。但是我也设计了一个 ObjectProcessor ,把对象序列化的支持,以更上层的形式结合到框架中。这个 Processor 是可以自定义对象序列化的方法,这样开发者就可以自己选择任何“编码、解码”的能力,而不需要依靠底层的支持。

至于压缩和加密这一类功能,确实是可以放在 Protocol 层中实现,甚至可以作为一个抽象层次加入 Protocol ,可能只有一个 Protocol 层不足以支持这么丰富的功能,需要好像 Apache Mina 这样,设计一个“调用链”的模型。但是为了简单起见,我觉得在具体需要用到的地方,再额外添加 Protocol 的实现类就好,比如添加一个“带压缩功能的 TLV Protocol 类型”之类的。

消息本身被抽象成一个叫 Message 的类型,它拥有“服务名字”“会话ID”两个消息头字段,用以完成“分发”和“会话保持”功能。而消息体则被放在一个字节数组中,并记录下字节数组的长度。

  1. enum MessageType { 
  2.     TypeError, ///< 错误的协议 
  3.     TypeRequest, ///< 请求类型,从客户端发往服务器 
  4.     TypeResponse, ///< 响应类型,服务器收到请求后返回 
  5.     TypeNotice  ///< 通知类型,服务器主动通知客户端 
  6. }; 
  7.  
  8. ///@brief 通信消息体的基类 
  9. ///基本上是一个 char[] 缓冲区 
  10. struct Message { 
  11. public: 
  12.     static int MAX_MAESSAGE_LENGTH; 
  13.     static int MAX_HEADER_LENGTH; 
  14.    
  15.     MessageType type;  ///< 此消息体的类型(MessageType)信息 
  16.  
  17.     virtual ~Message();    virtual Message& operator=(const Message& right); 
  18.  
  19.     /** 
  20.      * @brief 把数据拷贝进此包体缓冲区 
  21.      */ 
  22.     void SetData(const char* input_ptr, int input_length); 
  23.  
  24.     ///@brief 获得数据指针 
  25.     inline char* GetData() const{ 
  26.         return data_; 
  27.     } 
  28.  
  29.      ///@brief 获得数据长度 
  30.     inline int GetDataLen() const{ 
  31.         return data_len_; 
  32.     } 
  33.   
  34.     char* GetHeader() const; 
  35.     int GetHeaderLen() const; 
  36.  
  37. protected: 
  38.     Message(); 
  39.     Message(const Message& message); 
  40.   
  41. private: 
  42.     char* data_;                  // 包体内容缓冲区 
  43.     int data_len_;                // 包体长度 
  44.  
  45. }; 

根据之前设计的“请求响应”和“通知”两种通信模式,需要设计出三种消息类型继承于 Message,他们是:Request(请求包)、Response(响应包)、Notice(通知包)。

(编辑:应用网_丽江站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读