Protobuf 完整解析 - 公司最經常使用的數據交互協議

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
相關文章
相關標籤/搜索