Protocol Buffers



        这篇概论主要是介绍Protocol Buffers,并且告诉你,如果你要开始使用Protocol Buffers,需要做哪些事情。

1. 什么是Protocol Buffers
        Protocol Buffers是一种易扩展、高效的、自动化的序列化结构化的数据的机制,比起XML来,它更小、更快、更简单。一旦你明确了你想要你的数据用什么结构, 你就可以很容易用某种生成的源代码来读写你的结构化数据,可以是各种各样的数据流,也可以用在各种各样的语言中。你甚至可以更新你的数据结构,而不用重新 部署你用“老”的数据格式编译的程序。

2. Protocol Buffers是怎样工作的?
        你可以通过在.proto文件里面用Protocol Buffers消息类型进行定义,来让你准备序列化的信息如何结构化。每一个Protocol Buffers消息是信息的一条小的逻辑记录,里面包含一系列名称-值对。下面我们来看一个非常简单的.proto文件,这个文件定义了一个人的信息。

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


        正如你看到的,消息格式非常简单,每个消息类型都有一个或者多个唯一的有限域,每个域都有一个名称和值类型,值类型可以是数字(整数或者浮点数)、布尔 值、字符串、连续字节,甚至可以是其他的Protocol Buffers的消息类型(如上面的例子),这样你可以用分层的方式定义你的数据结构。并且你可以指定可选的域、必选的域和重复的域。

        一旦你已经定义了你的Protocol Buffers消息,你可以对你的.proto文件运行你应用程序所使用语言的Protocol Buffers编译器来生成数据访问类。这个类会为每个域提供简单的访问方法(类似query()和set_query()),也会提供方法把整个结构序 列化成连续字节或者从连续字节解析成一个整个结构。举个例子,如果你选择了C++语言,在上面给出的例子上运行编译器,将会生成一个C++的Person 类,然后你可以在你的应用程序里面使用这个类,来填充、序列化和检索这个Person的Protocol Buffers的消息。你可以写出一些类似这样的代码:

C++代码   收藏代码
  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);  


        然后,晚点,你可以读回你的消息:

C++代码   收藏代码
  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 Buffers作为你数据格式的通信协议时,你可以扩展你的协议,而不用担心破坏现有的代码。

3. 为什么不使用XML?
        在序列化结构化数据方面,Protocol Buffers比起XML来,有很多优点:

  • Protocol Buffers比XML更简单。
  • Protocol Buffers比XML小3~10倍。
  • Protocol Buffers比XML快20~100倍。
  • Protocol Buffers比XML更明确。
  • 在生成数据访问类方面,Protocol Buffers比XML更容易编程实现。


        我们以构建一个person模型为例子,person里面包含一个name和一个email。如果采用XML方式,我们需要如下处理:

Xml代码   收藏代码
  1. <person>  
  2.   <name>John Doe</name>  
  3.   <email>jdoe@example.com</email>  
  4. </person>  


        而相应的Protocol Buffers消息(文本格式)如下所示:

Proto代码   收藏代码
  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 Buffers二进制格式(上面的Protocol Buffers的文本格式只是为了方便调试或编辑的时候阅读)的时候,可能只有28个字节,解析只需要大概100~200纳秒。而XML版本的至少需要 69个字节(除去空格等),解析需要大概5~10微秒的时间。

        同样,操作一个Protocol Buffers也更容易:

C++代码   收藏代码
  1. cout << "Name: " << person.name() << endl;  
  2. cout << "E-mail: " << person.email() << endl;  


        反而使用XML你需要如下处理:

C++代码   收藏代码
  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 Buffers并不总是一个比XML更好的解决方案。比如,使用一个基于标记的文本文档进行建模,使用Protocol Buffers并不是一个很好的方案,因为在文本里面你不能很容易的进行隔行扫描结构。另外,XML的可读性和可编辑性要比Protocol Buffers的本地格式好很多。XML还有一些扩展——自我描述。Protocol Buffers只有在你已经对消息进行了定义(.proto文件)的前提下,才有意义。

4. Protocol Buffers简史
        Protocol Buffers最初是由Google开发,用来处理索引服务器的请求/响应协议。在Protocol  Buffers之前,采用了一种通过手工编组的格式来处理请求和响应,并且这种协议还支持多版本的,这样就导致了会出现一些丑陋的代码,如下所示:

C++代码   收藏代码
  1. if (version == 3) {  
  2.   ...  
  3. } else if (version > 4) {  
  4.   if (version == 5) {  
  5.     ...  
  6.   }  
  7.   ...  
  8. }  


        很明显,格式化的协议会让部署新版本协议的时候更加复杂,因为开发人员必须在按下一个开关开始使用新的协议之前,确认所有服务器(包括请求发起服务器和真正处理请求的服务器)能够理解新的协议。

        Protocol Buffers是被设计用来解决以下两个方面的许多问题:

  • 数据格式里面能够很容易引入一个新的域,中间服务器不需要观察数据格式就能够很简单的去解析它,并且不需要知道所有域就能够让数据通过。
  • 数据格式里面有更多的自我描述,能够被各种各样的语言(C++、Java等)处理。


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

        随着Protocol Buffers的发展,它又有了一些其他的特征和用法:

  • 自动生成序列化和反序列化代码,从而避免手工编写解析代码。
  • 另外因为能够被用来进行短暂的远程过程调用(Remote Procedure Call,RPC)式的请求,所以人们开始使用Protocol Buffers作为一个便利的自我描述的数据格式,用来进行数据的持久化存储(例如,在Bigtable里面)。
  • 服务器的RPC接口可以开始作为协议文件的一部分来进行声明了,协议编译器可以自动生成stub类,用户可以在服务器端用真实的接口实现来进行重载。


        Protocol Buffers现在是Google的数据沟通语言,在写这篇文章的时候,在Google的代码里面大概用12183个.proto文件定义了大概 48162种不同的消息类型。他们被用于RPC系统和在各种各样的存储系统里面持久化存储数据这两个方面。

转载于:https://my.oschina.net/aiadaniel/blog/95615

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值