protobuf学习

protobuf学习

varints编码

基本思想/基本逻辑

普通的int数据类型,无论其值的大小,所占用的存储空间都是相等的。

varints 编码 使用每个字节的 最高有效位 作为标志位,而剩余的 7位 以二进制补码的 形式 来存储数字值本身, 当最高位有效位 为 1 时,代表其后还跟有字节, 最高有效位为0 时,代表 是 该数字的最后一个字节。

缺点

如果数字是负数, 则采用varints 编码 会恒定占用 10个字节。

zigzag编码

基本思想/基本逻辑

在网络传输和数据存储场景中,需要对数据进行压缩。数据压缩的算法非常多,但大部分的数据压缩算法的原理是通过某种编码方式不存储数据中的0比特位,因此0比特位越多,数据压缩的效果越好。ZigZag编码就是一种增加0比例位的编码方式。

eg: 假设数据类型为byte的负数-11,其二进制在计算机中是用补码表示的,计算过程如下。

正数原码:00001011

反码:11110100

补码(反码加1):11110101

处理过程:

  1. 左移一位:11101010
  2. 符号位放到最后一位:11101011
  3. 除最后一位外全部取反:00010101

编码公式

ZigZag(n) = n>>7 ^ n<<1

protobuf编解码原理

对于int32类型的数据,protobuf 都会转为 uint64 而后使用varints 编码来处理,因此当字段可能为负数时, 我们应使用 sint32 或 sint64,这样protobuf 会按照zigzag编码将数据变化后再采用 varints 编码进行压缩,从而缩短数据的二进制位数。

sint32-> zigzag编码 + varints 编码合起来。

wrie_type 不同值时的二进制结构

  1. 当wire_type 等于0 的时候整个二进制结构为: msb field_number wire_type value

    value 的编码 采用 varints 编码 ,故不需要额外的位来表示 整个value 的长度。 因为 varint的 msb 位 标示下一个字节 是否是 有效的 起到了 指示长度的作用。

  2. 当wire_type 等于 1,5 的时候 二进制结构为:msb field_number wire_type value

    因为 都是取固定的 32位, 或者 64位,因此也不需要额外的位 来表示整个value的长度。

  3. 当 wire_type 等于 2的时候 整个二进制结构为:msb field_number wire_type length value

    因为表示的是可变长度的值,需要有额外的位来指示长度。

field_num 范围与二进制编码

  1. 1到 15,仅使用 1bytes 用一个字节表达 就是

    1 0000 000

    第一位 表示 是否有后续字节, 如果 0 表示 没有,即就一个字节,蓝色部分表示 field-number, 绿色部分则是 wire_type 部分,表示数据类型。

  2. 16 到 2047, 以两个bytes为例:

    1 0000000 0 0000 000

​ 红色部分 依然是 符号位, 每个byte 的第一位都用来表示下 一byte 是否和自己有关, 表示field_num 大小的有 11位 ,能表达的数字最大值就是 2的 11次方 减 1 , 即 2047

Type Meaning Used For
0 VarInt int32, int64, uint32, uint64, sint32, sint64, bool, enum
1 64-bit fixed64, sfixed64, double
2 Length-delimited string, bytes, embedded messages, packed repeated fields
3 Start group groups (deprecated)
4 End group groups (deprecated)
5 32-bit fixed32, sfixed32, float

总结:field_num 就是tag,wrie_type 就是type

posted @ 2021-12-11 17:03  dldream  阅读(80)  评论(0)    收藏  举报