ProtoBuf 介绍,2.0 & 3.0对比
介绍
Protobuf即Protocol Buffers,是Google公司开发的一种跨语言和平台的序列化数据结构的方式,是一个灵活的、高效的用于序列化数据的协议。与XML和JSON格式相比,Protobuf更小、更快、更便捷。
Protobuf支持生成代码的语言包括Java、Python、C++、Go、JavaNano、Ruby、C#,官网地址是https://developers.google.com/protocol-buffers/。
Portobuf的序列化的结果体积要比XML、JSON小很多,XML和JSON的描述信息太多了,导致消息要大;此外Portobuf还使用了Varint 编码,减少数据对空间的占用。
Portobuf序列化和反序列化速度比XML、JSON快很多,是直接把对象和字节数组做转换,而XML和JSON还需要构建成XML或者JSON对象结构。
数据内容-ProtoBuf 2.0
一个.proto 文件,主要的数据内容如下例子:
message SearchRequest {
required string query = 1;
optional int32 page_number = 2;
optional int32 result_per_page = 3;
repeated int32 samples = 4 [packed=true];
optional double profit_rate = 5 [default=-1.0]
}
从.proto文件生成了什么?
当用protocolbuffer编译器来运行.proto文件时,编译器将生成所选择语言的代码,这些代码可以操作在.proto文件中定义的消息类型,包括获取、设置字段值,将消息序列化到一个输出流中,以及从一个输入流中解析消息。
对C++来说,编译器会为每个.proto文件生成一个.h文件和一个.cc文件,.proto文件中的每一个消息有一个对应的类。
对Java来说,编译器为每一个消息类型生成了一个.java文件,以及一个特殊的Builder类(该类是用来创建消息类接口的)。
ProtoBuf 3.0
-
在第一行非空白非注释行,必须写:
syntax = "proto3";
-
字段规则移除了 “required”,并把 “optional” 改名为 “singular”;
在 proto2 中 required 也是不推荐使用的。因为 required是永久性的:在将一个字段标识为required的时候,应该特别小心。如果在某些情况下不想写入或者发送一个required的字段,将原始该字段修饰符更改为optional可能会遇到问题——旧版本的使用者会认为不含该字段的消息是不完整的,从而可能会无目的的拒绝解析。
proto3 直接从语法层面上移除了 required 规则 -
“repeated”字段默认采用
packed
编码;在 proto2 中,需要明确使用
[packed=true]
来为字段指定比较紧凑的packed
编码方式。 -
语言增加 Go、Ruby、JavaNano 支持;
-
移除了 default 选项;
在 proto2 中,可以使用 default 选项为某一字段指定默认值。在 proto3 中,字段的默认值只能根据字段类型由系统决定。也就是说,默认值全部是约定好的,而不再提供指定默认值的语法。
Proto 一些规则
-
请勿更改任何现有字段的字段编号。
-
添加的任何新字段都应该是 optional 或 repeated。这意味着基于“旧的”消息格式的代码而序列化的任何消息仍可以由被新生成的代码解析,因为这些消息不会缺少任何 required 元素。你应该为这些元素设置合理的默认值,以便新代码可以正确地与旧代码生成的 message 进行交互。同样,你的新代码创建的 message 可以由旧代码解析:旧的二进制文件在解析时只是忽略新字段。但是未丢弃这个新字段,如果稍后序列化消息,则将新字段与其一起序列化。因此,如果将消息传递给新代码,则新字段仍然可用。(兼容性强)
- 可以删除非required字段,只要在新的 message 类型中不再使用该字段的编号。也许你希望的是重命名该字段,那么可以添加前缀 “OBSOLETE_”,或者将字段编号保留(reserved),以便将来你的 .proto文件 的用户不会不小心重用这个编号。
只要类型和编号保持不变,非required字段就可以转换为扩展 extensions,反之亦然。
Oneof
如果你的 message 包含许多可选字段,并且最多只能同时设置其中一个字段,则可以使用 oneof 功能强制执行此行为并节省内存。
Oneof 字段类似于可选字段,除了 oneof 共享内存中的所有字段,并且最多只能同时设置一个字段。设置 oneof 的任何成员会自动清除所有其他成员。你可以使用特殊的 case() 或 WhichOneof() 方法检查 oneof 字段中当前是哪个值(如果有)被设置,具体方法取决于你选择的语言。
要在 .proto 中定义 oneof,请使用 oneof 关键字,后跟你的 oneof 名称,在本例中为 test_oneof:
message SampleMessage { oneof test_oneof { string name = 4; SubMessage sub_message = 9; } }
然后,将 oneof 字段添加到 oneof 定义中。你可以添加任何类型的字段,但不能使用 required,optional 或 repeated 关键字。如果需要向 oneof 添加重复字段,可以使用包含重复字段的 message。
ProtoBuf 在RPC 中的使用
https://www.eet-china.com/mp/a63366.html