需求
- 有三个字段,sender_uid(发送者ID)、content(消息内容)、timestamp(时间戳)
- 低延迟、高并发、消息可靠、支持多种消息类型
- 思考一个协议应该完成哪些步骤
思路
一个好的自定义协议设计,需要考虑消息边界、可扩展性、编解码效率和安全性。以下是一个分层的设计思路:
-
协议分层结构
一个完整的网络包结构建议分为两层:包头 和 包体。
-
包头 (Header):用于描述包本身,与具体业务(聊天)无关。是固定长度的二进制数据,便于快速解析。
-
包体 (Body):承载具体的业务数据(如聊天消息)。其内容由包头中的"消息类型"决定。
-

B. 包体 (Packet Body)
包体是变长的,其格式由Command ID决定。对于聊天消息(假设Command ID=0x0001,私聊),其结构就是我们需要设计的"聊天消息体"。
聊天消息体设计(序列化方案对比)
您需要将{sender_uid, content, timestamp}这三个字段(以及可能的其他字段,如target_uid)序列化成二进制。
使用高效序列化库
使用Protobuf、MessagePack (MsgPack) 或 FlatBuffers 来定义消息体。
例如,用Protobuf定义 .proto文件:
protobuf
message ChatMessage {
uint64 sender_uid = 1;
string content = 2;
int64 timestamp = 3;
}
-
优点:在性能、体积和开发效率上取得最佳平衡。自动生成编解码代码,支持向后/向前兼容(通过字段编号),是工业级标准。
-
缺点:需要引入第三方库。
完整数据流示例(以Protobuf方案为例)
- 客户端构建一个 ChatMessage对象,用Protobuf库将其序列化成二进制数据 B_body。
- 计算 B_body的长度 len_body。
- 按定义填充包头,将 len_body写入"包体长度"字段。
- 将包头的二进制数据和 B_body拼接,得到完整的网络包 B_packet。
- 通过Socket(可能是基于WebSocket或Raw TCP)发送 B_packet。
- 服务端收到数据后:
-
先读取固定长度的包头(例如14字节)。
-
从包头中解析出 len_body。
-
继续从Socket读取 len_body字节,得到完整的包体数据。
-
根据包头的 Command ID,知道这是一个聊天消息,调用对应的Protobuf解析函数,将包体数据反序列化成 ChatMessage对象。
-
进行业务逻辑处理(如敏感词过滤、存储、转发给目标玩家)。
-