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