1. 程式人生 > >gRPC proto3語法指南

gRPC proto3語法指南

本文將描述如何使用protocol buffer 語言構造你的protocol buffer資料,包括.proto檔案語法規則,以及如何由.proto檔案生成資料訪問類。本文涵蓋了proto3版本的協議語言:想了解proto2的語法,檢視 Proto2 語言指南.

這是一個參考指南——給出了一步一步的操作的示例,示例使用了本文中描述的很多特性,這裡有適合你所選語言的教程

定義一個訊息型別

首先讓我們來看一個非常簡單的例子。假定我們有這樣的需求,我們要定義一個搜尋請求訊息,每個訊息都包含一個查詢字串,和你感興趣的特定頁面編號,以及每個頁面的命中個數。

syntax = "proto3"
; message SearchRequest { string query = 1; int32 page_number = 2; int32 result_per_page = 3; }
  1. 檔案的第一行指定了你使用的是proto3的語法:如果你不指定,protocol buffer 編譯器就會認為你使用的是proto2的語法。這個語句必須出現在.proto檔案的非空非註釋的第一行。
  2. 我們看到,搜尋請求訊息結構中定義指定了三個欄位(name/value pairs)。每個欄位都有一個名稱和型別。

指定欄位型別

在上述例子中,所有的欄位都是值型別:兩個整形(page_number and result_per_page) 和一個字串 (query)。然而,你也可以指定你的欄位的組合型別,包括列舉和其他訊息型別。

分配標識——tag

如你所見,訊息中的每個欄位都有一個唯一的數字標識。這些標識用來在訊息的二進位制格式中識別你的欄位,並且,一旦你的訊息投入使用,這些標識就不應該再被修改。

注意,標識是由1到15使用一個位元組來編碼,包括標識數字和欄位型別(你可以在Protocol Buffer 編碼中檢視更多詳細)。

標識16到2047佔用兩個位元組。所以你應該保留1到15,用作出現最頻繁的訊息型別的標識。記得為將來會繼續增加並可能頻繁出現的元素留一點兒標識區間,也就是說,不要一下子把1—15全部用完,為將來留一點兒哦。

你可以指定的最小的標識數字是1,最大是228,或者536,870,911。你也不能使用19000 到 19999之間的數字(FieldDescriptor::kFirstReservedNumber through FieldDescriptor::kLastReservedNumber),因為它們被Protocol Buffers保留使用——如果你在自己的.proto檔案中使用了一個保留數字,protocol buffer 編譯器將會提示。同樣的,你不能使用任何之前保留的標識。

指定欄位規則

訊息欄位可以是下邊中的一種:

  1. singular(單個): 符合語法規則的訊息包含零個或者一個這樣的欄位(最多一個)。

  2. repeated(重複): 一個欄位在合法的訊息中可以重複出現一定次數(包括零次)。重複出現的值的次序將被保留。在proto3中,重複出現的值型別欄位預設採用壓縮編碼。你可以在這裡找到更多關於壓縮編碼的東西: Protocol Buffer Encoding

新增更多訊息型別

多個訊息型別可以定義在一個.proto檔案中。這個在你定義多個關聯的訊息的時候非常有用,——這樣,舉個例子吧,如果你想定義你的搜尋訊息型別的響應訊息格式,你可以在同一個.proto檔案中新增如下的內容:

message SearchRequest {
  string query = 1;
  int32 page_number = 2;
  int32 result_per_page = 3;
}

message SearchResponse {
 ...
}

添加註釋

在你的 .proto 檔案中添加註釋, 使用C/C++-風格的 // 語法,像下邊這樣:

message SearchRequest {
  string query = 1;
  int32 page_number = 2;  // Which page number do we want?
  int32 result_per_page = 3;  // Number of results to return per page.
}

保留欄位

如果你通過刪除整個欄位更新了訊息型別,或者將整個欄位其註釋掉,未來使用者在編寫新的型別的時候能夠複用這些註釋掉的標識數字。然而,這會引起一些嚴重的問題,如果他們後來載入了同一個.proto的舊版,包括資料損壞,安全隱私bug等等。一個確保這種問題不會發生的辦法是,保留你要刪除的欄位的標識。Protocol buffer 編譯器將會提示以後使用者使用這些保留的欄位標識。

message Foo {
  reserved 2, 15, 9 to 11;
  reserved "foo", "bar";
}

注意,你不要混淆同一個保留語句中的欄位名稱和標識。

你的.proto編譯之後會生成什麼?

當你執行對一個.proto檔案的編譯之後,編譯器會為你選擇的語言生成程式碼。你在檔案中描述的訊息型別,包括獲取和設定欄位的值,序列化你的訊息到一個輸出流,以及從一個輸入流中轉換出你的訊息。

  1. 對於C++,編譯器會為每個.proto檔案生成一個.h 和一個.cc的檔案,為每一個給出的訊息型別生成一個類。
  2. 對於Java,編譯器會生成一個java檔案,其中為每一個訊息型別生成一個類,還有特殊的用來建立這些訊息類例項的Builder類,
  3. Python有一點小不同——Python編譯器生成一個模組兒,其中為每一個訊息型別生成一個靜態的描述器,在執行時,和一個metaclass一起使用來建立必要的Python資料訪問類。
  4. 對於Go,編譯器為每個訊息型別生成一個.pb.go檔案。
    ……

值型別

值型別的訊息欄位可以是一下型別中的一種——這個表格展示了可以在.proto檔案中使用的型別,以及自動生成的相應語言的型別:

.proto Type 說明 C++ Type Java Type Python Type[2] Go Type
double double double float float64
float float float float float32
int32 使用可變長度編碼。對負數進行編碼時比較低效 – 如果你的欄位要使用負數值,請使用sint32來代替。 int32 int int int
int64 使用可變長度編碼。對負數進行編碼時比較低效 – 如果你的欄位要使用負數值,請使用sint64來代替。 int64 long int/long[3] int64
uint32 使用可變長度編碼 uint32 int[1] int/long[3] uint32
uint64 使用可變長度編碼 uint64 long[1] int/long[3] uint64