[ProtoBuf]定义ProtocolBuffer消息

为什么使用Protocol Buffers

一个非常简单的 “address book” 应用例子,它可以从文件读取和向文件写入人们的联系人详情。地址簿中的每个人具有一个名字 (name)ID,电子邮件地址 (email address),和联系人电话号码 (contact phone)你要如何序列化和提取这样的结构化数据呢?有一些方法可以解决这个问题: 

原始的内存数据结构可以以二进制的形式发送/保存。随着时间的流逝,这是一种脆弱的方法,因为接收/读取的代码必须以完全相同的内存布局、尾端等等编译。此外,随着文件以原始的格式累积数据及处理那种格式的软件的复制,那种格式被不断传播,则它是非常难以扩展的格式。

你可以发明一种特别的方式来将数据项编码编码为一个字符串 —— 比如将4int值编码为”12:3:-23:67”。这是一个简单而灵活的方法,尽管它需要编写一次性的编码和解析代码,而且解析消耗一小段运行时代价。这对于编码非常简单的数据是最好的方式。

将数据序列化为XML这种方法可能非常具有吸引力,因为XML(有点) 人类可读的,而且它有大量编程语言的bindings库。如果你想要与其它的应用/项目共享数据的话,这可能是一个很好的选择。然而,XML是臭名昭著的空间密集,而且编码/解码它需要消耗应用大量的性能开销。而且,浏览一个XML DOM树也被认为比通常浏览类中的简单字段更复杂。

Protocol buffers是解决这个问题灵活,高效,自动化的方案。通过 Protocol buffers ,你可以编写一个 .proto 描述你想要存储的数据结构。通过它, Protocol buffers 编译器创建一个类,以一种高效的二进制格式实现自动的编码和解析 Protocol buffers 数据。生成的类为构成一个 Protocol buffers 的字段提供了getterssetters方法,并处理读取和写入 Protocol buffers 的细节。重要地是, Protocol buffers 格式通过使代码依然能够读取用老的格式编码的数据来支持随着时间对格式的扩展

定义一个地址簿数据结构消息(message) addressbook.proto

protoBuf的优点

  1. protoBuf在Google内部长期使用,产品稳定成熟,很多商业的项目都选择使用
  2. 跨语言,它支持Java、C++、Python、ObJect-c、C#、Go等语言,
  3. protoBuf编码后消息更小、有利于存储传输
  4. 编码和解码的效率非常之高
  5. 支持不同版本的协议向前兼容
  6. 支持自定义可选和必选字段

package tutorial;
option java_package = "sg.com.protobuf";
option java_outer_classname = "PersonProto";
message Person{
  required string name = 1;
  required int32 id = 2;
  optional string email = 3;

  enum PhoneType{
    MOBILE = 0;//移动电话
    HOME = 1;//家庭电话
    WORK = 2;//工作电话
  }

  message PhoneNumber{
    required string number = 1;
    optional PhoneType type = 2 [default = HOME];
  }

  repeated PhoneNumber phone = 4;
}

message AddressBook{
  repeated Person person = 1;
}
关键字说明:

packages包名--命名空间

package ourproject.lyphone;该包名在生成对应的C++文件时,将被替换为名字空间名称,既namespace ourproject { namespace lyphone。而在生成的Java代码文件中将成为Java代码文件的包名。

java_package:指定生Java类的包名
java_outer_classname:指定生成Java代码的外部类名称。如果没有指定该选项,Java代码的外部类名称为当前文件的文件名部分,同时还要将文件名转换为驼峰格式,如:my_project.proto

message消息——类

message是消息定义的关键字,等同于C++中的struct/class,或是Java中的class。

字段修饰符——必须required、可选optional、重复repeated

每个字段必须用下面的修饰符中的一个来注解。 

  • required:字段必须提供,否则消息将被认为是 未初始化的 (uninitialized)”。如果libprotobufdebug模式编译,则序列化未初始化的消息将导致断言失败。在优化的构建中,检查将被跳过,消息仍将被写入。然而,解析未初始化的消息将总是失败 (通过喜爱parse方法中返回false)。否则,required字段的行为将与optional字段完全相同。 
  • optional:字段可以设置也可以不设置。如果可选的字段值没有设置,则将使用默认值。对于简单的类型,你可以指定你自己的默认值,如我们在例子中为电话号码类型做的那样。否则,将使用系统默认值:数字类型为0,字符串类型为空字符串,bools值为false。对于内嵌的消息,默认值总是消息的 默认实例 (default instance)” 原型(prototype)”,它们没有自己的字段集。调用accessor获取还没有显式地设置的 optional (required) 字段的值总是返回字段的默认值。 
  • repeated:字段可以重复任意多次 (包括0)。在 protocol buffer 中,重复值的顺序将被保留。将重复字段想象为动态大小的数组。

enum——枚举

enum是枚举类型定义的关键字,等同于C++/Java中的enum。

[default = default_value]——设置默认值

optional类型的字段如果在序列化时没有被设置,或者是老版本的消息中根本不存在该字段,那么在反序列化该类型的消息是,optional的字段将被赋予类型相关的缺省值,如bool被设置为falseint32被设置为0Protocol Buffer也支持自定义的缺省值,如:

optional int32 result_per_page = 3 [default = 10]。

Tag——二进制编码唯一标识

每个元素上的 “ = 1”” = 2”标记标识在二进制编码中使用的该字段唯一的 “tag” 标签数字12则表示不同的字段在序列化后的二进制数据中的布局位置。在该例中,name字段编码后的数据一定位于id之后。需要注意的是该值在同一message中不能重复。另外,对于Protocol Buffer而言,标签值为115的字段在编码时可以得到优化,既标签值和类型信息仅占有一个byte,标签范围是162047的将占有两个bytes,而Protocol Buffer可以支持的字段数量则为229次方减一。有鉴于此,我们在设计消息结构时,可以尽可能考虑让repeated类型的字段标签位于115之间,这样便可以有效的节省编码后的字节数量。

数据类型

许多标准的简单数据类型可用作字段类型,包括boolint32floatdouble,和string。你也可以通过使用消息类型作为字段类型来给你的消息添加更多结构 —— 在上面的例子中,Person消息包含了多个PhoneNumber消息,同时AddressBook消息包含Person消息。你甚至可以在其它消息中嵌套的定义消息类型 —— 如你所见,PhoneNumber类型是在Person中定义的。如果你想要你的字段值为某个预定义的值列表中的某个值的话,你也可以定义enum类型 —— 这里你想要指定电话号码是MOBILEHOME,或WORK中的一个。类型对照表

.proto Type

Notes

C++ Type

Java Type

double

 

double

double

float

 

float

float

int32

如果你的领域可能有负值,使用SINT32代替。

int32

int

int64

如果你的领域可能有负值,使用sint64代替。

int64

long

uint32

Uses variable-length encoding.

uint32

int

uint64

Uses variable-length encoding.

uint64

long

sint32

int值。比普通int32更有效地编码负数。

int32

int

sint64

int值。比普通int64更有效地编码负数。

int64

long

fixed32

Always four bytes.

uint32

int

fixed64

Always eight bytes.

uint64

long

sfixed32

Always four bytes.

int32

int

sfixed64

Always eight bytes.

int64

long

bool

 

bool

boolean

string

A string must always contain UTF-8 or 7-bit ASCII.

string

String

bytes

May contain any arbitrary sequence of bytes.

string

ByteString



你可能感兴趣的:(序-列-化)