proto3 協議指引


一、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類型外的任何類型。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM