一、作用
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
- package discover;
- option java_package = "com.sg.discover";
- option java_outer_classname = "SocialRecommend";
- message RecommendInfo {
- optional string hid = 1;
- optional string tags = 2;
- repeated TopicInfo topicList = 3;
- }
- message TopicInfo {
- optional string name = 1;
- optional string type = 2;
- repeated string entities = 3;
- repeated string tags = 4;
- }
(2)使用如下命令编译proto文件,生成对应Java代码
注:编译成功无消息输出,会产生文件;
./ 与 msg.proto中间有空格
(3)序列化
[java] view plaincopy
- private SocialRecommend.RecommendInfo transRecommendInfoToPB(RecommendBean recommendInfo) {
- SocialRecommend.RecommendInfo.Builder builder =
- SocialRecommend.RecommendInfo.newBuilder();
- builder.setHid(recommendInfo.hid);
- builder.setTags(recommendInfo.tags);
- for(int i = 0; i< recommendInfo.topicList.size(); i++){
- TopicInfo topicInfo = recommendInfo.topicList.get(i);
- SocialRecommend.TopicInfo kvTopic = trasnTopicInfoToPB(topicInfo);
- builder.addTopicList(kvTopic);
- }
- return builder.build();
- }
[java] view plaincopy
- byte[] pbByteArray = pb.toByteArray();
(4)反序列化
[java] view plaincopy
- SocialRecommend.RecommendInfo msg = SocialRecommend.RecommendInfo.parseFrom(pbByteArray);
- System.out.println(msg);
参考http://blog.csdn.net/program_think/article/details/4229773
http://blog.csdn.net/erli11/article/details/27213239