Protobuf 的序列化和反序列化的细节

假设需要传递一个如下所示的messege

syntax = "proto3";

message MyMessage {
  int32 field1 = 1; // 值为1的int32字段
  string field2 = 2; // 值为"abc"的string字段
}

Protocol Buffers (Protobuf) 序列化和反序列化的细节

Protobuf 是一种高效的二进制序列化格式,它通过紧凑的编码方式来减少数据大小。以下是 Protobuf 序列化和反序列化的详细过程,包括长度压缩的机制。

1. Protobuf 的编码规则

Protobuf 使用一种称为 Varint 的编码方式来压缩整数类型,并根据字段类型选择不同的编码方式。以下是常见字段类型的编码规则:

  • Varint:用于 int32, int64, uint32, uint64, bool 等类型。
  • Length-delimited:用于 string, bytes, repeated 类型。
  • Fixed-length:用于 fixed32, fixed64, float, double 类型。

2. 序列化的过程

序列化是将消息对象转换为紧凑的二进制格式的过程。以下是序列化的详细步骤:

(1) 字段的编码

每个字段在序列化时由以下两部分组成:

  • 字段标识符 (Key):包含字段编号和字段类型。
  • 字段值 (Value):字段的实际数据。
字段标识符 (Key)

字段标识符是一个 Varint,包含以下信息:

  • 字段编号 (Field Number):在 .proto 文件中定义的字段编号。
  • 字段类型 (Wire Type):表示字段值的编码方式。

字段标识符的计算公式:

Key = (Field Number << 3) | Wire Type

0

Varint

1

64-bit 固定长度

2

Length-delimited

5

32-bit 固定长度

示例

假设字段编号为 1,字段类型为 Varint (Wire Type = 0),则:

Key = (1 << 3) | 0 = 8

(2) 字段值的编码

字段值的编码方式取决于字段类型:

  • Varint 编码:整数类型使用 Varint 编码。
  • Length-delimited 编码:字符串和字节数组先编码长度,再编码内容。
  • Fixed-length 编码:浮点数和固定长度整数直接按固定字节数存储。

3. Varint 编码的细节

Varint 是一种变长整数编码方式,用于压缩整数。它的核心思想是:

  • 每个字节的最高位(MSB)表示是否有后续字节。 如果 MSB = 1,表示还有后续字节。如果 MSB = 0,表示这是最后一个字节。
  • 剩余 7 位用于存储实际数据。
示例

整数 300 的二进制表示为 100101100,用 Varint 编码如下:

  1. 将二进制分成 7 位一组,从低位开始:1001011000010110000000010
  2. 对每组添加 MSB: 第一组:00101100 → 10101100(MSB = 1,表示有后续字节)。第二组:00000010 → 00000010(MSB = 0,表示这是最后一个字节)。
  3. 最终编码为:10101100 00000010

4. Length-delimited 编码的细节

Length-delimited 类型(如字符串和字节数组)先编码长度,再编码内容:

  1. 长度:使用 Varint 编码表示内容的字节数。
  2. 内容:直接存储实际数据。
示例

字符串 "abc" 的编码:

  1. 字符串长度为 3,用 Varint 编码为 00000011
  2. 字符串内容为 ASCII 编码:61 62 63
  3. 最终编码为:03 61 62 63

5. 反序列化的过程

反序列化是将二进制数据解析为消息对象的过程。以下是反序列化的详细步骤:

(1) 解析字段标识符

从二进制数据中读取 Varint,解析字段编号和字段类型:

  • 字段编号:Key >> 3
  • 字段类型:Key & 0x07

(2) 解析字段值

根据字段类型解析字段值:

  • Varint:逐字节读取,直到 MSB = 0。
  • Length-delimited:先读取长度(Varint 编码),再读取内容。
  • Fixed-length:直接读取固定字节数。

示例

假设接收到的二进制数据为:08 01 12 03 61 62 63,解析过程如下:

  1. 字段 1: Key = 08 → 字段编号 = 1,字段类型 = 0 (Varint)。值 = 01 → 解码为整数 1。
  2. 字段 2: Key = 12 → 字段编号 = 2,字段类型 = 2 (Length-delimited)。长度 = 03 → 内容长度为 3。内容 = 61 62 63 → 解码为字符串 "abc"。

最终解析结果:

{
  "field1": 1,
  "field2": "abc"
}

