开发者教程

欢迎使用protocol buffer的开发人员文档 - 一种与语言无关,平台无关,可扩展的序列化结构化数据的方法,用于通信协议,数据存储等。

本文档面向希望在其应用程序中使用protocol bufferJavaC++Python开发人员。 本概述介绍了protocol buffer,以及入门所需要做的工作 - 您可以继续学习本教程或深入研究protocol buffer编码API参考文档提供了包含以上三种语言的参考,以及用于编写.proto文件的语言样式指南。

什么是protocol buffer

protocol buffer是一种灵活,高效,自动化的机制,用于序列化结构化数据 - 想想XML,但更小,更快,更简单。 您可以定义数据的结构化结构,然后使用特殊生成的源代码轻松地将结构化数据写入和读取各种数据流,并使用各种语言。 您甚至可以更新数据结构,而不会破坏根据”旧”格式编译的已部署程序。

protocol buffer的工作机制?

您可以通过在.proto文件中定义protocol buffer消息类型来指定您希望如何构建序列化信息。 每个protocol buffer消息都是一个小的逻辑信息记录,包含一系列名称-值对。 以下是.proto文件的一个非常基本的示例,该文件定义了包含有关人员信息的消息:

  1. message Person {
  2. required string name = 1;
  3. required int32 id = 2;
  4. optional string email = 3;
  5. enum PhoneType {
  6. MOBILE = 0;
  7. HOME = 1;
  8. WORK = 2;
  9. }
  10. message PhoneNumber {
  11. required string number = 1;
  12. optional PhoneType type = 2 [default = HOME];
  13. }
  14. repeated PhoneNumber phone = 4;
  15. }

如您所见,消息格式很简单 - 每种消息类型都有一个或多个唯一编号的字段,每个字段都有一个名称和一个值类型,其中值类型可以是数字(整数或浮点数),布尔值,字符串,原始字节,甚至(如上例所示)其他protocol buffer消息类型,允许您分层次地构建数据。您可以指定可选字段,必填字段和重复字段。您可以在Protocol Buffer Language Guide中找到有关编写.proto文件的更多信息。

一旦定义了消息,就可以在.proto文件上运行应用程序语言的protocol buffer编译器来生成数据访问类。这些为每个字段提供了简单的访问器(如name()set_name()),以及将整个结构序列化/解析为原始字节的方法 - 例如,如果您选择的语言是C++,则运行编译器上面的例子将生成一个名为Person的类。然后,您可以在应用程序中使用此类来填充,序列化和检索Person protocol buffer消息。然后你可以写一些这样的代码:

  1. Person person;
  2. person.set_name("John Doe");
  3. person.set_id(1234);
  4. person.set_email("jdoe@example.com");
  5. fstream output("myfile", ios::out | ios::binary);
  6. person.SerializeToOstream(&output);

然后,稍后,您可以在以下位置阅读您的消息:

  1. fstream input("myfile", ios::in | ios::binary);
  2. Person person;
  3. person.ParseFromIstream(&input);
  4. cout << "Name: " << person.name() << endl;
  5. cout << "E-mail: " << person.email() << endl;

您可以在不破坏向后兼容性的情况下为邮件格式添加新字段; 旧的二进制文件在解析时只是忽略新字段。 因此,如果您的通信协议使用protocol buffer作为其数据格式,则可以扩展协议,而无需担心破坏现有代码。

您将在API参考部分找到有关使用生成的protocol buffer代码的完整参考,您可以在protocol buffer编码中找到有关protocol buffer消息如何编码的更多信息。

为什么不使用XML?

对于序列化结构化数据,protocol bufferXML具有许多优点。 protocol buffer:

  • 更简单
  • 比小3到10倍
  • 比你快20到100倍
  • 不那么暧昧
  • 生成更易于以编程方式使用的数据访问类

例如,假设您想要为具有nameemailperson建模。 在XML中,您需要:

  1. <person>
  2. <name>John Doe</name>
  3. <email>jdoe@example.com</email>
  4. </person>

而相应的protocol buffer消息(protocol buffer文本格式)是:

  1. # Textual representation of a protocol buffer.
  2. # This is *not* the binary format used on the wire.
  3. person {
  4. name: "John Doe"
  5. email: "jdoe@example.com"
  6. }

