首页 > 代码库 > Google的开源技术protobuf概述

Google的开源技术protobuf概述

一、作用

      protobuf(Protocol Buffers)是Google内部使用的一个项目,后来贡献给开源社区为大家使用。它要做的事情和xml类似,就是要把某种数据结构的信息有某种格式保存起来,主要用于数据存储、传输协议格式等场合。

二、优点

     和xml有着类似的功能,那么肯定有一些更加优势的地方。

     1、时间开销

          xml格式化(序列化)的开销还可以,但是xml解析(反序列化)的开销较大。相比protobuf的时间开销要小一些;

      2、空间开销

         为了提高可读性xml中引入了一些冗余的文本信息,空间开销加大。相比protobuf的空间开销要小一些;

      3、开发调用简单

         只需使用message定义消息结构,在发送方使用set方法发送消息,在接收方使用调用方法接收消息即可。省去了xml配置、编译和解析的过程。

         比如:

有个电子商务的系统(假设用C++实现),其中的模块A需要发送大量的订单信息给模块B,通讯的方式使用socket。
假设订单包括如下属性:
--------------------------------
  时间:time(用整数表示)
  客户id:userid(用整数表示)
  交易金额:price(用浮点数表示)
  交易的描述:desc(用字符串表示)
--------------------------------
  如果使用protobuf实现,首先要写一个proto文件(不妨叫Order.proto),在该文件中添加一个名为"Order"的message结构,用来描述通讯协议中的结构化数据。该文件的内容大致如下:


--------------------------------
message Order
{
  required int32 time = 1;
  required int32 userid = 2;
  required float price = 3;
  optional string desc = 4;
}
--------------------------------

  然后,使用protobuf内置的编译器编译 该proto。由于本例子的模块是C++,你可以通过protobuf编译器的命令行参数(看“这里 ”),指定它生成C++语言的“订单包装类”。(一般来说,一个message结构会生成一个包装类)
  然后你使用类似下面的代码来序列化/解析该订单包装类:


--------------------------------
// 发送方
Order order;
order.set_time(XXXX);
order.set_userid(123);
order.set_price(100.0f);
order.set_desc("a test order");

string sOrder;
order.SerailzeToString(&sOrder);
// 然后调用某种socket的通讯库把序列化之后的字符串发送出去
// ......

--------------------------------
// 接收方
string sOrder;
// 先通过网络通讯库接收到数据,存放到某字符串sOrder
// ......

Order order;
if(order.ParseFromString(sOrder)) // 解析该字符串
{
  cout << "userid:" << order.userid() << endl
  << "desc:" << order.desc() << endl;
}
else
{
  cerr << "parse error!" << endl;
}
--------------------------------

 

      4、代码灵活,降低模块间的耦合性

        A和B两个模块相互通信,当其中一个模块或消息格式发生改变时,只需改动一点代码即可。

      5、支持多种编程语言

        Google发布的源码中包括C++、Java、Python三种语言,现在可以支持ActionScript、C#、Lisp、Erlang、Perl、PHP、Ruby等。而且Protobuf支持通信的双方使用不同的语言开发。

三、缺点

      1、代码可读性差

         Protobuf使用二进制格式进行编码,如果通信双方有一方出现了问题,二进制的消息很难被读懂,很难对错误定位。虽然Protobuf提供了TextFormat工具类,但是也不能彻底解决问题,未解决问题可以直接抓包并dump成log以定位错误。

      2、缺乏自描述

         没有自描述信息,二进制的格式很难被看懂,需配合Proto文件。

四、Protobuf的使用及实例

1 下载安装

(1)下载

需要两个包,protobuf-2.5.0.tar.gz,protoc-2.5.0-win32.zip。

本来可以到https://code.google.com/p/protobuf/downloads/list下载,不过被墙了。

可以移步到这里下载:http://download.csdn.net/detail/erli11/7408633 

下载相同版本供java使用的protobuf-java-2.5.0.jar:

http://repo1.maven.org/maven2/com/google/protobuf/protobuf-java/2.5.0/protobuf-java-2.5.0.jar

2demo展示

(1)创建proto文件

在protoc-2.5.0-win32目录(包含protoc.ext可执行文件),创建msg.proto

[plain] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package discover;  
  2. option java_package = "com.sg.discover";  
  3. option java_outer_classname = "SocialRecommend";    
  4.   
  5. message RecommendInfo  {  
  6.     optional string hid = 1;  
  7.     optional string tags = 2;  
  8.     repeated TopicInfo topicList = 3;  
  9. }  
  10.     
  11. message TopicInfo  {    
  12.   optional string name = 1;  
  13.   optional string type = 2;           
  14.   repeated string entities = 3;    
  15.   repeated string tags = 4;   
  16. }   

 

(2)使用如下命令编译proto文件,生成对应Java代码


注:编译成功无消息输出,会产生文件;

./ 与 msg.proto中间有空格

(3)序列化

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. private SocialRecommend.RecommendInfo transRecommendInfoToPB(RecommendBean recommendInfo) {  
  2.     SocialRecommend.RecommendInfo.Builder builder =   
  3.         SocialRecommend.RecommendInfo.newBuilder();  
  4.     builder.setHid(recommendInfo.hid);  
  5.     builder.setTags(recommendInfo.tags);  
  6.     for(int i = 0; i< recommendInfo.topicList.size(); i++){  
  7.         TopicInfo topicInfo = recommendInfo.topicList.get(i);  
  8.         SocialRecommend.TopicInfo kvTopic = trasnTopicInfoToPB(topicInfo);  
  9.         builder.addTopicList(kvTopic);  
  10.     }  
  11.     return builder.build();  
  12. }  
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. byte[] pbByteArray = pb.toByteArray();  


 

(4)反序列化

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. SocialRecommend.RecommendInfo msg = SocialRecommend.RecommendInfo.parseFrom(pbByteArray);    
  2.             System.out.println(msg);  

 

 

参考http://blog.csdn.net/program_think/article/details/4229773

       http://blog.csdn.net/erli11/article/details/27213239

Google的开源技术protobuf概述