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

  1. 在第一行非空白非注释行,必须写:

    syntax = "proto3";

  2. 字段规则移除了 “required”,并把 “optional” 改名为 “singular”

    在 proto2 中 required 也是不推荐使用的。因为 required是永久性的:在将一个字段标识为required的时候,应该特别小心。如果在某些情况下不想写入或者发送一个required的字段,将原始该字段修饰符更改为optional可能会遇到问题——旧版本的使用者会认为不含该字段的消息是不完整的,从而可能会无目的的拒绝解析。

    proto3 直接从语法层面上移除了 required 规则
  3. “repeated”字段默认采用 packed 编码;

    在 proto2 中,需要明确使用 [packed=true] 来为字段指定比较紧凑的 packed 编码方式。

  4. 语言增加 Go、Ruby、JavaNano 支持;

  5. 移除了 default 选项;

    在 proto2 中,可以使用 default 选项为某一字段指定默认值。在 proto3 中,字段的默认值只能根据字段类型由系统决定。也就是说,默认值全部是约定好的,而不再提供指定默认值的语法。

Proto 一些规则

  1. 请勿更改任何现有字段的字段编号。

  2. 添加的任何新字段都应该是 optional 或 repeated。这意味着基于“旧的”消息格式的代码而序列化的任何消息仍可以由被新生成的代码解析,因为这些消息不会缺少任何 required 元素。你应该为这些元素设置合理的默认值,以便新代码可以正确地与旧代码生成的 message 进行交互。同样,你的新代码创建的 message 可以由旧代码解析:旧的二进制文件在解析时只是忽略新字段。但是未丢弃这个新字段,如果稍后序列化消息,则将新字段与其一起序列化。因此,如果将消息传递给新代码,则新字段仍然可用。(兼容性强)

  3. 可以删除非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

posted @ 2022-08-09 15:42  Clovran-Wong  阅读(2610)  评论(0编辑  收藏  举报