- 本文来自Google Protocol Buffer Encode说明文档的翻译以及记录原地址为:<a href = "https://developers.google.com/protocol-buffers/docs/encoding#structure">https://developers.google.com/protocol-buffers/docs/encoding#structure</a>
Protocol Buf 关于encode 和 decode的说明文档
如下一个简单的message定义
message Test1 {
required int32 a = 1;
}
在应用中如果将Test1中的a变量赋值为150,那么经过encode之后的字节流为08 96 01,此文档将叙述这些字节所代表的意义。
动态int类型
动态int类型(varints)是一种用一个或者多个字节序列化整数的方法。每一个字节(除了最后一个)都有最高有效位,暗示将会有更多的字节到来。字节的低七位为实际的数值,采用的是小端法表示。
例如对于数字-1仅仅有一个字节,那么不存在最高有效位(0000 0001)
如果是300 那么在encode之后表示为(没有其它信息仅仅是300):
1010 1100 0000 0010
首先移除最高有效位:010 1100 000 0010
由于是小端法表示的需要调整字节顺序:
000 0010 010 1100 = 300
消息结构
protocol buffer 其实是一种序列化的键值对,key是由tag和类型(type)构成的,例如:
required string name = 1;
tag是1,类型(type)是string,而变量名仅仅被用于decode 之后与类型(type)的定义相关联。
当消息被encode的时候,key和value被串行进字节序列中,当被decode时,如果遇到不被识别的key,转换器将会跳过。类型以及对应的值如下表所示:
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 |
在字节流中每一个key都是一个varint值,通过(tag << 3 ) | (type)获得,也就是说,最后三个bit存储类型。
举个例子:key = 08时
0000 1000 分析可以知道,type = 0 即Varint类型变量,同时tag = 1。
那么回头看Test1的例子,由于字节序列为08 96 01,第一个字节08代表key,type = 0(varint) , tag = 1,后两个字节96 01代表value,1001 0110 0000 0001,舍弃最高有效位得到:001 0110 000 0001,由于小端法,需要将字节变换顺序得到:000 0001 001 0110 即是128 + 16 + 4 + 2 = 150
更多值类型
有符号整形
如前一节所述,所有type = 0 时都会被认为是varint类型,然而不同于有符号整形(sint32,sint64,int32,int64)encode负数的时候。encode负数的时候,总是会得到10个字节的varint,出于效率的考虑,会将负数变为非常大的无符号整数,并使用ZigZag编码。
ZigZag编码:对于32位整数编码之后得到的值(n<<1)(n>>31),对于64位(n<<1)(n>>63)
No-varint 数值
No-varint 数值编码采用固定长度,字节序列采用小端法。
Strings
type是2,字节序列除了指定key,还需要保存字符串的长度,如字符串"testing":
encode之后的字节序列为:12 07 74 65 73 74 69 6e 67,第一个字节表示key,tag = 2 , type = 2,07是字符串encode之后的长度。
消息
消息的处理与字符串类似,如下所示
message Test3 {
required Test1 c = 3;
}
同样将Test1中的a赋值150,得到encode之后的字节序列为: 1a 03 08 96 01,可以看到字节序列后三个值对应的是150的key和value,1a代表message 的key(type = 2 ,tag = 3),03表示之后的长度。