您的位置:首页 > 其它

ProtoBuf 笔记

2011-07-08 18:08 447 查看

编码

Base 128 Varints

uint32中1,10 ,2^32 都使用32位表示,比较浪费。
MSB为0代表一个数字结束,1表示还未结束;这样对于较小的数字比较节省空间,当然大的数字可能要多一个字节。
采用小端表示,以下为300的Base 128 Varints表示的解码过程。
varints 编码:10101100   00000010
去掉最高位:   0101100     0000010
小端->大端:   0000010     0101100
去掉前面的0:            10     0101100  
二进制->10: 300

消息格式

protobuf格式的消息只是K,V对,K为字段的id而不是名字用于节省空间。
到了服务端后通过消息定义文件(如.proto或类定义文件)可以重新从id获得名字。
序列化中,类型信息和字段ID合在了一起 (field_number << 3) | wire_type。wire types 只包含类型的大小信息,不指出具体哪种类型,最多3位。

More Value Types

Signed Integers

protobuf的varints编码策略就是:假定程序使用过程中,较小的数使用较多;于是将小的数编码为更少的位数。
这个策略很直白,是从整体上应用,而不是像哈夫曼编码那样具体分析每次数据中每个字符的频率。
对于有符号整数sint32和sint64,也应用了这个策略,使用了Zigzag编码:假定程序使用过程中,绝对值越小的使用频率越高;于是将绝对值小的数编码为更少的位数。
即:-1编码为1,1编为2,-2编为3,2编为4,-3编为5......。

换句话说,每个值n都按下式编码:(n << 1) ^ (n >> 31)如果是64bit,那么用下面的式子:(n << 1) ^ (n >> 63)实际上个人使用过程中应该是在某个范围内的正数,使用频率比负数要高。但是这里是编码需要一种简单的策略,而不是压缩。

Non-varint Numbers

varint指的是变长的,包括int32,、sint32、int64、sint64。
non-varint就是指采用不变长的方式编码。包括32位的float、fixed32、sfix32以及64位的double、fixed64、sfixed64。其中fixed64,fixed32、sfix32、sfixed64其实和int32,、sint32、int64、sint64表达能力一样,只是采用了平常使用的定长方式编码。

String

wire type 2(length-delimited)意味着后面跟的value是一个用varint编码的length,然后跟着一个length指定长度的bytes。message Test2 {
required string b = 2;
}如果b被set为“testing”, 那么你会得到下面这个序列:12 07 74 65 73 74 69 6e 67标红色的bytes是UTF8编码下的“testing”。
这个stream中的key是0×12 –> id=2, type=2。(id << 3) | wire_type。也就是10 010,10进制为18,16进制为12。

表示长度的varint是7。
随后跟着7个bytes,就是我们的string。

Embedded Messages

下面定义了一个message,里面又包含了一个Test1类型的message:message Test3 {
required Test1 c = 3;
}下面是编码后的版本 1a 03 08 96 01后三个byte正是第一个例子中的结果(08 96 01), 150的varint编码。

而且他们前面的byte是3(也就是length)。
id=3, wiretype = 2。 (id << 3) | wire_type。11  010,16进制为1a。
可以看出embedded message的处理方法和string是完全一样的(wiretype = 2).

Optional And Repeated Elements

如果message中包含repeated类型,应该是类似数组的意思。没有加[packed=true]选项,每个元素都还要加 key,但是不需要排列一起可以和其他字段穿插,这个特点没什么用。
新版本可以加[packed=true]选项,只需要写一次key就行了。但是不能和其他字段穿插。

例如,这样的一个message type:
message Test4 {
repeated int32 d = 4[packed=true];
}假设你创建了一个Test4对象,repeated field d中存入了3,270,86942. 那么,编码后的形式将会是:22 // tag (field number 4, wire type 2)
06 // payload size (6 bytes)
03 // first element (varint 3)
8E 02 // second element (varint 270)
9E A7 05 // third element (varint 86942)只有类型为原始数字类型的repeated field才能被声明为“packed”。

Field Order

在.proto文件中,你可以以任意顺序安排field number,但是,序列化一个message时,它的fields应该按照field number的顺序写入。这样可以让负责parse的code可以使用一些依赖于field number顺序的优化技术。当然,protocol buffer的parser必须能够以任意顺序解析field,因为并不是所有的message都是仅仅经过简单的序列化生成的。


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息