当前位置: 首页>数据库>正文

protobuf响应解析 java protobuf解析工具

一、原理

protobuf全称Google Protocol Buffers,是google开发的的一套用于数据存储,网络通信时用于协议编解码的工具库。它和XML或者JSON差不多,也就是把某种数据结构的信息,以某种格式(XML,JSON)保存起来,protobuf与XML和JSON不同在于,protobuf是基于二进制的。主要用于数据存储、传输协议格式等场合。那既然有了XML等工具,为什么还要开发protobuf呢?主要是因为性能,包括时间开销和空间开销:

1.时间开销:XML格式化(序列化)和XML解析(反序列化)的时间开销是很大的,在很多时间性能上要求很高的场合,你能做的就是看着XML干瞪眼了。

2.空间开销:熟悉XML语法的同学应该知道,XML格式为了有较好的可读性,引入了一些冗余的文本信息。所以空间开销也不是太好(应该说是很差,通常需要实际内容好几倍的空间)。

据实验(当然不是我实验),一条消息数据,用protobuf序列化后的大小是json格式的十分之一,xml格式的二十分之一。

作者:majianfei1023 
来源:CSDN 
原文: 
版权声明:本文为博主原创文章,转载请附上博文链接!

代码 生成机制
  除了性能好,代码生成机制是主要吸引俺的地方。为了说明这个代码生成机制,俺举个例子。
  比如有个电子商务的系统(假设用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;
}

  有了这种代码生成机制,开发人员再也不用吭哧吭哧地编写那些协议解析的代码了(干这种活是典型的吃力不讨好)。
  万一将来需求发生变更,要求给订单再增加一个“状态”的属性,那只需要在Order.proto文件中增加一行代码。对于发送方(模块A),只要增加一行设置状态的代码;对于接收方(模块B)只要增加一行读取状态的代码。哇塞,简直太轻松了!
  另外,如果通讯双方使用不同的编程语言来实现,使用这种机制可以有效确保两边的模块对于协议的处理是一致的。
  顺便跑题一下。
  从某种意义上讲,可以把proto文件看成是描述通讯协议的规格说明书(或者叫接口规范)。这种伎俩其实老早就有了,搞过微软的COM编程或者接触过CORBA的同学,应该都能从中看到IDL(详细解释看“这里 ”)的影子。它们的思想是相通滴。

  ◇支持“向后兼容”和“向前兼容”
  还是拿刚才的例子来说事儿。为了叙述方便,俺把增加了“状态”属性的订单协议成为“新版本”;之前的叫“老版本”。
  所谓的“向后兼容”(backward compatible),就是说,当模块B升级了之后,它能够正确识别模块A发出的老版本的协议。由于老版本没有“状态”这个属性,在扩充协议时,可以考 虑把“状态”属性设置成非必填 的,或者给“状态”属性设置一个缺省值(如何设置缺省值,参见“这里 ”)。
  所谓的“向前兼容”(forward compatible),就是说,当模块A升级了之后,模块B能够正常识别模块A发出的新版本的协议。这时候,新增加的“状态”属性会被忽略。
  “向后兼容”和“向前兼容”有啥用捏?俺举个例子:当你维护一个很庞大的分布式系统时,由于你无法同时 升级所有 模块,为了保证在升级过程中,整个系统能够尽可能不受影响,就需要尽量保证通讯协议的“向后兼容”或“向前兼容”。

  ◇支持多种编程语言
  俺开博以来点评 的几个开源项目(比如“Sqlite ”、“cURL ”),都是支持很多种 编程语言滴,这次的protobuf也不例外。在Google官方发布的源代码中包含了C++、Java 、Python三种语言(正好也是俺最常用的三种,真爽)。如果你平时用的就是这三种语言之一,那就好办了。
  假如你想把protobuf用于其它语言,咋办捏?由于Google一呼百应的号召力,开源社区对protobuf响应踊跃,近期冒出很多其它编程语言的版本(比如ActionScript、C#、Lisp、Erlang、Perl、PHP 、Ruby等),有些语言还同时搞出了多个开源的项目。具体细节可以参见“这里 ”。
  不过俺有义务提醒一下在座的各位同学。如果你考虑把protobuf用于上述这些语言,一定认真评估对应的开源库。因为这些开源库不是Google官方提供的、而且出来的时间还不长。所以,它们的质量、性能等方面可能还有欠缺。

  ★protobuf有啥缺陷?
  前几天刚刚在“光环效应 ”的帖子里强调了“要同时评估优点和缺点”。所以俺最后再来批判一下这玩意儿的缺点。
  ◇应用 不够广
  由于protobuf刚公布没多久,相比XML而言,protobuf还属于初出茅庐。因此,在知名度、应用广度等方面都远不如XML。由于这个原因,假如你设计的系统需要提供若干对外的接口给第三方系统调用,俺奉劝你暂时不要考虑protobuf格式。
  ◇二进制格式导致可读性差
  为了提高性能,protobuf采用了二进制格式进行编码。这直接导致了可读性差的问题(严格地说,是没有可读性)。虽然protobuf提供了TextFormat这个工具类(文档在“这里 ”),但终究无法彻底解决此问题。
  可读性差的危害,俺再来举个例子。比如通讯双方如果出现问题,极易导致扯皮(都不承认自己有问题,都说是对方的错)。俺对付扯皮的一个简单方法 就是直接抓包并dump成log,能比较容易地看出错误在哪一方。但是protobuf的二进制格式,导致你抓包并直接dump出来的log难以看懂。
  ◇缺乏自描述
  一般来说,XML是自描述的,而protobuf格式则不是。给你一段二进制格式的协议内容,如果不配合相应的proto文件,那简直就像天书一般。
  由于“缺乏自描述”,再加上“二进制格式导致可读性差”。所以在配置文件方面,protobuf是肯定无法取代XML的地位滴。


https://www.xamrdz.com/database/6qe1962882.html

相关文章: