一、简介
protocol buffers是google推出的一种数据序列化格式,简称protobuf。
具有以下优点
- 支持多种编程语言
- 序列化数据体积小
- 反序列化速度快
- 序列化和反序列化代码自动生成
同时,也有以下缺点:
- 可读性差,缺乏自描述性
在项目 thrift-protobuf-compare中,对各种序列化方式做了全方位的对比,对比结果中,protobuf各项都处于第5左右(共21个),综合性能较好。
下图(左JSON,右Protobuf)是同样的一段数据,用json和protobuf分别描述(仅表示描述方式,并不是最终生成的序列化数据)。可以看出,protobuf是把json中的key去掉了,用数字代替key,从而实现了减小了序列化后的数据大小。而protobuf反序列化过程中,无需做字符串解析,所以速度也很快,综合性能优于json很多。
二、使用步骤
protobuf使用,主要分为以下步骤:
1. 定义消息格式,编写.proto文件
2. 选择合适的protobuf实现框架,对.proto文件进行编译,生成对应的源代码文件
3. 在代码中调用生成的源代码文件,完成序列化和反序列化功能
三、在Android中使用
目前在Android种有两种实现框架,google-protobuf和square-wire。
1. 使用google-protobuf框架
以后补充
2. 使用square-wire框架
以后补充
四、原理
1. 消息格式
如下图所示,protobuf数据是连续的key-value组成,每个key-value对表示一个字段,value可以是基础类型,也可以是一个子消息。
其中,key表示了该字段数据类型,字段id信息,而value则是该字段的原始数据。若字段类型是string/bytes/子message(长度不固定),则在key和value之间还有一个值表示该字段的数据长度,如下图所示:
key值的计算方式为:key=(id<<3)|type,其中id是在消息定义时的字段id,而type表示数据类型,取值范围0-5,如下表所示:
例:假如proto文件定义如下,其中消息取值为code=10,msg=”abc”,尝试计算序列化后的消息数据。
message Response {
required int32 code = 1;
required string msg = 2;
}
答:
a. 消息的最终结构为key1-value1-key2-length2-value2;
b. 其中,key1=(id<<3)|type = (1<<3)|0=0x08,value1=0x0a,key2=(id<<3)|type=(2<<3)|2=0x12,length2=0x03,value2=0x616263;
c. 因此,最终的消息数据为:0x080a1203616263.
2. varint编码
在java中,int用4字节表示,long用8字节表示,而在实际场景中,一般我们不会使用到很大的数,因此使用4/8字节表示数值会有冗余。为了进一步减小序列化后的数据大小,protobuf引入了varint编码,解决数值表示过程中的冗余问题。
在protobuf中,key值/length/int32/int64/uint32/uint64使用了varint编码表示。
varint编码原理如下图所示,每个字节首位表示后面是否还有字节,而后7位表示数据。图中所示的数据,用二进制表示实际上是00101000100111(protobuf采用小端模式),即2599。
3. zigzag编码
由于负数在计算机中用补码表示,首位永远是1,无法使用varint编码进行压缩。为了解决此问题,protobuf引入了zigzag编码,目前,sint32和sint64类型的数据使用zigzag编码。
zigzag编码原理是,首先按照下表中的规律,将数据全部转化成正数,然后再用varint进行编码。
例:-3(int类型)用zigzag编码处理后,结果为0x05,仅需1个字节;而若不用zigzag,在内存中表示为0xFFFFFFFD,需要4个字节;若直接使用varint编码,则是0xFEFFFFFF0F,需要5个字节。
今天的文章protocol buffers原理与使用分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/24580.html