开发学院

您的位置:首页>教程>正文

教程正文

Protocol Buffer C++实例教程: 定义协议格式

定义协议格式

  要创建地址簿应用程序,您需要从.proto文件开始。.proto文件中的定义很简单:为要序列化的每个数据结构添加一条消息,然后为消息中的每个字段指定一个名称和类型。下面是定义的消息的.proto文件,addressbook.proto。

syntax = "proto2";

package tutorial;

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 phones = 4;
}

message AddressBook {
  repeated Person people = 1;
}

  如您所见,语法类似于C++或Java。让我们检查一下文件的每个部分,看看它有什么作用。

  .proto文件以包声明开始,这有助于防止不同项目之间的命名冲突。在C++中,生成的类将被放在与包名匹配的命名空间中。

  接下来,是您的消息定义。消息是包含一组类型化字段的集合。许多标准的简单数据类型都可作为字段类型,包括bool、int32、float、double和string。您还可以通过使用其他消息类型作为字段类型来为消息添加进一步的结构:在上面的示例中,Person消息包含honeNumber消息,而AddressBook消息包含Person消息。您甚至可以定义嵌套在其他消息中的消息类型:如您所见,honeNumber类型是在Person中定义的。如果您希望某个字段具有预定义的值列表之一,也可以定义枚举类型:在这里,您希望指定电话号码可以是MOBILE, HOME或WORK之一。

  每个元素上的" = 1", " = 2"标记标识字段在二进制编码中使用的唯一“标记”。标签号1-15需要比更高的数字少一个字节来编码,因此作为一种优化,您可以决定将那些标签用于常用或重复的元素,而将标签号16和更高的用于不常用的可选元素。重复字段中的每个元素都需要重新编码标签号,因此重复字段是这种优化的特别好的候选者。

  每个字段必须用以下修饰符之一进行注释:

  •   required: 必须为字段提供一个值,否则消息将被视为“uninitialized”。如果libprotobuf是在调试模式下编译的,序列化未初始化的消息将导致断言失败。在优化的构建中,检查被跳过,消息将被写入。但是,解析未初始化的消息总是会失败(通过从解析方法返回false )。除此之外,必填字段的行为与可选字段完全一样。

  •   optional:该字段可以设置,也可以不设置。如果未设置可选字段值,则使用默认值。对于简单类型,您可以指定自己的默认值,就像我们在示例中对电话号码类型所做的那样。否则,将使用系统默认值:数字类型为零,字符串为空字符串,布尔值为false。对于嵌入式消息,默认值始终是消息的“default instance”或“prototype”,其中没有设置任何字段。调用访问器来获取未显式设置的optional(或required)字段的值总是返回该字段的默认值。

  •   repeated: 字段可以重复任何次数(包括零)。重复值的顺序将保留在protocol buffer中。将重复字段视为动态大小的数组。

  Required是永久性的。在根据需要标记字段时,您应该非常小心。如果您希望在某个时候停止写入或发送必填字段,将该字段更改为可选字段将会有问题:旧版本的消息接收器会认为没有该字段的邮件不完整,可能会拒绝或丢弃它们。您应该考虑为您的缓冲区编写特定于应用程序的自定义验证例程。谷歌的一些工程师得出结论,使用required弊大于利;他们更喜欢只使用optional和repeated。然而,这种观点并不普遍。

  您可以在Protocol Buffer语言指南中找到完整的.proto文件编写指南,包括所有的字段类型。但是不要去寻找类似于类继承的工具:Protocol Buffer不会这样做。