protubuf的简知

 

1.  Protobuf简介

Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,很适合做数据存储或 RPC 数据交换格式。它可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。目前提供了 C++、Java、Python 三种语言的 API。

优点:

1. Protobuf 有如 XML,不过它更小、更快、也更简单。定义自己的数据结构,然后使用生成的代码来读写这个数据结构。生成一次数据结构,便可以用多种语言进行解析。

2. “向后”兼容性好,不必修改支持就结构的程序,就可以发布新的数据结构。这一点主要与protobuf的编码相关。

3. Protobuf 语义更清晰,无需类似 XML 解析器的东西,直接根据.proto文件生成对应的访问类,对数据序列化及反序列化。

4. 友好,简单易学,使用 Protobuf 无需学习复杂的文档对象模型。

缺点:

1. 生成的二进制文件不具备xml、json的可读、可编辑,没有.proto文件,将无法读取bin文件的内容。

2.Protobuf使用

支持的数据类型如下表:

1.  书写.proto文件

2.  编译.proto文件,生成目标源码。

protoc  -I=$SRC_DIR  --cpp_out=$DST_DIR  $SRC_DIR/addressbook.proto

 

2.1 字段限制

字段限制共有3类:
required:必须赋值的字段
optional:可有可无的字段
repeated:可重复字段(变长字段),类似于数组。

optional int32 old_field = 6 [deprecated=true]; 表明该字段已经被弃用了,在新代码中不建议使用。
由于一些历史原因,repeated字段并没有想象中那么高效,新版本中(2.3.0版本之后)允许使用特殊的选项来获得更高效的编码: repeated int32 samples = 4 [packed=true]。

2.2 Tags

消息中的每一个字段都有一个独一无二的数值类型的Tag.1到15使用一个字节编码,16到2047使用2个字节编码,所以应该将Tags 1到15留给频繁使用的字

2.3可选字段与缺省值

在消息解析时,如果发现消息中没有包含可选字段,此时会将消息解析对象中相对应的字段设置为默认值,可以通过下面的语法为optional字段设置默认值:

optional int32 result_per_page = 3 [default = 10];

如果没有指定默认值,则会使用系统默认值,对于string默认值为空字符串,对于bool默认值为false,对于数值类型默认值为0,对于enum默认值为定义中的第一个元素.

2.4使用其他消息类型

可以使用一个消息的定义作为另一个消息的字段类型.

也可以使用import语法来包含另外一个.proto文件。

import "myproject/other_protos.proto";

2.5嵌套类型

在protocol中可以定义如下的嵌套类型

如果在另外一个消息中需要使用Result定义,则可以通过Parent.Type来使用.

3.  protobuf序列化成二进制流

protocol buffer支持的数据类型在wire_format_lite.h定义。

VARINT类数据表示要用variant编码对所传入的数据做压缩存储。

FIXED32FIXED64类数据不对用户传入的数据做variant压缩存储,存储原始字节。

LENGTH_DELIMITED类数据主要针对string类型、repeated类型和嵌套类型,对这些类型编码时需要存储他们的长度信息。

START_GROUP是一个组(该组可以是嵌套类型,也可以是repeated类型)的开始标志。

END_GROUP是一个组(该组可以是嵌套类型,也可以是repeated类型)的结束标志。

3.1         Protobuf为什么速度快,文件小?

a.  压缩编码

消息经过序列化后会成为一个二进制数据流,在这个二进制流中,逐个字段以定义的顺序相邻。每个字段中由元信息tag和字段的值value组成。在解包的时候,Protocol Buffer 根据 tag 就可以知道相应的 Value 应该对应于消息中的哪一个 field。

其中,tag的编码为:field_number<< 3 | wire_type。 

field_number为定义.proto文件时那些数字1, 2,3,wire_type为字段类型的编号。key的最后3个bits用于存储字段的类型信息,所以protobuf支持的类型不会超过8种。同时Protocol Buffer在一个消息中可以支持的字段数量应为2的29次方减一。

3.2 Protobuf如何做到压缩数据?

1.     variant编码

variant是一种紧凑型数字编码,用一个或多个字节来表示一个数字,值越小的数字使用越少的字节数。这能减少用来表示数字的字节数。Int32最多可以存4byte,很小的数也许1byte就足够,大数则需要 > 4byte,但毕竟大数少。因此能有效减少序列化的文件大小。

比如,131415的variant编码

8bit的最高位为1,表示后面的8bit为有效数据。protobuf字节序列采用的小端,计算时调整下byte顺序。

1)    int32/int64/uint32/uint64类型的编码

  message Test1 {
          required int32 a = 1;
      }

     赋值a = 150,写入bin文件为08 96 01。key的编码为:field_number << 3 | wire_type,因此低三位为数据类型0。将结果右移3位( >> 3),此时得到的结果为1,即字段a在消息Test1中的标签号。

2)    String类型的编码
     string类型值为2,key信息之后是字节数组的长度信息,最后在紧随指定长度的实际数据值信息。如:
      message Test2 {
          required string b = 2;
      }

      现在我们设置b的值为"testing"。其编码后数据如下:
      12 07 74 65 73 74 69 6E 67

     第一个字节0x12表示key,通过解码可以得到字段类型2和字段标号2。第二个字节07表示testing的长度。后面7个字节则表示testing。

    在.proto文件中定义消息的字段标号时,可以是不连续的,但是如果将其定义为连续递增的数值,将获得更好的编码和解码性能。

 2. zigzag编码

可变编码的最高位用于表示下一个字节是否有效,一个负数必然需要5个byte来表示。为此,ProtoBuffer 定义了 sint32 这种类型,采用 zigzag 编码来存储负数。编码会将有符号整型映射为无符号整型,以便绝对值较小的负数仍然可以有较小的varint编码值。

Protocol Buffer位移操作时均采用的算术位移,如-1映射成1。

3解码

XML 需要从文件中读取出字符串,再转换为 XML 文档对象结构模型。之后,再从 XML 文档对象结构模型中读取指定节点的字符串,最后再将这个字符串转换成指定类型的变量。这个过程非常复杂,其中将 XML 文件转换为文档对象结构模型的过程通常需要完成词法文法分析等大量消耗 CPU 的复杂计算。

protobuf解析从文件读入的二进制数据流,并将解析出来的数据赋予 helloworld 类的相应数据成员。 Protobuf 的解码可以通过几个简单的数学运算完成,无需复杂的词法语法分析,因此 ReadTag() 等方法都非常快。

4.  Protobuf的前后兼容

在解时protobuf跳过不识别的字段,这样新老版本消息定义在新老程序之间的兼容性,从而有效的避免了使用消息格式的older程序在解析newer程序发来的newer消息时,一旦遇到未知(新添加的)字段时而引发的解析和对象初始化的错误。 

Protobuf根据序列化的Key的到value,key的获取与字段的tag相关,因此考虑兼容性时需要注意以下:

· 不要改变任何已存在字段的Tag值,可能会导致数值类型不匹配。

·  建议使用optional和repeated字段限制,尽可能的减少required的使用.

·  不需要的字段可以删除,删除字段的Tag不应该在新的消息定义中使用.

·  不需要的字段可以转换为扩展,反之亦然只要类型和数值依然保留

·  int32, uint32, int64,uint64, 和bool是相互兼容的,可以将其中一种类型任意改编为另外一种类型而不会产生任何问题

·  sint32 和 sint64是相互兼容的

·  string 和 bytes是相互兼容的

·  fixed32 兼容 sfixed32, fixed64 兼容 sfixed64.

·  optional 兼容repeated

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值