一、protocal buffer 是什麼?
一種序列化機制。
什麼是序列化?
一種轉化為可儲存和傳輸物件的過程。
序列化的方式有很多,那麼proto有什麼特殊的呢?
它的英文介紹裡提到了neutral這個詞,中立,無關的。
language-neutral 跨語言:它可以應用於多種開發語言之間資料互動。
platform-neutral 跨平臺:它可以執行於多種系統平臺。
可擴充套件
序列化過程效能優越,速度快。
序列化後為二進位制資料,相對的佔用空間更小(儲存成本及傳輸成本)及一定程度的保障資料的安全性。
提供支援多語言的自動化程式碼生成工具,開發易用性。
二、下面以一個簡單地示例開始:
proto3 檔案:.proto
syntax = "proto3"; message SearchRequest { string query = 1; int32 page_number = 2; int32 result_per_page = 3; }
第一行宣告當前使用的proto3版本協議語法(proto編譯器預設使用proto2版本協議語法),宣告必須為檔案的第一行,此前不能有任何內容,包括註釋。
訊息使用“message”關鍵字定義,內部以“欄位型別 欄位名稱 = 欄位序號;”形式定義所要包含額屬性。
1、序號:
每一個欄位被賦予一個唯一的序號,起始為1且不可重複。通常考慮到向後相容的因素,不建議修改已定義的欄位序號。
需要注意的是,序號大小會影響序列化編碼的空間佔用,例如:
序號範圍[1,15]:proto使用1個位元組儲存欄位的序號及型別,適宜定義常用欄位。
序號範圍 [16,2047]:proto使用2個位元組儲存欄位的序號及型別。
...
序號可用域[1,229 - 1],其中[19000,19999]為proto保留序號範圍(編譯使用),不可使用。另外,開發方可以約定保留序號,以供擴充套件或其它特殊使用。
2、欄位約束
singular:更直觀的可以用optional來釋義,可選欄位,0個或1個,proto3中未預設約束。
repeated:列表集合欄位型別,可以包含 >=0 個欄位元素。
三、資料型別
proto3編碼型別對應不同開發語言資料型別:
.proto Type | 說明 | Java Type |
---|---|---|
double | double | |
float | float | |
int32 |
使用可變長編碼。 對於負數編碼效率較低(可以使用sint32型別儲存) |
int |
int64 |
使用可變長編碼。 對於負數編碼效率較低(可以使用sint64型別儲存) |
long |
uint32 | 使用可變長編碼。 | int[1] |
uint64 | 使用可變長編碼。 | long[1] |
sint32 | 使用可變長編碼,儲存有符號整數。尤其對負數編碼效率更高。 | int |
sint64 |
使用可變長編碼,儲存有符號整數。尤其對負數編碼效率更高。 |
long |
fixed32 | 四位元組空間佔用。儲存值>228時,儲存效率高於uint32。 | int[1] |
fixed64 |
八位元組空間佔用。儲存值>256時,儲存效率高於uint64。 |
long[1] |
sfixed32 | 四位元組空間佔用 | int |
sfixed64 | 八位元組空間佔用 | long |
bool | boolean | |
string | UTF-8編碼或者7位ASCII文字,長度不可超過232 | String |
bytes | 可以儲存任何二進位制資料,長度不可超過232 | ByteString |
四、預設值
singular 型別欄位在進行編解碼時,如果沒有進行賦值則賦予預設值。不同型別使用預設值如下:
型別 | 預設值 |
string | 空字串 |
bytes | 空byte陣列 |
bool | false |
數值型別 | 0 |
enums | 定義的列舉第一個元素(預設必須為0) |
定義的message型別 | 不賦值 |
repeated * | 空列表 |
proto3關於預設值的操作,在我們實際的使用中不免會造成一些困擾,我們需要去區分未知結果和預設值結果兩者之間的區別。例如,我們定義了bool型別欄位updated(是否已更新),預設的false所表示未更新,則會將未知是否已更新覆蓋。
對於此,通常處理的方式是引入包裝型別wrapper,使用如下:
import "google/protobuf/wrappers.proto";
wappers.proto檔案定義如下:
// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // https://developers.google.com/protocol-buffers/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Wrappers for primitive (non-message) types. These types are useful // for embedding primitives in the `google.protobuf.Any` type and for places // where we need to distinguish between the absence of a primitive // typed field and its default value. // // These wrappers have no meaningful use within repeated fields as they lack // the ability to detect presence on individual elements. // These wrappers have no meaningful use within a map or a oneof since // individual entries of a map or fields of a oneof can already detect presence. syntax = "proto3"; package google.protobuf; option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option cc_enable_arenas = true; option go_package = "github.com/golang/protobuf/ptypes/wrappers"; option java_package = "com.google.protobuf"; option java_outer_classname = "WrappersProto"; option java_multiple_files = true; option objc_class_prefix = "GPB"; // Wrapper message for `double`. // // The JSON representation for `DoubleValue` is JSON number. message DoubleValue { // The double value. double value = 1; } // Wrapper message for `float`. // // The JSON representation for `FloatValue` is JSON number. message FloatValue { // The float value. float value = 1; } // Wrapper message for `int64`. // // The JSON representation for `Int64Value` is JSON string. message Int64Value { // The int64 value. int64 value = 1; } // Wrapper message for `uint64`. // // The JSON representation for `UInt64Value` is JSON string. message UInt64Value { // The uint64 value. uint64 value = 1; } // Wrapper message for `int32`. // // The JSON representation for `Int32Value` is JSON number. message Int32Value { // The int32 value. int32 value = 1; } // Wrapper message for `uint32`. // // The JSON representation for `UInt32Value` is JSON number. message UInt32Value { // The uint32 value. uint32 value = 1; } // Wrapper message for `bool`. // // The JSON representation for `BoolValue` is JSON `true` and `false`. message BoolValue { // The bool value. bool value = 1; } // Wrapper message for `string`. // // The JSON representation for `StringValue` is JSON string. message StringValue { // The string value. string value = 1; } // Wrapper message for `bytes`. // // The JSON representation for `BytesValue` is JSON string. message BytesValue { // The bytes value. bytes value = 1; }
五、列舉
enum 列舉物件 {
UNKOWN = 0; //預設值機制使用(首先必須有一個列舉值為0的列舉例項,其次相容proto2中使用第一個變數為預設值的機制)
列舉例項 = 列舉值;
... ...
}
六、定義更新
1、不可修改已定義的欄位序號。
2、可以刪除已定義的欄位,但是其序號不可在被使用。
3、int32, uint32, int64, uint64及bool是相互相容的,只不過轉換過程會產生值域變更。
4、sint32 和 sint64 是相互相容的。
5、byte3儲存值為有效UTF-8編碼內容時與string相互相容。
七、未知欄位
未能對應解析的欄位會儲存於未知欄位中。此機制在proto3中最初拋棄,v3.5版本重新引入。
八、Map 型別
定義如下:
map<key_type, value_type> map_field = N。
key_type:任何整形或者string型別。
value_type:可以為除了Map型別外的任何型別。