Protocol Buffer Basics: C++ 简单的Protocol Buffer C++例子

This tutorial provides a basic C++ programmer’s introduction to working with protocol buffers. By walking through creating a simple example application, it shows you how to

  • Define message formats in a .proto file.
  • Use the protocol buffer compiler.
  • Use the C++ protocol buffer API to write and read messages.

This isn’t a comprehensive guide to using protocol buffers in C++. For more detailed reference information, see the Protocol Buffer Language Guide, the C++ API Reference, the C++ Generated Code Guide, and the Encoding Reference.

简单的Protocol Buffer例子。

Defining Your Protocol Format

To create your address book application, you’ll need to start with a .proto file. The definitions in a .proto file are simple: you add a message for each data structure you want to serialize, then specify a name and a type for each field in the message. Here is the .proto file that defines your messages, addressbook.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;
}

As you can see, the syntax is similar to C++ or Java. Let’s go through each part of the file and see what it does.

语法跟C++或Java相似。

The .proto file starts with a package declaration, which helps to prevent naming conflicts between different projects. In C++, your generated classes will be placed in a namespace matching the package name.

首先需要一个package声明,用来防止在不同项目中的命令冲突。在C++中,这个package声明会被翻译成namespace命名空间,然后里面是翻译的你定义的类。

接下来,您将得到消息定义。消息只是包含一组类型字段的聚合。许多标准的简单数据类型都可用作字段类型,包括bool、int32、float、double和string。您还可以使用其他消息类型作为字段类型来为消息添加进一步的结构-在上面的示例中,Person消息包含PhoneNumber消息,而AddressBook消息包含Person消息。您甚至可以定义嵌套在其他消息中的消息类型——如您所见,电话号码类型是在Person中定义的。如果希望某个字段具有一个预定义的值列表,也可以定义枚举类型-在这里,您要指定电话号码可以是移动电话号码、家庭电话号码或工作电话号码。

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

扫描二维码关注公众号,回复: 9744882 查看本文章

Each field must be annotated with one of the following modifiers:

  • required(必需):必须提供字段的值,否则消息将被视为“未初始化”。如果libprotobuf是在调试模式下编译的,序列化未初始化的消息将导致断言失败。在优化的生成中,将跳过检查,并且无论如何都将写入消息。但是,解析未初始化的消息总是会失败(解析方法返回false)。除此之外,必选字段的行为与可选字段完全相同。
  • optional:字段可以设置,也可以不设置。如果未设置可选字段值,则使用默认值。对于简单类型,可以指定自己的默认值,正如我们在示例中对电话号码类型所做的那样。否则,将使用系统默认值:数字类型为零,字符串为空字符串,bools为false。对于嵌入消息,默认值始终是消息的“默认实例”或“原型”,该消息没有设置任何字段。调用访问器以获取未显式设置的可选(或必需)字段的值总是返回该字段的默认值。
  • repeated :该字段可以重复任意次数(包括零次)。重复值的顺序将保留在协议缓冲区中。将重复字段看作动态大小的数组。

Required Is Forever You should be very careful about marking fields as required. If at some point you wish to stop writing or sending a required field, it will be problematic to change the field to an optional field – old readers will consider messages without this field to be incomplete and may reject or drop them unintentionally. You should consider writing application-specific custom validation routines for your buffers instead. Some engineers at Google have come to the conclusion that using required does more harm than good; they prefer to use only optional and repeated. However, this view is not universal.

You’ll find a complete guide to writing .proto files – including all the possible field types – in the Protocol Buffer Language Guide. Don’t go looking for facilities similar to class inheritance, though – protocol buffers don’t do that.

Required是不可以删除的,举个例子,作为对象的标识就很适合。

Compiling Your Protocol Buffers

Now that you have a .proto, the next thing you need to do is generate the classes you’ll need to read and write AddressBook (and hence Person and PhoneNumber) messages. To do this, you need to run the protocol buffer compiler protoc on your .proto:

If you haven’t installed the compiler, download the package and follow the instructions in the README.

Now run the compiler, specifying the source directory (where your application’s source code lives – the current directory is used if you don’t provide a value), the destination directory (where you want the generated code to go; often the same as $SRC_DIR), and the path to your .proto. In this case, you…:

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

Because you want C++ classes, you use the --cpp_out option – similar options are provided for other supported languages.

This generates the following files in your specified destination directory:

  • addressbook.pb.h, the header which declares your generated classes.
  • addressbook.pb.cc, which contains the implementation of your classes.

命令如下:

:cat 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;
}
:protoc -I=. --cpp_out=. ./addressbook.proto
:ls
addressbook.pb.cc	addressbook.pb.h	addressbook.proto
The Protocol Buffer API

Let’s look at some of the generated code and see what classes and functions the compiler has created for you. If you look in addressbook.pb.h, you can see that you have a class for each message you specified in addressbook.proto. Looking closer at the Person class, you can see that the compiler has generated accessors for each field. For example, for the name, id, email, and phones fields, you have these methods:

  // name
  inline bool has_name() const;
  inline void clear_name();
  inline const ::std::string& name() const;
  inline void set_name(const ::std::string& value);
  inline void set_name(const char* value);
  inline ::std::string* mutable_name();

  // id
  inline bool has_id() const;
  inline void clear_id();
  inline int32_t id() const;
  inline void set_id(int32_t value);

  // email
  inline bool has_email() const;
  inline void clear_email();
  inline const ::std::string& email() const;
  inline void set_email(const ::std::string& value);
  inline void set_email(const char* value);
  inline ::std::string* mutable_email();

  // phones
  inline int phones_size() const;
  inline void clear_phones();
  inline const ::google::protobuf::RepeatedPtrField< ::tutorial::Person_PhoneNumber >& phones() const;
  inline ::google::protobuf::RepeatedPtrField< ::tutorial::Person_PhoneNumber >* mutable_phones();
  inline const ::tutorial::Person_PhoneNumber& phones(int index) const;
  inline ::tutorial::Person_PhoneNumber* mutable_phones(int index);
  inline ::tutorial::Person_PhoneNumber* add_phones();

先挂着。。

发布了114 篇原创文章 · 获赞 5 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/LU_ZHAO/article/details/104788564