一个语言中立,平台中立,可扩展的方法序列化结构数据用于protocols的交流,数据存储和更多。
这篇文档用户是用于Java,C++,或者是Python语言开发者想在他们的应用中使用protocol buffers的。大概的介绍了protocol buffers和告诉你开始时需要做什么。
1What are protocol buffers?(protocol buffers是什么?)
protocol buffers是一个灵活的,高效的,自动在序列化结构数据时,像XML,但是protocol buffers更小、更快、更简单。你可以决定你想要你的数据是什么结构的,然后你可以使用生成的源代码简单的写和读取你的结构数据,从多样化的数据流获取和使用多种语言。你甚至可以更改你的数据结构在不破坏已部署的项目。
2How do they work?(他们是怎么工作的)
你确定你想要的信息,通过在.proto 文件定义protocol buffer类型的message。每一个protocol buffer的message是一个消息的小的逻辑记录,包括一系列的name-value 对。下面是一个基本的.proto文件的例子,这个例子中定义了一个message,包括关于一个人的信息:
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; }
然后,你可以像下面这样读取你的信息:
fstream input("myfile", ios::in | ios::binary); Person person; person.ParseFromIstream(&input); cout << "Name: " << person.name() << endl; cout << "E-mail: " << person.email() << endl;
正如你所看到的,message(消息)的格式是简单的,每一个message(消息)类型有一个或多个唯一的数字属性,每一个属性有一个名称(name)和一个value类型,value 类型可以是numbers(integer或者是浮点型的),booleans,strings,raw bytes,甚至是其他的protocol buffer message 类型,允许你组织你的数据分层。你可以指定optional 属性,required(必须的)属性和repeated(重复的)属性。
一旦你已经定义了你的消息,你可以运行你应用中的语言的protocol buffer 编辑器编辑你的.proto文件来生成数据访问类。这些提供了简单的访问每一个属性就像方法用于serialize/parse整个结构to/from raw bytes.所以,对于实例,如果你选择的语言是C++,使用编辑器编译上面的例子会生成一个叫Person类。你可以在你的应用中使用这个类来生成、序列化和恢复Person protocol buffer 消息。你应该像下面这样写代码:
Person person; person.set_name("John Doe"); person.set_id(1234); person.set_email("jdoe@example.com"); fstream output("myfile", ios::out | ios::binary); person.SerializeToOstream(&output);你可以在你的message格式中添加新的属性在不破坏向后兼容性的情况下;在解析时旧的二进制会忽略新增加的属性。所以如果你有一个交流的protocol,用protocol buffer作为数据格式,你可以扩展你的protocol在不用担心破坏已存在的代码下。
你会发现在API Reference中生成protocol buffer的完整版。
3why not just use XML?(为什么不使用XML)
protocol buffers比XML序列化结构数据有很多优势:
1,、更简单;2、小到3到10倍;3、快20到100倍;4、更少的歧义;5、生成数据访问类比编程的方式更简单
比如,你想要一个Person模型有一个name和emial,使用XML,你需要:
<person> <name>John Doe</name> <email>jdoe@example.com</email> </person>当你响应protocol buffer 消息时:
# Textual representation of a protocol buffer. # This is *not* the binary format used on the wire. person { name: "John Doe" email: "jdoe@example.com" }
当这个消息被编码成protocol buffer 的二进制格式时,它可能是28个字节花费100-200 nanoseconds 来解析。使用XML至少是69字节如果你删除一个空格,和花费5000-10000 nanoseconds 来解析。
所以,综上所述protocol buffer更简单:
cout << "Name: " << person.name() << endl; cout << "E-mail: " << person.email() << endl;然而使用XML你将会像下面:
cout << "Name: " << person.getElementsByTagName("name")->item(0)->innerText() << endl; cout << "E-mail: " << person.getElementsByTagName("email")->item(0)->innerText() << endl;然而,protocol buffers并不总是比XML好,对于一个实例,protocol buffers将会是一个再好不过的方法了,因为你不需要简单的使用text插入结构。另外,XML是可读和可编辑的,protocol buffers,至少在他们内部的格式,不像XML是自己描述定义的。一个protocol buffer只有你定义了.proto文件才有意义。
5How do I get started?
下载包http://code.google.com/p/protobuf/downloads/list,这个包括了用于编译Java 、Python和C++源代码的编译器,就像你需要I/O和测试类。为了创建和运行你的编辑器,安装README中的介绍去做。
一旦你都设置好了,安装教程中去尝试使用你选择的语言,这会一步一步的让你通过使用protocol buffer创建一个简单的应用。
6A bit of history
protocol buffer 是Google开发的,用于处理索引服务的request/response协议。在protocol buffer之前,有一个格式用于request和response用于处理marshalling/unmarshalling of requests and responses,支持protocol好几个版本。这以某些方式生成丑陋的代码,比如:
if (version == 3) { ... } else if (version > 4) { if (version == 5) { ... } ... }
明确了protocol的格式也使新的protocol版本显示复杂了,因为开发人员已经确定所有的在起始的请求和真实的服务处理请求理解了新的protocol在他们能够跳出开始使用新的之前。
Protocol buffers 已经设计了很多解决问题的方法:
(1)、新的属性能够很容易的被引进,中间服务器不需要检查数据能够简单的解析它不需要知道所有的属性。
(2)、格式有更多的自我描述,可以处理多种语言(C++,Java等)。
但是,用户仍然需要亲自写自己的解析代码。
因为系统的演变,它获得了一些其他的特性和用途:
(1)自动序列化和反序列化代码避免了需要手动解析;
(2)除了用于短暂的RPC请求,人们开始使用protocol buffers作为自我描述的格式永久性的存储数据;
(3)服务器RPC接口被声明为protocl 文件的一部分,在protocol编译器生成类,这些类能够重写服务器接口的实现。