6. 长度压缩的优势

  • 小整数压缩:Varint 对小整数非常高效。例如,0127 只需 1 个字节。
  • 跳过未识别字段:Length-delimited 类型的长度信息允许解析器快速跳过未知字段。
  • 紧凑的二进制格式:相比 JSON 或 XML,Protobuf 消除了冗余的标签和空格。

总结

Protobuf 的序列化和反序列化通过 Varint 和 Length-delimited 编码实现了高效的压缩和解析。它的核心特点是:

  1. 使用 Varint 压缩整数,减少存储空间。
  2. 使用字段标识符和类型信息实现灵活的消息解析。
  3. 通过长度信息支持快速跳过未知字段。

这种机制使 Protobuf 成为一种高效、灵活的序列化格式,非常适合网络传输和存储。

全部评论

相关推荐

前面两次都是一面挂,还是我太菜了。。。但每次挂都立马被捞,也是比较难绷这次一个主面试官,一个旁听,还有一个会议室,视频会议里一共四个人。。。但也是全程不开摄像头,说实话碰见这种不开摄像头的面试官真的很无语😓,不过问的问题还算正常。1.自我介绍2.说说项目3.为什么用这些技术栈4.你最熟悉的编程语言是什么 5.说说vue&nbsp;vue2和vue3你觉得有哪些变化6.有了解过Proxy吗&nbsp;为什么用了Proxy做变更7.更新完数据之后直接拿到DOM的话会拿到最新的数据的值吗8.有一些这种列表,列表数据会存到一个数组里,如果我把这个数组里面去push了,添加了一些数据之后,我直接去拿这个列表的DOM的话我拿到的是一个全量的DOM吗9.了解过nextTick()吗10.讲讲事件循环11.nextTick它是属于宏任务还是微任务呢&nbsp;&nbsp;12.promise输出题 13.前端构建工具有了解过一些吗&nbsp;vite&nbsp;webpack&nbsp;14.有了解过他们有什么区别吗&nbsp;比如vite相比webpack有哪些优势15.ESmodule模块化机制你有了解吗16.ESmodule和commonJS有什么区别,有了解过一些吗17.Router两种路由模式是怎么去实现的?18.两种路由模式怎么选择?19.浏览器支持的一些数据存储方式20.LocalStorage可以设置过期时间吗21.支持跨域的数据传输吗22.Cookie23.跨域解决方案24.聊聊性能优化、渲染优化25.怎么实现虚拟滚动的26.手撕&nbsp;图片懒加载反问
查看26道真题和解析
点赞 评论 收藏
分享
05-16 10:17
河南大学 Java
全程50分钟,项目和实习没问,都是八股手撕:接雨水1、hashmap怎么实现的;扩容因子设置过大和过小有什么问题,为什么是0.75;为什么要选红黑树;可以用跳表来替换红黑树吗(这个点答的不是很好)2、concurrent&nbsp;hashmap线程安全原理,1.7和1.8的区别3、synchronized和&nbsp;ReentrantLock的异同点;为什么有了synchronized之后,后面还要有ReentrantLock4、synchronized和&nbsp;ReentrantLock的底层如何实现的5、垃圾回收机制介绍一下;G1还有新生代和老年代的概念吗;G1和CMS比有哪些优势6、浏览器打开一个url涉及的过程,结合计算机网络的角度详细说一说7、HTTP请求头常见的字段有哪些,保持长连接的字段是什么;加了keepAlive连接就不会中断了吗,怎么维护这个连接呢,何时中断(这一点回答的一般)8、HTTP响应码&nbsp;500、501、502……&nbsp;&nbsp;介绍一下,以及收到这些返回码如何排查问题9、HTTPS如何建立连接的,TLS的整个过程&nbsp;;HTTPS为什么要有不同版本的加密算法,这些不同版本的加密算法为了去解决什么问题(这点回答的一般)10、TCP的可靠性保证;拥塞控制详细介绍一下;11、TCP层和应用层用到的数据包是不一样的,可能应用层数据包有的时候比传输层包大,有的时候比更小。粘包和拆包的问题,如何解决12、网络忙时和闲时路由的选择是不一样的,路由选择协议。(说了几个路由选择协议的名字,具体原理有点忘了)
查看13道真题和解析
点赞 评论 收藏
分享
评论
1
7
分享

创作者周榜

更多
牛客网
牛客企业服务