开发者指导:
欢迎来到protocol buffers的开发者文档,protocol buffers以一种语言无关的,跨平台的,可扩展的方式序列化结构数据,它可以应用在通信协议,数据存储或者其他方面.
这个文档主要面向用JAVA,C++,Python语言进行protocol buffers应用程序开发的开发者.概要主要是介绍protocol buffers,并且告诉你在进行开发前,需要准备些什么,你可以继续跟随指导学习,或者直接探究protocol buffer的编码.针对这三种语言的API参考文献都已经提供,并且参考语言和代码格式去写.proto文件.
protocol buffers是什么?
protocol buffers提供了一种灵活的,有效的,自动的机制去序列化结构化的数据,像XML一样,但是更加的小,快速,简单.你一次性的定义你想结构化的数据,然后你可以很容易的用一种语言实现一个程序把结构化的数据往各种数据流中写或者读.你甚至可以在不破坏你的被编译成旧格式的程序的部署的情况下,更新你的数据结构.
他们如何工作?
通过在.proto文件中定义protocol buffer消息类型,你可以制定你想要序列化的信息被结构化的机制.每个protocol buffer消息是一个小的记录信息的逻辑记录,它包含了一个名字值对序列.下面是一个基本的proto文件的例子,这个文件定义了包含一个人的信息的消息.
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;
}
就像你看见的,消息的格式很简单,每个消息类型有一个或者更多个被唯一编码的域,并且每个域有一个名字值类型,其类型可以是一个数字(整形或者浮点型),bool型,strings,raw bytes,甚至(就像上面的例子一样)是其他的protocol buffer消息类型,允许你继承性的结构化你的数据.你可以指定哪个域是可选的(用optional关键字),要求的(用required关键字)或者是重复的(用repeated关键字).在Protocol Buffer 语言指导上你可以找到更多的关于.proto文件的信息.
一旦你定义了你的消息,你可以用preotocol buffers对于特定的语言编译器去编译你的.protocol文件,产生存取数据的类.这些类提供了一个简单的存取者(像query()和set_query())也就是一些方法向原始的字节中序列化整个结构,或者从原始的字节中析取出整个结构.例如,如果你选择用C++,在上面的.protocol文件上编译,将会产生一个叫做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);
然后,你可以看到下面的消息:
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参考部分,你将会找到一个完整的关于运用产生的protocol buffer代码的参考,并且在Protocol Buffer Encoding中,你能够找出更多的关于protocol buffer消息是如何被编码的信息.
为什么不仅仅用XML?
对于序列化结构数据,Protocol buffers有许多的优点超过XML:
:简单
:小3,10倍
:快20,100倍
:更准确
:产生在编程中更加容易使用的存取数据的类
例如,让我们假设你想用名字,邮件在XML中对人进行建模,你需要这么做:
<person>
<name>John Doe</name>
<email>jdoe@example.com</email>
</person>
相应的protocol buffer消息(在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纳秒去解析.这个XML版本如果去掉空格的话至少要占用68字节,并且将要花费5000-10000纳秒的时间去解析.
也就是,控制一个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就不是一种好的解决办法,因为用文本你不能很容易的表示这个结构.另外XML是一种对于人来说容易阅读,容易编辑的语言,而porotocol buffers至少在它自己的格式上不是这样的.XML在某种程度上是自描述的.只有在信息进行定义的情况下,protocol buffer才是有意义的.
听起来好像是好的解决方案,如何开始?
下载一个包http://code.google.com/p/protobuf/downloads/,它包含了完全的对于java,python,C++的protocol buffer编译器的原代码.还有为了IO和测试需要的一些类.为了构建和安装你的编译器,按照README中的步骤进行.
一旦你完成了所有的配置,根据你选择的语言按照指导进行操作,它将会让你用protocol buffers构建一个简单的应用程序.
历史:
Protocol buffers刚开始是GOOGLE开发出来的,用来处理一个索引服务的请求和回复协议,在protocol buffers以前,有一种对于请求和响应的格式,它用手工对请求和响应进行编组和解析,并且这种格式支持很多的不通版本的协议.它将会产生下面丑陋的代码:
if (version == 3) {
...
} else if (version > 4) {
if (version == 5) {
...
}
...
}
明确的格式化的协议也使得新协议版本的推出更加的复杂,因为开发者必须确保所有的服务商不论是请求的发出者还是请求的实际处理者,在他们开始用新的协议之前,理解新的协议.
protocol buffers被设计去解决下面这些问题:
1.新的域可以被容易的引进,因为中间服务器不需要理解内部的数据,就可以简单的把数据解析出来,并且不需要知道所有的域就可以通过数据.
2.格式更多的是自描述的,可以由各种语言处理.
然而,使用者仍然需要手工编写自己的解析代码.
随着系统的进化,它已经获得许多其他的特点和应用:
1.自动产生串行化和并行化的代码,避免了手工对于解析代码的编写.
2.另外可以被用于短期的远程过程调用.
3.服务器远程过程调用接口开始被声明为协议的一部分,协议编译器产生stub类,用户可以重载这个类,对它进行实际的实现.
Protocol buffers现在是GOOGLE的对于数据的通用语言,在12183个.proto文件的Google代码树中,定义了48162个不同的信息类型.它们用于远程过程调用系统或者是用于在不通的存储系统中持久化的数据存储.