protocol buffers详细介绍及项目主页地址
protocol buffers主页: https://code.google.com/p/protobuf/
一、protocol buffers介绍
Protocol Buffers是Google公司开发的一种数据描述语言,类似于XML能够将结构化数据序列化,可用于数据存储、通信协议等方面。它不依赖于语言和平台并且可扩展性极强。现阶段官方支持c++、java、python等三种编程语言,但可以找到大量的几乎涵盖所有语言的第三方拓展包。通过它,你可以定义你的数据的结构,并生成基于各种语言的代码。这些你定义的数据流可以轻松地在传递并不破坏你已有的程序。并且你也可以更新这些数据而现有的程序也不会受到任何的影响。Protocol Buffers经常被简称为protobuf。
通常,编写一个protocol buffers应用需要经历如下三步:
2、使用Google提供的protocol buffers编译器来生成代码文件,一般为.h和.cc文件,主要是对消息格式以特定的语言方式描述
3、使用protocol buffers库提供的API来编写应用程序
二、定义Proto文件
proto文件即消息协议原型定义文件,在该文件中我们可以通过使用描述性语言,来良好的定义我们程序中需要用到数据格式。首先我们可以通过Google在线文档上提供的一个电话簿的例子来了解下,不过稍微加了点改动。
//本文由 http://www. 编辑整理 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; required bytes unsure = 5; //Add byte array here } message AddressBook { repeated Person person = 1; }
消息格式定义很简单,对于每个字段而言都有一个修饰符(required/repeated/optional)、字段类型(bool/string/bytes/int32等)和字段标签(Tag)组成。
三个修饰符解释如下:
1)对于required的字段而言,初值是必须要提供的,否则字段的便是未初始化的。在Debug模式的buffer库下编译的话,序列化话的时候可能会失败,而且在反序列化的时候对于该字段的解析会总是失败的。所以,对于修饰符为required的字段,请在序列化的时候务必给予初始化。
2)对于optional的字段而言,如果未进行初始化,那么一个默认值将赋予该字段,当然也可以指定默认值,如上述proto定义中的PhoneType字段类型。
3)对于repeated的字段而言,该字段可以重复多个,google提供的这个addressbook例子便有个很好的该修饰符的应用场景,即每个人可能有多个电话号码。在高级语言里面,我们可以通过数组来实现,而在proto定义文件中可以使用repeated来修饰,从而达到相同目的。当然,出现0次也是包含在内的。
其中字段标签标示了字段在二进制流中存放的位置,这个是必须的,而且序列化与反序列化的时候相同的字段的Tag值必须对应,否则反序列化会出现意想不到的问题。
三、编译proto文件,生成特定语言数据的数据定义代码
在定义好了proto文件,就可以将该文件作为protocol buffers编译器的输入文件,编译产生特定语言的数据定义代码文件了。本文主要是针对C++语言,所以使用编译器后生成的是.h与.cc的代码文件。
编译安装完成protocol buffers后,就可以使用下列命令来完成编译过程:
protoc.exe -proto_path=SRC --cpp_out=DST SRC/addressbook.proto
其中--proto_path指出proto文件所在的目录,--cpp_out则是生成的代码文件要放的目录,最后的一个参数指出proto文件的路径。如上述命令中可以看出,将SRC目录下的addressbook.proto编译后放在DST目录下,应该会生成addressbook.pb.h和addressbook.pb.cc文件(/Files/royenhome/addressbook.rar)。
通过查看头文件,可以发现针对每个字段都会大致生成如下几种函数,以number为例:
// required string number = 1; inline bool has_number() const; inline void clear_number(); inline const ::std::string& number() const; inline void set_number(const ::std::string& value); inline void set_number(const char* value); inline ::std::string* mutable_number();
可以看出,对于每个字段会生成一个has函数(has_number)、clear清除函数(clear_number)、set函数(set_number)、get函数(number和mutable_number)。这儿解释下get函数中的两个函数的区别,对于原型为const std::string &number() const的get函数而言,返回的是常量字段,不能对其值进行修改。但是在有一些情况下,对字段进行修改是必要的,所以提供了一个mutable版的get函数,通过获取字段变量的指针,从而达到改变其值的目的。
而对于字段修饰符为repeated的字段生成的函数,则稍微有一些不同,如技术文章 iis7站长之家字段,则编译器会为其产生如下的代码:
// repeated .Person.PhoneNumber phone = 4; inline int phone_size() const; inline void clear_phone(); inline const ::google::protobuf::RepeatedPtrField< ::Person_PhoneNumber >& phone() const; inline ::google::protobuf::RepeatedPtrField< ::Person_PhoneNumber >* mutable_phone(); inline const ::Person_PhoneNumber& phone(int index) const; inline ::Person_PhoneNumber* mutable_phone(int index); inline ::Person_PhoneNumber* add_phone();
可以看出,set函数变成了add函数,这个其实很好理解。上面也说过,repeated修饰的字段在高级语言中的实现可能是个数组或动态数组,所以当然通过添加的方式来加入新的字段值。
四、 protocol buffers优点
同XML相比,Protocol buffers在序列化结构化数据方面有许多优点:
1. 使用简单
2. 体积小,比XML小3-10倍
3. 高性能,比XML块20-100倍
4. 减少了二义性
6、支持多种编程语言
7 平台无关、语言无关、兼容性好
举例
我们可以举出例子对这两者进行比较。
XML格式数据:
<person> <name>John Doe</name> <email>jdoe@</email> </person>
Protocol buffers定义:
person { name: "John Doe" email: "jdoe@“ }
java命名空间javax.naming接口context的类成员方法: security_protocol定义及介绍 Protocol Buffers Editor java命名空间javax.xml.soap接口soapconstants成员方法: default_soap_protocol定义参考 Protocol Buffers java命名空间javax.xml.soap接口soapconstants成员方法: soap_1_1_protocol定义参考 提示:RPC:unknown protocol 这是为什么? java命名空间javax.xml.soap接口soapconstants成员方法: soap_1_2_protocol定义参考 PHP HTTP protocol client java命名空间javax.management.remote类jmxconnectorserverfactory的类成员方法: protocol_provider_packages定义及介绍 protocol2method java命名空间javax.management.remote类jmxconnectorfactory的类成员方法: protocol_provider_packages定义及介绍 Redis 的 Java 实现 redis-protocol java命名空间java.io接口objectstreamconstants的类成员方法: protocol_version_1定义及介绍 关于 Address family not supported by protocol java命名空间java.io接口objectstreamconstants的类成员方法: protocol_version_2定义及介绍 如何解决can't identify protocol的问题 java命名空间javax.xml.soap接口soapconstants成员方法: dynamic_soap_protocol定义参考 怎么确定 socket(int domain, int type, int protocol) 三个参数? java命名空间javax.management.remote类jmxconnectorfactory的类成员方法: protocol_provider_class_loader定义及介绍 connect:address family not supported by protocol该如何解决? java命名空间javax.management.remote类jmxconnectorserverfactory的类成员方法: protocol_provider_class_loader定义及介绍