protobuf的编码方式

本文介绍protobuf的编码方式。源地址

一个简单的消息

message Test1 {
  required int32 a = 1;
}

我们创建一个Test1消息,给a赋值150,序列化之后存储,我们得到如下的3个byte数据(16进制表示):

08 96 01

非常的简洁,那么这是如何得到的呢?下面我们开始分析

Varints编码

首先介绍Varints编码,它是一种对int型变量的变长编码,使用1个或者多个byte表示一个整数。在这种编码方式下,小的整数需要更少的字节表示。

Varints使用Litte-Endian(小端)字节序(低位在前,高位在后)。下面是Varints的两个基本规则:

  1. (1)每个字节的最高位是标志位,0表示该字节是最后一个字节,1表示该字节后面还有其他字节
  2. (2)每个字节的低7位存储数值的位

举例来说,整数 1 经过编码后是:

0000 0001

只有一个字节,可以看出,Varints编码去除了全0无意义的高位字节。

另一个例子,整数300,编码后的结果:

1010 1100 0000 0010

我们稍微分析一下,首先,每个字节的最高位是标志位,去掉

1010 1100 0000 0010 010 1100  000 0010

Varints使用Litte-Endian字节序,我们要将高位与地位调换

000 0010  010 1100
→  000 0010 ++ 010 1100
→  100101100
→  256 + 32 + 8 + 4 = 300

如此,我们便得到了结果,下面我们分析一下编码的过程是怎样的:

300 = 100101100
从右向左,每7位分为一组,不足7位补零
000 0010,010 1100
使用Litte-Endian字节序
010 1100,000 0010
按照规则(1) 补0或补1
1010 1100,0000,0010

消息结构

protobuf的消息就是一系列的key-value对,key在编码时使用field(就是变量=后面那个数),而不使用变量名。

value的type定义如下:

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’包含了field number和type,格式为:(field_number << 3) | type。也就是说,后三个bit存储的是type。本文开头的例子,存储的第一个字节是08,二进制为

0000 1000

type=000=0,field_number=0000 1=1,符合a的field_number,a是整形,type=1。后面两个字节

96 01 = 1001 0110  0000 0001
       → 000 0001  ++  001 0110 (drop the msb and reverse the groups of 7 bits)
       → 10010110
       → 2 + 4 + 16 + 128 = 150

正是给a赋的值150。到此我们已经理解了本文开头的简单示例。

非整数变量

非整数变量比较简单,double和fixed64的type是1,float和fixed32的type是5,因为长度固定,得知type就知道怎么取value。

对于type=2,value存储的是 长度+value值,举个例子:

message Test2 {
  required string b = 2;
}

给b赋值"testing",编码结果如下:

12 07 74 65 73 74 69 6e 67

红色部分是UTF-8编码的"testing",key=0×12 → field_number = 2, type = 2 ; 0×07是长度,共有7个字节。

protobuf 编码的基础知识大概就是这样,更多的内容可以参考官方文档。学习了这些具体的编码方式,我们才会更深刻的理解,为啥protobuf比 XML 小 3 到 10 倍,快 20 到 100 倍。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值