`

(转)为什么Protobuf 的默认序列化格式没有包含消息的长度与类型

阅读更多

Protobuf 是经过深思熟虑的消息打包方案,它的默认序列化格式没有包含消息的长度与类型,自然有其道理。哪些情况下不需要在 protobuf 序列化得到的字节流中包含消息的长度和(或)类型?我能想到的答案有:

  • 如果把消息写入文件,一个文件存一个消息,那么序列化结果中不需要包含长度和类型,因为从文件名和文件长度中可以得知消息的类型与长度。
  • 如果把消息写入文件,一个文件存多个消息,那么序列化结果中不需要包含类型,因为文件名就代表了消息的类型。
  • 如果把消息存入数据库(或者 NoSQL),以 VARBINARY 字段保存,那么序列化结果中不需要包含长度和类型,因为从字段名和字段长度中可以得知消息的类型与长度。
  • 如果把消息以 UDP 方式发生给对方,而且对方一个 UDP port 只接收一种消息类型,那么序列化结果中不需要包含长度和类型,因为从 port 和 UDP packet 长度中可以得知消息的类型与长度。
  • 如果把消息以 TCP 短连接方式发给对方,而且对方一个 TCP port 只接收一种消息类型,那么序列化结果中不需要包含长度和类型,因为从 port 和 TCP 字节流长度中可以得知消息的类型与长度。
  • 如果把消息以 TCP 长连接方式发给对方,但是对方一个 TCP port 只接收一种消息类型,那么序列化结果中不需要包含类型,因为 port 代表了消息的类型。
  • 如果采用 RPC 方式通信,那么只需要告诉对方 method name,对方自然能推断出 Request 和 Response 的消息类型,这些可以由 protoc 生成的 RPC stubs 自动搞定。

对于最后一点,比方说 sudoku.proto 定义为:

service SudokuService {
  rpc Solve (SudokuRequest) returns (SudokuResponse);
}

那么 RPC method Sudoku.Solve 对应的请求和响应分别是 SudokuRequest 和 SudokuResponse。在发送 RPC 请求的时候,不需要包含 SudokuRequest 的类型,只需要发送 method name Sudoku.Solve,对方自知道应该按照 SudokuRequest 来解析(parse)请求。这个例子来自我的半成品项目 evproto,见 http://blog.csdn.net/Solstice/archive/2010/04/17/5497699.aspx 

对于上述这些情况,如果 protobuf 无条件地把长度和类型放到序列化的字节串中,只会浪费网络带宽和存储。可见 protobuf 默认不发送长度和类型是正确的决定。Protobuf 为消息格式的设计树立了典范,哪些该自己搞定,哪些留给外部系统去解决,这些都考虑得很清楚。

只有在使用 TCP 长连接,且在一个连接上传递不止一种消息的情况下(比方同时发 Heartbeat 和 Request/Response),才需要我前文提到的那种打包方案。(为什么要在一个连接上同时发 Heartbeat 和业务消息?请见陈硕《分布式系统的工程化开发方法》 p.51 心跳协议的设计。)这时候我们需要一个分发器 dispatcher,把不同类型的消息分给各个消息处理函数,这正是本文的主题之一。

分享到:
评论

相关推荐

    5.自动识别Protocolbuf消息类型1

    描述中提到的问题在于,protobuf序列化的数据不包含长度信息和类型标识,需要在应用层额外处理。 在网络编程中,Protobuf提供了高效的数据序列化和反序列化机制,但有两个主要问题需要解决: 1. **长度问题**:...

    PHP常见的序列化与反序列化操作实例分析

    上述代码将之前序列化的字符串`$info`还原为原始的数组结构,`$zhangsan`现在包含了与`$arr`相同的数据。 **3. 优缺点** - **优点**:序列化允许将复杂的数据结构保存到数据库、文件系统或通过网络传递,而无需...

    protocol-buffers-encodings-源码.rar

    Protocol Buffers(简称protobuf)是由Google开发的一种数据序列化协议,它允许开发者定义数据结构,并将这些数据结构高效地编码和解码为二进制格式,便于在网络间传输或者存储。protobuf的核心优势在于其小巧、高效...

    Netty面试题(2022最新版)

    - **原因**:TCP是流式传输,没有消息长度的概念。 - **解决方法**: - 使用固定长度的消息格式; - 在消息之间添加分隔符; - 使用自定义协议,包含消息长度等元信息; - 利用Netty提供的长度字段编码解码器...

    第三届卫生健康行业网络安全技能大赛 复盘培训

    在ProtoBuf协议栈逆向中,我们可以发现ProtoBuf协议通信序列化构造的特征。通过分析main函数,我们可以找到输入经过命令处理器处理后转换为对应结构分别对应了堆块常规的:add / edit / show / delete 功能。 _数组...

Global site tag (gtag.js) - Google Analytics