Google Protocol Buffer(简称 Protobuf)是一种轻便高效的结构化数据存储格式,平台无关、语言无关、可扩展,可用于通信协议和数据存储等领域。java
数据交互xml、json、protobuf格式比较git
一、json: 通常的web项目中,最流行的主要仍是json。由于浏览器对于json数据支持很是好,有不少内建的函数支持。github
二、xml: 在webservice中应用最为普遍,可是相比于json,它的数据更加冗余,由于须要成对的闭合标签。json使用了键值对的方式,不只压缩了必定的数据空间,同时也具备可读性。golang
三、protobuf : 是后起之秀,是谷歌开源的一种数据格式,适合高性能,对响应速度有要求的数据传输场景。由于profobuf是二进制数据格式,须要编码和解码。数据自己不具备可读性。所以只能反序列化以后获得真正可读的数据。相对于其它protobuf更具备优点web
1:序列化后体积相比Json和XML很小,适合网络传输编程
2:支持跨平台多语言json
3:消息格式升级和兼容性还不错浏览器
4:序列化反序列化速度很快,快于Json的处理速速网络
protoBuf的优势数据结构
Protobuf 有如 XML,不过它更小、更快、也更简单。你能够定义本身的数据结构,而后使用代码生成器生成的代码来读写这个数据结构。你甚至能够在无需从新部署程序的状况下更新数据结构。只需使用 Protobuf 对数据结构进行一次描述,便可利用各类不一样语言或从各类不一样数据流中对你的结构化数据轻松读写。它有一个很是棒的特性,即“向后”兼容性好,人们没必要破坏已部署的、依靠“老”数据格式的程序就能够对数据结构进行升级。
Protobuf 语义更清晰,无需相似 XML 解析器的东西(由于 Protobuf 编译器会将 .proto 文件编译生成对应的数据访问类以对 Protobuf 数据进行序列化、反序列化操做)。使用 Protobuf 无需学习复杂的文档对象模型,
Protobuf 的编程模式比较友好,简单易学,同时它拥有良好的文档和示例,对于喜欢简单事物的人们而言,Protobuf 比其余的技术更加有吸引力。
ProtoBuf 的不足
Protobuf 与 XML 相比也有不足之处。它功能简单,没法用来表示复杂的概念。XML 已经成为多种行业标准的编写工具,Protobuf 只是 Google 公司内部使用的工具,在通用性上还差不少。 因为文本并不适合用来描述数据结构,因此 Protobuf 也不适合用来对基于文本的标记文档(如 HTML)建模。另外,因为 XML 具备某种程度上的自解释性,它能够被人直接读取编辑,在这一点上Protobuf 不行,它以二进制的方式存储,除非你有 .proto 定义,不然你无法直接读出 Protobuf 的任何内容
Protobuf安装
安装protoBuf
#下载 protoBuf: $ git clone https://github.com/protocolbuffers/protobuf.git
#安装依赖库 $ sudo apt-get install autoconf automake libtool curl make g++ unzip libffidev -y
#安装 $ cd protobuf/ $ ./autogen.sh $ ./configure $ make $ sudo make install $ sudo ldconfig # 刷新共享库
#成功后须要使用命令测试
$ protoc –h
获取 proto包
#Go语言的proto API接口 $ go get -v -u github.com/golang/protobuf/proto
安装protoc-gen-go插件
#安装 $ go get -v -u github.com/golang/protobuf/protoc-gen-go #编译 $ cd $GOPATH/src/github.com/golang/protobuf/protoc-gen-go/ $ go build #将生成的 protoc-gen-go可执行文件,放在/bin目录下 $ sudo cp protoc-gen-go /bin/
protobuf的语法
定义一个消息类型
syntax = "proto3"; message PandaRequest { string name = 1; int32 shengao = 2; repeated int32 tizhong = 3; }
PandaRequest消息格式有3个字段,在消息中承载的数据分别对应于每个字段。其中每一个字段都有一个名字和一种类型。
文件的第一行指定了你正在使用proto3语法:若是你没有指定这个,编译器会使用proto2。这个指定语法行必须是文件的非空非注释的第一个行。
在上面的例子中,全部字段都是标量类型:两个整型(shengao和tizhong),一个string类型(name)。
Repeated 关键字表示重复的那么在go语言中用切片进行表明正如上述文件格式,在消息定义中,每一个字段都有惟一的一个标识符。
添加更多消息类型
在一个.proto文件中能够定义多个消息类型。在定义多个相关的消息的时候,这一点特别有用——例如,若是想定义与SearchResponse消息类型对应的回复消息格式的话,你能够将它添加到相同的.proto文件中
syntax = "proto3"; message PandaRequest { string name = 1; int32 shengao = 2; int32 tizhong = 3; } message PandaResponse { ... }
添加注释
向.proto文件添加注释,可使用C/C++/java/Go风格的双斜杠(//) 语法格式,如:
syntax = "proto3"; message PandaRequest { string name = 1; //姓名 int32 shengao = 2; //身高 int32 tizhong = 3; //体重 } message PandaResponse { ... }
从.proto文件生成了什么?
当用protocol buffer编译器来运行.proto文件时,编译器将生成所选择语言的代码,这些代码能够操做在.proto文件中定义的消息类型,包括获取、设置字段值,将消息序列化到一个输出流中,以及从一个输入流中解析消息。
对C++来讲,编译器会为每一个.proto文件生成一个.h文件和一个.cc文件,.proto文件中的每个消息有一个对应的类。
对Python来讲,有点不太同样——Python编译器为.proto文件中的每一个消息类型生成一个含有静态描述符的模块,,该模块与一个元类(metaclass)在运行时(runtime)被用来建立所需的Python数据访问类。
对go来讲,编译器会为每一个消息类型生成了一个.pd.go文件。
标准数据类型
一个标量消息字段能够含有一个以下的类型——该表格展现了定义于.proto文件中的类型,以及与之对应的、在自动生成的访问类中定义的类型:
默认值
当一个消息被解析的时候,若是被编码的信息不包含一个特定的元素,被解析的对象锁对应的域被设置位一个默认值,对于不一样类型指定以下:
对于strings,默认是一个空string
对于bytes,默认是一个空的bytes
对于bools,默认是false
对于数值类型,默认是0
使用其余消息类型
你能够将其余消息类型用做字段类型。例如,假设在每个PersonInfo消息中包含Person消息,此时能够在相同的.proto文件中定义一个Result消息类型,而后在PersonInfo消息中指定一个Person类型的字段
message PersonInfo { repeated Person info = 1; } message Person { string name = 1; int32 shengao = 2; repeated int32 tizhong = 3; }
使用proto2消息类型
在你的proto3消息中导入proto2的消息类型也是能够的,反之亦然,而后proto2枚举不能够直接在proto3的标识符中使用(若是仅仅在proto2消息中使用是能够的)。
嵌套类型
你能够在其余消息类型中定义、使用消息类型,在下面的例子中,Person消息就定义在PersonInfo消息内,如:
message PersonInfo { message Person { string name = 1; int32 shengao = 2; repeated int32 tizhong = 3; } repeated Person info = 1; }
若是你想在它的父消息类型的外部重用这个消息类型,你须要以PersonInfo.Person的形式使用它,如:
message PersonMessage { PersonInfo.Person info = 1; }
固然,你也能够将消息嵌套任意多层,如:
message Grandpa { // Level 0 message Father { // Level 1 message son { // Level 2 string name = 1; int32 age = 2; } } message Uncle { // Level 1 message Son { // Level 2 string name = 1; int32 age = 2; } }
定义服务(Service)
若是想要将消息类型用在RPC(远程方法调用)系统中,能够在.proto文件中定义一个RPC服务接口,protocol buffer 编译器将会根据所选择的不一样语言生成服务接口代码及存根。如,想要定义一个RPC服务并具备一个方法,该方法可以接收 SearchRequest并返回一个SearchResponse,此时能够在.proto文件中进行以下定义:
service SearchService { //rpc 服务的函数名 (传入参数)返回(返回参数) rpc Search (SearchRequest) returns (SearchResponse); }
Demo:
syntax = "proto2"; package proto.client_type; import "proto_basic.proto"; option java_package = "com.xxxx.common.proto"; option java_outer_classname = "ClientTypeProto"; message ClientTypeInfo { optional uint32 client_type_id = 1; // 类型ID optional string client_type_code = 2; // 类型标识 optional string client_type_name = 3; // 类型名称 optional string create_time = 4; // 建立时间 optional string update_time = 5; // 更新时间 } //获取终端类型列表参数 message QueryClientTypeListRequest { optional proto.basic.RequestBasic basic = 1; optional string client_type_code = 2; // 类型标识 optional string client_type_name = 3; // 类型名称 optional uint32 index = 4; // 页码 optional uint32 size = 5; // 单页长度 } //返回终端类型列表参数 message QueryClientTypeListResponse { optional proto.basic.ResponseBasic basic = 1; optional uint32 current_page = 2; // 当前页码 optional uint64 total_page = 3; // 总页码 optional uint64 total_count = 4; // 总个数 repeated ClientTypeInfo client_type_list = 5; //活动信息 }
生成proto
protoc --java_out=../java proto_upush_wx_account.proto