Protocol Buffers 的编码
消息的结构
|
|
一个 Protocol Buffers 的消息,由 3 部分组成 字段编号 field index
、线路类型 wire type
和 有效负载 payload
。这种类型的方案叫做 TLV。上图中的 Value 就是 payload,承载用户的数据。
上图中的 Tag
是由 field index
和 wire
组成的:
field index
:PB message 中定义的 1,2,3 序号。wire
:告诉解析器它之后的 payload 有多大。
wire
有 6 种类型:VARINT
,I64
,LEN
,SGROUP
,EGROUP
,I32
。
ID | Name | Used For |
---|---|---|
0 | VARINT | int32, int64, uint32, uint64, sint32, sint64, bool, enum |
1 | I64 | fixed64, sfixed64, double |
2 | LEN | string, bytes, embedded messages, packed repeated fields |
3 | SGROUP | group start (deprecated) |
4 | EGROUP | group end (deprecated) |
5 | I32 | fixed32, sfixed32, float |
Tag
的计算方式:tag = (field_number << 3) | wire_type
。
编码技术
VARINT3
|
|
正数
This is the most significant bit (MSB) of the byte (sometimes also called the sign bit). The lower 7 bits are a payload。
这是字节的最高有效位 (MSB)(有时也称为符号位)。低 7 位是 payload;如果一个字节的 第 8 位是 0,表示这个字节是整数的最后一个字节。如果 第 8 位是 1,则还有 后续字节。
当 A 是 127 的时候,payload 是 01111111
。
|
|
- Tag(
field number
和wire
):(0000 0001 « 3) | 0000 0000 = 000 1000 = 8。 - payload:
01111111
:为 0 表示最后一个字节。
当 A 是 150 的时候,payload 是 10010110 00000001
。
|
|
- payload
10010110
:为 1 表示后续还有字节。
varint 大于 127 后 payload 计算方式:
|
|
负数
负数的话用到了 ZigZag
编码,将有符号整数转化为无符号整数,便于在编码中进行压缩和传输。
|
|
- Tag:(0000 0001 « 3) | 0000 0000 = 8。
- payload:
11111110 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 00000001
LEN
|
|
LEN
wire 类型,消息是由 Tag + 一个varint指定长度 + payload
组成。
|
|
- Tag: (0000 0010 « 3) | 0000 0010 = 0001 0010 = 18
- 一个表示长度的 varint:6 表示后面字符串的长度。
- payload:“123456” 的
UTF-8
字符编码是49 50 51 52 53 54
。
|
|
- 长度 varint:3。
- payload:“我”的
UTF-8
字符编码E68891
。
Non-varint Numbers
I64 是 8 个字节, I32 是 4 个字节。
|
|
1.5 = 1 + 0.5 = 2^0 + 2^-1 二进制表示 0 01111111 10000000000000000000000
,IEEE 754 1符号位 + 8指数位 + 23位数位
|
|
- Tag:(0000 0001 « 3) | 0000 0101 = 13
- payload:
00000000 00000000 11000000 00111111