ProtoBuf协议入门指南
ProtoBuf协议入门指南
1 简介
服务器与客户端通信,必须有协议,否则双方无法理解对方的码流。在protobuf中,协议是由一系列的消息组成的。因此最重要的就是定义通信时使用到的消息格式。 在制定协议时,不是一气呵成的,是一个完善和优化的过程。首先,需要了解定义的格式与命名的规则,接下来根据自己所做的小模块(如登录模块)所需要的数据进行消息的定义,在程序的完成过程中可能会需要其他通信数据,此时可以添加字段。因此在项目启动的初期不必拘泥于协议的完整,只需大致制定出一个协议,在项目进行的过程中不断完善。
2 协议的定义格式
来看一个简单的例子。定义一个“下注请求”的消息格式,客户端请求有用户ID、下注详情、下注类型,服务端回复有返回码、描述、剩余筹码、一组牌型。可采用如下的方式来定义消息类型的.proto文件了: //注释采用双斜杠
//自定义下注信息
message BetItem
{
optional uint32 lineNumber = 1; // 线条数
optional uint32 lineBet = 2; // 每条线的赌注
}
//客户端发送的请求内容
message BetRoomCmd_C
{
required uint32 uid = 1; // 用户ID
optional BetItem betReq = 2; // 下注详情
optional uint32 betType = 3; // 下注类型
}
//服务器端回复的内容
message BetRoomCmd_S
{
required uint32 resultCode = 1; // 返回码
optional string desc = 2; // 描述
optional uint32 remainderChips = 3; // 剩余筹码
repeated uint32 resultArray = 5; // 一组牌型
}
protobuf消息定义格式:
至少一个字段组合而成,类似于C语言中的结构。
字段格式:限定修饰符① | 数据类型② | 字段名称③ | = | 字段编码值④ | [字段默认值⑤]
required uint32 uid = 1;
限定修饰符 数据类型 字段名称 编码值
2.1 限定修饰符 required \ optional \ repeated
required: 表示是一个必须字段,如上例,下注请求时必须发送用户ID。对于发送方,在发送消息之前必须设置该字段的值,对于接收方,必须能够识别该字段。一个格式良好的消息一定要含有1个这种字段; optional:表示是一个可选字段,对于发送方,在发送消息时,可以有选择性的设置或者不设置该字段的值。对于接收方,如果能够识别可选字段就进行相应的处理,如果无法识别,则忽略该字段; repeated:表示该字段可以包含0~N个元素。其特性和optional一样,但每一次可包含多个值,可看作是在传递一个数组,如上例中获取一组牌型。
2.2 数据类型
| 数据类型 | 描述 |
|---|---|
| bool | 布尔类型 |
| double | 64位浮点数 |
| float | 32为浮点数 |
| int32 | 32位整数 |
| uin32 | 无符号32位整数 |
| int64 | 64位整数 |
| uint64 | 64为无符号整 |
| sint32 | 32位整数,处理负数效率更高 |
| sing64 | 64位整数 处理负数效率更高 |
| fixed32 | 32位无符号整数 |
| fixed64 | 64位无符号整数 |
| sfixed32 | 32位整数、以更高的效率处理负数 |
| sfixed64 | 64为整数 |
| string | 只能处理 ASCII字符 |
| bytes | 用于处理多字节的语言字符、如中文 |
| enum | 可以包含一个用户自定义的枚举类型uint32 |
| message | 可以包含一个用户自定义的消息类型 |
message表示支持嵌套消息,消息可以包含另一个消息作为其字段。如上例:BetRoomCmd_C中optional BetItem betReq = 2;, BetItem为自定义的消息类型。
2.3 字段名称
协议字段命名需要遵循如下规则:
①平台服务器协议中的协议字段名称统一小写;
②游戏业务协议字段名称首单词小写,后续单词首字母大写;
③每个协议字段定义后,需要有精简的注释;
④尽可能让required类协议写在前面,同类描述字段相邻靠拢表示;(同类描述字段表示相同类型的描述字段,如:玩家的昵称、头像为一类;玩家的金币、积分为一类等)
⑤各字段之间,尽可能保证格式整齐。
2.4 字段编码值
有了该值,通信双方才能互相识别对方的字段。当然相同的编码值,其限定修饰符和数据类型必须相同。
2.5 默认值
当在传递数据时,对于required数据类型,如果用户没有设置值,则使用默认值传递到对端。当接受数据是,对于optional字段,如果没有接收到optional字段,则设置为默认值。
3 协议命名规则
3.1 规则
注:以下的规则针对的是本公司。 协议命名需要遵循如下规则: • 每个协议定义前,需要有精简的注释; • 协议命名中,每个单词或缩写单词,首字母需要大写; • 协议命名从左到右为:Proto关键字+业务描述+一级协议业务描述+平台通讯方式+上行/下行协议方式。 举例如下:

①Proto关键字:Proto对应的关键字,message。
②业务描述:业务的具体描述。
③一级协议业务描述:一级协议的业务描述。
④平台通讯方式类型:
- 平台服务器与客户端之间通讯,对应值为"Pmd";
- 区服务器服与平台服务器之间通讯,对应值为"Smd";
- 客户端与服务器之间通讯,对应值为"Cmd";
⑤上行/下行协议方式:协议分为上行协议与下行协议。
- 上行协议即请求协议,对应值为"_C"。
- 下行协议即回复协议,对应值为"_S"。
- 上行协议与下行协议,对应值为"_CS"。
3.2 实例
// 请求注册帐号
message RequestAccountRegisterLoginUserCmd_C
{
required string account = 1; // 账号
required string password = 2; // 账号ID
optional string code = 3; // 验证码
}

// 返回注册帐号
message ReturnAccountRegisterLoginUserCmd_S
{
required string account = 1; // 账号
r equired uint64 accountid = 2; // 账号ID
}
