Protocol Buffers學習(1):定義一個訊息

大大怪發表於2017-05-08

首先讓我們來看一個非常簡單的例子。 假設你想定義一個訊息格式,用來表示搜尋請求,其中每個搜尋請求都有三項:

  • 一個查詢字串
  • 你感興趣的特定結果頁
  • 以及每個頁面的結果數

下邊是用來定義訊息型別的.proto檔案

syntax = "proto3";

message SearchRequest {
  string query = 1;
  int32 page_number = 2;
  int32 result_per_page = 3;
}複製程式碼
  • 第一行表示使用的protocol版本是3,如果你不寫這一條,protobuf會認為你使用的是protobuf2,而且,這行必須是第一行,前邊也不能有註釋
  • SearchRequest這條訊息定義了三個欄位(名稱/值對),每條訊息都要包含這三個欄位,每個欄位都有一個名稱和一個型別

欄位型別說明

在上面的例子中,所有欄位都是基本型別:兩個整數(page_number和result_per_page)和一個字串(query)。這些欄位也可以是複合型別,包括列舉和其他訊息型別

欄位標籤

訊息定義中的每個欄位都有唯一的編號標籤,這些標記用於以訊息二進位制格式標識欄位,訊息開始使用之後就不能修改

注意

  • 值在1到15範圍內的標籤需要一個位元組進行編碼,包括標識號和欄位型別
  • 在16到2047範圍內的標籤佔用兩個位元組。

因此,你應該為非常頻繁出現的訊息元素保留標籤1到15。記住要為可能在將來新增的頻繁出現的元素留出一些空間。

最小的標籤是1,最大的標籤是536870911,即2^29 - 1,並且19000 - 19999protobuf系統保留標籤,不能使用這幾個

欄位規則說明

一共有兩種型別

  • singular: 一個符合規則的訊息應該具備零個或者一個該欄位
  • repeated: 一個符合規則的訊息可以有零個或者任意個該欄位,並且保留重複的順序,在proto3中,基本型別的重複欄位預設壓縮編碼

新增更多訊息型別

可以在單個.proto檔案中新增多個訊息型別,例如

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

message SearchResponse {
 ...
}複製程式碼

新增註釋

可以使用//.proto檔案新增註釋。例如

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.
}複製程式碼

保留欄位(欄位修改或者刪除解決辦法)

當訊息型別更新或者刪除時,這些被修改的欄位的標籤如果繼續使用,會造成資料不正確的問題,這時需要把這些標籤保留起來,防止跟舊版本的資料發生衝突。
(當使用JSON序列化時,欄位名稱也有可能存在這個問題),通俗來說,就相當於已經上線了使用A介面的一個APP,這個時候服務端如果想修改A介面的資料格式,只能新增一個介面,並且肯定不能使用A介面的地址

案例

message Foo {
  reserved 2, 15, 9 to 11;
  reserved "foo", "bar";
}複製程式碼

這就表示 2,15,9,10,11,"foo", "bar"都不能重複使用了

.proto檔案會生成什麼?

當編譯.proto檔案時,編譯器將根據你選擇的語言生成對應程式碼,你需要使用檔案中描述的訊息型別,包括獲取和設定欄位值,將訊息序列化 輸出流,以及解析來自輸入流的訊息

  • 對於PHP,編譯器會為每個訊息生成一個類,用來描述該訊息
  • 對於C ++,編譯器從每個.proto生成.h.cc檔案,併為您的檔案中描述的每個訊息型別指定一個類
  • 對於Java,編譯器會為每個訊息型別生成一個帶有類的.java檔案,以及用於建立訊息類例項的特殊Builder類
  • Python有點不同, Python編譯器生成一個模組,其中包含.proto中每個訊息型別的靜態描述符,然後使用元類在執行時建立必要的Python資料訪問類
  • 對於Go,編譯器會為檔案中的每種訊息型別生成一個具有型別的.pb.go檔案
  • 對於Ruby,編譯器生成一個包含訊息型別的包含Ruby模組的.rb檔案
  • 對於JavaNano,編譯器輸出與Java類似,但沒有Builder類
  • 對於Objective-C,編譯器從每個.proto生成一個pbobjc.hpbobjc.m檔案,在檔案中描述的每個訊息型別都有一個類
  • 對於C#,編譯器從每個.proto生成一個.cs檔案,在檔案中描述的每個訊息型別都有一個類

相關文章