博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
protobuf编码
阅读量:6940 次
发布时间:2019-06-27

本文共 2635 字,大约阅读时间需要 8 分钟。

protobuf能够跨平台提供轻量的序列化和反序列化,得益于其平台无关的编码格式,本文就介绍下其中的编码格式。

Varints

在protobuf中大量使用到了Varints的编码格式,这是一个可变长度的编码格式用于编码整形数字。

Varint的最小单位是byte,即8位,每byte第一位(msb)是标志位用于标记是否还有后续byte。

===1===0000 0001===300===1010 1100  0000 0010

上面300的例子首先读入第一个字节发现第一位为1,表示还有后续byte,然后读取后一个byte,第一位为0就判断已经读完,然后组装数值将其余位数取出0101100 0000010,然后反转并拼接成为000 0010-010 1100,这样就组成了300。

433963-20170325180421799-354709776.png

其他类型

负数,sint与int

在protobuf的定义中sint和int似乎看上去是重复的,但其实这两种类型的底层编码式不同的。这里以-3为例:

-3使用int编码会变成FD FF FF FF FF FF FF FF FF 01,首先这也是varint编码去掉每个byte的首位标志位然后反转顺序就成了FF FF FF FF FF FF FF FD是-3的补码。
而使用sint编码会变成05,貌似和-3没有关系,其实它是-3经过一个zigzag转换而得来的。

Signed Original Encoded As
0 0
-1 1
1 2
-2 3
2147483647 4294967294
-2147483648 4294967295

这样转换可以大大减少负数的表示长度,所以建议在经常出现负数的地方使用sint而不是int可以缩短编码的大小。

非varient数值

对于double/fixed64,float/fixed32会分别使用固定的64位或32位进行表示。

不定长数据类型

对于string,byte等类型,就使用这种类型,首先使用一个varint表示长度,之后是数据的内容,列入字符串aaa就是03 61 61 61 其中03表示长度为3,61是a的utf8编码。值得注意的是,嵌套的message类型、repeat字段也都是使用这种形式进行编码到对象中的。

message编码

有了上面这些在准备,我们可以进入真正的消息的编码了。protobuf中每个字段都是根据定义的tag来进行定位的,在序列化的数据中,每个字段首先是一个Varint用于标记tag,其中最后三位使用来标志该字段的数据类型。

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

前面的位数用于标志tag,例如0000 1000,去掉第一个标志位后三个类型位,就表示tag为1的字段。

对于repeat类型由于历史原因,proto2中默认是将数组元素并排排列在内的例如[1,2,3]会保存成[08 01 08 02 08 03]。后来对repeat类型进行了改进引入packed在定义的后面加上packed:

repeated int32 int = 1 [packed=true];

这样序列化的数据就成了0A 03 01 02 03,其中0A表示使用不定长编码,之后03表示长度,接下来是数据,就这个例子就能节约1byte。packed只适用于varint或固定长度数值表示的字段,对于string或者嵌套类型不适用,在proto3中支持的类型默认会使用packed。

实例

syntax = "proto2";message Person {    required string name=1;    required int32 age=2;    repeated Address add=3; }message Address{    required string add=1;}---实例---name: "MyName"age: 18add {  add: "MyAdd1"}add {  add: "MyAdd2"}---Hex---0A 06 4D 79 4E 61 6D 65 10 12 1A 08 0A 06 4D 79 41 64 64 31 1A 08 0A 06 4D 79 41 64 64 32---解释---0A                      //变长类型tag为1的字符串06                      //name字段6 byte长度4D 79 4E 61 6D 65       //MyName10                      //varint编码tag为212                      //181A                      //变长类型tag为308                      //Adress 8 byte长度0A                      //变长类型tag为106                      //add字段6 byte长度4D 79 41 64 64 31       //MyAdd11A                      //变长类型tag为308                      //Adress 8 byte长度0A                      //变长类型tag为106                      //add字段6 byte长度4D 79 41 64 64 32       //MyAdd2

转载于:https://www.cnblogs.com/resentment/p/6617787.html

你可能感兴趣的文章
display:inline-block
查看>>
2018 MUltiU 9 dp / 8 upper_bound ; 构造?/
查看>>
[LUOGU] P2704 炮兵阵地
查看>>
mysql 5.7 详细图文安装教程
查看>>
idea出现插件突然失灵解决方案
查看>>
初识Redis(一)
查看>>
20131105
查看>>
数据结构与算法面试题80道(19)
查看>>
html5菜单折纸效果
查看>>
收藏一下,虽然很多东西还没接触到
查看>>
[转]熵(Entropy),交叉熵(Cross-Entropy),KL-松散度(KL Divergence)
查看>>
VS基本教程
查看>>
Jmeter也能IP欺骗!
查看>>
iOS开发的Sketch之旅
查看>>
Python之tkinter中的askyescancel窗口返回值
查看>>
asp.net core系列 55 IS4使用Identity密码保护API
查看>>
VS2008中生成DLL项目
查看>>
1.4(Spring MVC学习笔记)JSON数据交互与RESTful支持
查看>>
[系统]安装fedora 19
查看>>
ajax发送请求(关于搜索引擎)
查看>>