前言
协议的选型上不多说,用Protobuf,关于如何选型,可以参考下面这个系列文章:
本文探讨的是基于Protobuf上如何做协议事件分发路由设计,预备知识可以参考:
版本选择建议选择: Protobuf3
思路设计
因此通常定义协议为:
| 两个字节 | 两个字节 | 不定长度 |
|---|---|---|
| 消息长度 | 协议号 | 消息 |
游戏中的路由主要作用为: 根据路由序号去解码协议消息, 并且分发到响应方法内处理.
协议号设计
协议号(cmd16), 占用16个bit, 分为两段:
- 模块协议号, 占用
7个bit:cmd - 子模块消息协议号, 占用
9个bit:c_cmd
两段协议号通过下面的规则组合成协议号(cmd16):
Cmd16 = Cmd bsl 9 + CCmd
注意: 协议号(cmd16), 总共占用16个bit, 范围在: 0 - 65535, 因此最大协议数量为: 65536个
模块协议号
占用7个bit: cmd
模块协议号(cmd)定义在msg.proto文件内:
1 | enum cmd { |
以枚举(enum)方式定义, 枚举名固定为cmd,枚举的Key(msg_base)必须与[文件名(msg_base.proto)]一致,枚举的Value(0)表示: 模块协议号(cmd).
注意: 模块协议号(cmd), 占用7个bit, 范围在: 0 - 127, 因此最大模块数量为: 128个
子模块消息协议号
占用9个bit: c_cmd
子模块消息协议号(c_cmd)定义在具体的协议(msg_base.proto)文件内:
1 | enum c_cmd{ |
同样以枚举(enum)方式定义, 枚举名固定为c_cmd,枚举的Key(HeartbeatReq)必须与对应的[协议名(HeartbeatReq)]一致,枚举的Value(0)表示: 子模块消息协议号(c_cmd).
注意: 子模块消息协议号(c_cmd), 占用9个bit, 范围在: 0 - 511, 因此最大协议数量为: 512个
协议消息设计
协议消息分类:
- 上行数据: 请求
- 下行数据: 响应/推送
一般游戏中只存在三种关系:
- 客户端同步请求返回
- 客户端异步请求
- 服务器主推消息
最好是希望这些关系能在协议文件内直观的表示,因此借用了pb的rpc来表示:
- 客户端同步请求返回:
rpc heartbeat(HeartbeatReq) returns (HeartbeatResp); - 客户端异步请求:
rpc just_req(JustReq) returns (Empty); - 服务器主推消息:
rpc heartbeat_push(Empty) returns (HeartbeatResp);
这些rpc都定义在service内,service名的定义必须以当前文件名为前缀, 以_service为后缀命名.
请参照 msg_base.proto:
1 | syntax = "proto3"; |
协议消息命名规范
协议名建议都以[驼峰命名法]命名
协议消息分类根据不同的命名后缀来区分:
- 请求:
Req, 例如:HeartbeatReq - 响应:
Resp, 例如:HeartbeatResp - 推送:
Push, 例如:TimePush
- 请求:
rpc名因为是请以[下划线命名法]命名, 例如:rpc just_req
rpc名的作用
上面定义的三种关系中, 每个关系都有一个名字,在服务端这一方, 除主推的消息的名字无用外,另外两种关系都是作为路由协议回调函数名来使用,这样也跟代码里面的关系对应上了.
使用
通过以上规则,我们只需要将这些规则加以使用,编写一个插件,去生成路由层的代码即可.
今天先说到这里,下次在开文章讲解插件的使用.