自己实现自定义协议的思考

需求

  • 有三个字段,sender_uid(发送者ID)、content(消息内容)、timestamp(时间戳)
  • 低延迟、高并发、消息可靠、支持多种消息类型
  • 思考一个协议应该完成哪些步骤

思路

一个好的自定义协议设计,需要考虑消息边界、可扩展性、编解码效率和安全性。以下是一个分层的设计思路:

  1. 协议分层结构

    一个完整的网络包结构建议分为两层:包头​ 和 包体。

    • 包头 (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方案为例)

  1. 客户端构建一个 ChatMessage对象,用Protobuf库将其序列化成二进制数据 B_body。
  2. 计算 B_body的长度 len_body。
  3. 按定义填充包头,将 len_body写入"包体长度"字段。
  4. 将包头的二进制数据和 B_body拼接,得到完整的网络包 B_packet。
  5. 通过Socket(可能是基于WebSocket或Raw TCP)发送 B_packet。
  6. 服务端收到数据后:
    • 先读取固定长度的包头(例如14字节)。

    • 从包头中解析出 len_body。

    • 继续从Socket读取 len_body字节,得到完整的包体数据。

    • 根据包头的 Command ID,知道这是一个聊天消息,调用对应的Protobuf解析函数,将包体数据反序列化成 ChatMessage对象。

    • 进行业务逻辑处理(如敏感词过滤、存储、转发给目标玩家)。

相关推荐
Revolution617 小时前
第一次运行 Node.js:终端里的 JavaScript 怎样执行
后端·面试·node.js
进击的程序猿~8 小时前
Go 并发底层原理面试学习指南
开发语言·面试·golang
wdfk_prog9 小时前
嵌入式面试真题学习笔记系列
笔记·学习·面试
用户28735553259212 小时前
OpenResty 中 Lua 脚本实战示例(分场景讲清 Lua 解决了 Nginx 原生做不到的事)
面试
帅次13 小时前
Android 应用高级面试:Window 近1年高频追问 18 题
android·面试·职场和发展
Revolution6113 小时前
Node.js 是什么:前端项目里哪些事情由它完成
前端·面试·node.js
GitLqr1 天前
深入理解 Flutter 架构:从 Widget 到 GPU 像素的全链路解析
flutter·面试·dart
众人皆醒我独醉1 天前
TGI:HuggingFace 的官方推理服务——不止 PagedAttention,更懂模型生态
面试·llm·ai编程
众人皆醒我独醉1 天前
vLLM:PagedAttention 如何让 LLM 推理吞吐提升 24 倍
面试·llm·ai编程
神奇小汤圆1 天前
面试官突然问:“数仓哪一层最适合做RAG?”他一下被问住了…
面试