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

需求

  • 有三个字段,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对象。

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

相关推荐
Mahir0810 小时前
Spring 循环依赖深度解密:从问题本质到三级缓存源码级解析
java·后端·spring·缓存·面试·循环依赖·三级缓存
绝知此事12 小时前
【算法突围 01】线性结构与哈希表:后端开发的收纳术
java·数据结构·算法·面试·jdk·散列表
kyriewen15 小时前
面试官让我查各部门工资最高的员工,我用AI三秒写出窗口函数,他愣了
后端·mysql·面试
罗超驿16 小时前
18.事务的隔离性和隔离级别:MySQL面试高频考点全解析
数据库·mysql·面试
做人求其滴16 小时前
面试经典 150 题 380 274
c++·算法·面试·职场和发展·力扣
小江的记录本16 小时前
【Java基础】Java 8-21新特性:JDK21 LTS:虚拟线程、模式匹配switch、结构化并发、序列集合(附《思维导图》+《面试高频考点清单》)
java·数据库·python·mysql·spring·面试·maven
ricardo197318 小时前
# Tree Shaking 深度解析:为什么你的代码没被摇掉?
前端·面试
小江的记录本18 小时前
【Java基础】反射与注解:核心原理、自定义注解、注解解析方式(附《思维导图》+《面试高频考点清单》)
java·数据结构·python·mysql·spring·面试·maven
罗超驿18 小时前
19.告别复杂SQL!用MySQL视图把逻辑拆成“变量”式操作
数据库·mysql·面试
jiayong2321 小时前
前端面试题库 - 浏览器与网络篇
前端·网络·面试