当此消息被编码为protocol buffer二进制格式(上面的文本格式只是用于调试和编辑的方便的人类可读表示)时,它可能是28字节长并且需要大约100-200纳秒来解析。 如果删除空格,XML版本至少为69个字节,并且需要大约5,000-10,000纳秒才能解析。

此外,操作protocol buffer要容易得多:

  1. cout << "Name: " << person.name() << endl;
  2. cout << "E-mail: " << person.email() << endl;

而使用XML,您必须执行以下操作:

  1. cout << "Name: "
  2. << person.getElementsByTagName("name")->item(0)->innerText()
  3. << endl;
  4. cout << "E-mail: "
  5. << person.getElementsByTagName("email")->item(0)->innerText()
  6. << endl;

但是,protocol buffer并不总是比XML更好的解决方案 - 例如,protocol buffer不是使用标记(例如HTML)对基于文本的文档建模的好方法,因为您无法轻松地将结构与文本交错。 此外,XML是人类可读和人类可编辑的; protocol buffer,至少是它们的原生格式不是。 XML在某种程度上也是自我描述的。 只有拥有消息定义(.proto文件)时,protocol buffer才有意义。

对我来说听起来像是解决方案! 我该如何开始?

下载包 - 它包含JavaPythonC ++``protocol buffer编译器的完整源代码,以及I/O和测试所需的类。 要构建和安装编译器,请按照自述文件中的说明进行操作。

完成所有设置后,请尝试按照所选语言的教程进行操作 - 这将指导您创建一个使用protocol buffer的简单应用程序。

介绍proto3

我们最新的版本3发布了一个新的语言版本-Protocol Buffer语言版本3(aka proto3),以及我们现有语言版本(aka proto2)中的一些新功能。 Proto3简化了Protocol Buffer,既易于使用,又可以在更广泛的编程语言中使用:我们当前的版本允许您使用JavaC++PythonJava LiteRubyJavaScriptObjective-CC#生成Protocol Buffer代码。此外,您可以使用最新的Go protoc插件为Go生成proto3代码,该插件可从golang/protobuf Github存储库获得。更多语言正在筹备中。

请注意,两种语言版本的API不完全兼容。为避免给现有用户带来不便,我们将继续在新Protocol Buffer版本中支持以前的语言版本。

您可以在发行说明中看到与当前默认版本的主要差异,并了解Proto3语言指南中的proto3语法。 proto3的完整文档即将推出!

(如果名称proto2proto3看起来有点令人困惑,那是因为当我们最初开源的Protocol Buffer时,它实际上是Google的第二版语言 - 也称为proto2。这也是我们的开源版本号从v2.0.0开始的原因。)

一些历史

Protocol Buffer最初是在Google开发的,用于处理索引服务器请求/响应协议。 在Protocol Buffer之前,有一种请求和响应的格式,它使用请求和响应的手动编组/解组,并支持许多版本的协议。 这导致了一些非常丑陋的代码,例如:

  1. if (version == 3) {
  2. ...
  3. } else if (version > 4) {
  4. if (version == 5) {
  5. ...
  6. }
  7. ...
  8. }

明确格式化的协议也使新协议版本的推出变得复杂,因为开发人员必须确保请求的发起者和处理请求的实际服务器之间的所有服务器都能理解新协议,然后才能切换开关以开始使用新协议。

Protocol Buffer旨在解决许多这些问题:

  • 可以轻松引入新字段,而不需要检查数据的中间服务器可以简单地解析它并传递数据而无需了解所有字段。
  • 格式更具自我描述性,可以用各种语言(C++Java等)处理。

但是,用户仍然需要手写自己的解析代码。

随着系统的发展,它获得了许多其他功能和用途:

  • 自动生成的序列化和反序列化代码避免了手动解析的需要。
  • 除了用于短期RPC(远程过程调用)请求之外,人们还开始使用Protocol Buffer作为一种方便的自描述格式,用于持久存储数据(例如,在Bigtable中)。
  • 服务器RPC接口开始被声明为协议文件的一部分,协议编译器生成存根类,用户可以通过服务器接口的实际实现来覆盖它们。

Protocol Buffer现在是Google的数据通用语言 - 在撰写本文时,Google代码树中有348952个.proto文件中定义了306747种不同的消息类型。 它们既可用于RPC系统,也可用于各种存储系统中的数据持久存储。