(转)Protocol Buffers概览-中译

开发向导

欢迎来到protocol buffers的开发者文档,protocol buffers是语言中立,平台中立,易于扩展的结构化数据序列化方法,它可以用在通讯协议,数据存储等方面。

这份文档的目标读者是试图在应用中使用protocol buffers的Java, C++或者Pytho开发者。这份概览告诉你如何开始-然后你可以去教程或者深入到protocol buffer编码API参考文档同样以三种语言提供,包括编写.proto文件的编程语言代码风格指导。

什么是protocol buffers?

Protocol buffers是一种可伸缩,高效的,自动化的结构化数据序列化机制,它比较像XML但是更小,更快,更简单。定义好你的数据结构,然后你就可以使用生成的特殊的源代码读写你的结构化数据,数据来源可以是各种数据流,也可以使用各种编程语言。你甚至可以在不破坏使用旧格式编译并已经部署的程序的情况下更新数据结构。

他们如何工作的?

通过在.proto文件中定义protocol buffer消息类型,说明需要被序列化的信息需要保持什么样的结构。一个protocol buffer消息是一小片信息的逻辑记录,包含一系列的名称-值对。这里是一个非常基础的例子,他定义了包含个人信息的消息:

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;
}

可以看到,消息格式很简单 - 每个消息有一个或多个编号的字段,每个字段有一个名字和一个类型,类型可以是数字(整形或浮点),布尔,字符串,原生字节或是其他protocol buffer消息类型(如上例)。你可以指明可选字段,必选字段和重复字段。关于编写.proto文件的更多信息请见Protocol Buffer语言指导

定义好消息后,就可以运行针对你的程序语言的protocol buffer编译器来编译.proto文件。这些类对每个字段提供简单存取器(例如query()和set_query())和序列化整个结构到原生字节或从原生字节解析结构的方法的。然后你可以在程序中用这个Persion类生成,序列化或者从protocl buffer消息中取得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参考找到使用生成的protocol buffer代码的完整的参考,在Protocol Buffer编码有更多关于protocol buffer消息如何编码的信息。

Why not just use XML?干嘛不直接用XML?

相较于XML,Protocol buffers在序列化结构化数据方面有许多优点。它:

  • 更简单
  • 3至10倍小
  • 快20-100倍
  • 更少的模糊性
  • 对编程来讲,生成数据访问类更容易使用。

比如说,你想建模一个person,它有name和email。如果用XML,你需要写:

扫描二维码关注公众号,回复: 750209 查看本文章
  <person>
<name>John Doename>
<email>[email protected]>
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: "[email protected]"
}

当这个消息被编码为二进制格式(文本格式)后,可能只有28字节长,并且解析只需要大约100-200纳秒。XML的版本至少69字节不包括空格,需要花费5,000-10,000纳秒解析。

Also, manipulating a protocol buffer is much easier:同样,操作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就不适合建模基于文本的有标记文档(如HTML),因为你很难在文字中插入结构信息。另外,XML是可读的并且易于手工编辑的;protocol buffers,至少在原生格式上不是这样。XML还是(某种程度上)自描述的。而protocol buffer仅仅在你有关于它的定义文件(.proto文件)的时候才有意义。

听起来对我有用!我怎么开始用它?

下载软件包 - 它包含了Java, Python, C++的protocol buffers编译器的所有源代码,还有用于I/O和测试的类。构建和安装它的方法请参见附带的README。

这些准备好以后,你就可以试试看针对你使用的编程语言的教程,它将带你一步一步创建一个使用protocol buffers的简单应用。

一点历史

Protocol buffers最初是在Google开发出来处理一个索引服务器的request/response协议的。在protocol buffers以前,有一个手动marshalling/unmarshalling请求/响应的处理格式,结果是看起来非常丑陋的代码,就像:

if(version ==3){
   
...
 
}elseif(version >4){
   
if(version ==5){
     
...
   
}
   
...
 
}

显式的格式化的协议也会把新版本协议的发布搞的很复杂,因为开发者必须保证在请求发起者和实际处理者这两端启用新协议之前,它们之间的所有的服务器,都必须理解新版本的协议。

Protocol buffers被设计来解决许多这样的问题:

  • 新的字段可以很容易被引入,不需要检查新增数据的中间服务器可以像之前一样解析原有数据并一起传输他们,不需要知道新的字段。
  • 格式是自描述的,可以被广泛的编程语言处理(C++, Java, 等)

然而,用户仍然需要手写他们自己的解析代码。

随着系统的进化,它已经有了一些其他特性和用途:

  • 自动生成的序列化和反序列化代码,用户可以不用手工编写解析代码了。
  • 除了被用作短期的RPC(远程过程调用)请求,人们开始用protocol buffers作为一种便利的自描述格式来持久化存储数据(比如Bigtable)。
  • 服务器的RPC接口开始声明成为protocol文件的一个部分,还有protocol编译器生成的类,用户可以用实际的实现重写他们。

Protocol buffers现在是Google交流数据的主要交际语 - 撰写本文时,Google的代码树中有12,183个.proto文件,包含有48,162个不同的消息类型定义。它们被用在RPC系统和各种存储系统的数据的持久化的存储。

猜你喜欢

转载自lanxinyuchs.iteye.com/blog/1100776