简介

Protocol Buffers 又简称为 Protobuf、PB。是 Google 推出的一种数据交换格式。注意,这是二进制的交换数据。

Protobuf 有自己的编译器,在 Linux 中叫做 protoc ,可以解释.proto 文件并且生成对应语言的源文件。目前 Google 提供了三种语言:Java, C++, Python。后面我们就以 C++ 来说明,其他语言类似。

总结一下:我们所说的 Protobuf,其实可以说是包含以下几部分:

  • 一种数据交换格式,可以将 C++ 中定义的存储类的内容 与 二进制序列串 相互转换,主要用于数据传输或保存
  • 定义了一种源文件,扩展名为 .proto,使用这种源文件,可以定义存储类的内容
  • Google 提供了一个编译器 protoc,可以编译 .proto编译成 .cc文件,使之成为一个可以在 C++ 工程中直接使用的类。类的功能非常完善,后文辉具体说明。

.proto 的简单语法

我们来定义一个可以覆盖大多数使用情况的例子,定义一个高中的班级和班上学生的信息

// --------------------------------------
// File: School.HighSchool.proto
//
package School.HighSchool;

message Person
{
    optional int32   id = 1;
    optional int32   age = 2;
    optional string  first_name = 3;
    optional string  last_name = 4;
    optional bool    is_female = 5;
};

message Class
{
    optional int32   grade_num = 1;
    optional int32   class_num = 2;
    optional Person  head_teacher = 3;
    repeated Person  students = 4;
};

文件的建议命名为 “包名.消息名.proto”。对于 C++ 而言,就是 “命名空间.数据类.proto”。

上面这段的语义,我直接用 C++ 的概念来说明吧:

  • 定义包的分类(命名空间)是 School 类别下的 HighSchool 子类别。
  • 定义一个 个人 数据类,包含学生的 ID、姓、名、性别等等信息。
  • 定义一个 班级 数据类,包含年级号和班级号、班主任信息、所有学生的信息。

这里有必要说明 optional 和 repeated。前者表示这个数据类型是可选的,也就是说有可能不存在这样的一个数据信息。后者表示这个数据类型是多个的,可以理解为一个堆,或者说一个 set、一个集合,总之就是多个同类数据,类似于 C++ 中的 vector。对应于 JSON 中的 array。Repeated 类型的数据有可能是空的(成员为 0)。

与 optional 相对应的是 required 类型,表示这个数据类型是必须的。但是,大部分资料都建议不要用这种类型。


生成C++类

上面的源文件,可以使用以下命令进行编译:

protoc -I=$SRC_DIR --cpp_out=$DST_DIR School.HighSchool.proto

编译完成后,生成两个文件:School.HighSchool.pb.ccSchool.HighSchool.pb.h
在类里面,大体结构是这样的:

namespace School {
namespace HighSchool {

class Person : public ::google::protobuf::Message {
    ...
}    // end of class Student

class Class : public ::google::protobuf::Message {
    ...
}    // end of class public

}}    // end of namespaces