欢迎来到 protocol buffers 的开发者指南。protocol buffers 是一个语言中立,平台中立针对通讯协议,数据存储和其他领域中对结构化数据进行序列化的扩展方法。 本文档主要针对的是 Java,C++ 或 Python 的开发人员希望在开发的应用程序中使用 Protocol Buffers。这个有关 Protocol Buffers 摘要性的介绍将会告诉你如何开始使用 Protocol Buffers。如果你希望更加深入的了解有关 Protocol Buffers 的内容,你可以进入 tutorials 或者 protocol buffer encoding 页面来详细了解。 有关 API 的参考文档,请参考页面:reference documentation 这里提供了所有这 3 种语言的参考,同时也针对 .proto language 和 style 提供相关的指南。 什么是 Protocol Buffers? Protocol buffers 是对结构化数据序列化的一个灵活,高效,自动化工具 —— 你可以将 Protocol buffers 想象成 XML,但是体积更小,更快也更加简单。 你可以自己定义你的结构化数据,然后你可以使用特定的代码生成工具来非常容易对你的结构化数据进行读取和写入。这些数据的读取和写入可以是一系列的数据流和使用不同的计算机程序语言。你甚至可以在不对已经部署的程序进行破坏的情况下更新你的数据结构。 Protocol Buffers 是如何进行工作的 你需要制定你希望如何将你的数据进行序列化。你是通过 proto 文件来定义你的消息结构化数据的。 每一 protocol buffer message 是一个小的信息记录逻辑,这个消息中包含有一系列的名字,变量对照序列。下面是一些基本的.proto 文件,这些文件中定义了一个消息,这个消息包含有一个 person 信息: 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; } 通过上面你可以看到这个消息的格式非常简单—— 每一个消息类型都有一个或者多个唯一进行编号的字段,每一个字段包含有一个名字和变量类型。 变量可以为数字(整形或者浮点型)(numbers),布尔类型(booleans),字符串(strings),原生二进制(raw bytes)甚至其他的 protocol buffer 消息类型,能够允许你分级的结构化你的数据。 你可以将字段指定为可选字段(optional fields),必须字段(required fields)和重复字段(repeated fields)。你可以从下面的 Protocol Buffer Language Guide 页面中找到更多有关 .proto 的定义。 一旦你成功定义了你的消息,你可以针对你使用的语言使用你定义的 .proto 来运行 protocol buffer 编译器(protocol buffer compiler)来生成数据访问类。 针对每一个字段,在数据访问类中提供了简单的访问方法(例如 name() 和 set_name())和序列化到原生 2 进制数据和从原生 2 进制数据反序列化的方法。 针对上面的定义,如果你现在使用的是 C++ 语言的话,当你把消息定义进行编译后,你将会得到一个称为 Person 的类。 你可以使用这个类在你的应用程序中进行填充数据,对数据进行序列化和从序列化的数据中(protocol buffer 消息)重新获得 Person 数据。 然后你可以写一些类似 Person person; 的代码。 Person person; person.set_name("John Doe"); person.set_id(1234); person.set_email("[email protected]"); fstream output("myfile", ios::out | ios::binary); person.SerializeToOstream(&output); 随后,你可以对消息进行读取: fstream input("myfile", ios::in | ios::binary); Person person; person.ParseFromIstream(&input); cout << "Name: " << person.name() << endl; cout << "E-mail: " << person.email() << endl; 你可以向你的消息中添加新的字段而不会损坏老的消息。这是因为在老的消息处理中,针对新的字段是完全忽略掉的。因此,如果你在你的通讯协议中使用 protocol buffers 为数据结构的话,你可以对你的协议和消息进行扩展而不需要担心老的代码没有办法编译通过,或者损坏老的代码。 你可以访问 API Reference section 页面中的内容来了解完整 protocol buffer 代码的生成和使用。 你也可以在 Protocol Buffer Encoding 页面中了解更多protocol buffer 消息是如何进行编码的。 为什么不使用 XML 针对 XML 来说 Protocol Buffers 具有更多的优势来对序列化结构数据。 更加简单 小于 XML 3 到 10 倍 快于 XML 20 到 100 倍 松耦合 使用程序工具来创建数据访问类,使数访问类更加简单 假设,你需要讲 person 这个数据进行定义,在 XML 你需要使用: <person> <name>John Doe</name> <email>[email protected]</email> </person> 来进行定义。 在 Protocol Buffers 中针对上面的消息文本化(text format)后显示为: # Textual representation of a protocol buffer. # This is *not* the binary format used on the wire. person { name: "John Doe" email: "[email protected]" } 当上面的消息被编码为 Protocol Buffer 二进制格式(binary format)上面的文字可能小于 28 bytes,并且可能需要 100-200 纳秒(nanoseconds)来进行处理。 我们将上面转换为可以人为读取的目的主要是为进行调试和编辑。 如果你使用 XML 的话,上面的信息至少需要 69 bytes (你需要删除所有的空格),同时你需要 5,000-10,000 纳秒(nanoseconds)来进行处理。 同时,对 protocol buffer 进行操作也是非常容易的: cout << "Name: " << person.name() <<…