Protobuf 語法

1. 基本規範

  • 文件以.proto做爲文件後綴,除結構定義以外的語句以分號結尾
  • 結構定義能夠包含:message、service、enum
  • message 定義結構體,service 定義方法
  • rpc方法定義結尾的分號無關緊要
  • Message 命名採用駝峯命名方式,字段命名採用小寫字母加下劃線分隔方式
  • Enums 類型名採用駝峯命名方式,字段命名採用大寫字母加下劃線分隔方式
  • Service與rpc方法名統一採用駝峯式命名
enum GenderType {
    SECRET = 0;
    FEMALE = 1;
    MALE = 2;
}

// 人
message Person {
    int64 id = 1;
    string name = 2;
    GenderType gender = 3;
    string number = 4;
}
複製代碼

2. 字段規則

字段格式

字段格式:限定修飾符 | 數據類型 | 字段名稱 | = | 字段編碼值 | [字段默認值]java

限定修飾符

限定修飾符包含:required、optional、repeated數組

  • Required:表示是一個必須字段
  • Optional:表示一個可選字段。對於接收方,若是可以識別可選字段就進行相應的處理,若是沒法識別,則忽略該字段
  • Repeated:表示該字段能夠包含0-N個元素。其中特性和optional同樣,可是每一次能夠包含多個值。能夠看作是在傳遞一個數組的值

數據類型

Protobuf定義了一套基本數據類型:markdown

Protobuf 數據類型 描述 打包
bool 布爾類型 1字節
double 64位浮點數 N
float 32位浮點數 N
int32 32位整數 N
uint32 無符號32位整數 N
int64 64位整數 N
uint64 64位無符號整數 N
$int32 32位整數,處理負數效率更高 N
$int64 64位整數,處理負數效率更高 N
fixed32 32位無符號整數 4
fixed64 64位無符號整數 8
$fixed32 32位整數,能以更高的效率處理負數 4
$fixed64 64位整數,能以更高的效率處理負數 8
string 只能處理ASCII字符 N
bytes 用於處理多字節的語言字符,如中文 N
enum 能夠包含一個用戶自定義的枚舉類型uint32 N(uiint32)
message 能夠包含一個用戶自定義的消息類型 N
  • N 表示打包的字節並非固定,而是根據數據的大小或者長度
  • 關於fiex32 和 int32的區別:fixed32的打包效率比int32的效率高,可是使用的空間通常比int32多

字段名稱

  • 字段名稱的命名與C、Java等語言的變量命名方式幾乎是相同的
  • protobuf 建議字段的命名採用如下劃線分隔的駝峯式

字段編碼值

  • 有了該值,通訊雙方纔能互相識別對方的字段,相同的編碼值,其限定修飾符和數據類型必須相同,編碼值的取值範圍爲:1 ~ 2^32 (4294967296)
  • 其中 1 ~ 15的編碼時間和空間效率都是最高的,編碼值越大,其編碼的時間和空間效率就越低
  • 1900 ~ 2000 編碼值爲 Google protobuf 系統內部保留值,建議不要在項目中使用

字段默認值

  • 當在傳遞數據時,對於required數據類型,若是用戶沒有設置值,則使用默認值傳遞到對端

3. service 如何定義

  • 若是想要將消息類型用在 RPC 系統中,能夠在 .proto文件中定義一個 RPC 服務接口,protocol buffer 編譯器會根據所選擇的不一樣語言生成服務接口代碼
  • 生成的接口代碼做爲客戶端與服務端的約定,服務端必須實現定義的全部接口方法,客戶端直接調用同名方法向服務端發起請求(即使業務上不須要參數也必須指定一個請求消息,通常會定義一個空message)

好比,想要定義一個 RPC 服務並具備一個方法,該方法接收 SearchRequest 並返回一個 SearchResponse,此時能夠在.proto文件中進行以下定義:ui

service SearchService {
	rpc Search(SearchRequest) returns (SearchResponse) {} } 複製代碼

4. Message 如何定義

  • 一個 message 類型定義描述了一個請求或響應的消息格式,能夠包含多種類型字段
  • 字段名用小寫,轉爲 go 文件後自動變爲大寫,message 就至關於結構體

5. 添加更多 Message 類型

一個 .proto 文件中能夠定義多個消息類型,通常用於同時定義多個相關的消息,例如在同一個 .proto 文件中同時定義搜索請求和響應消息:編碼

syntax = "proto3" // 聲明使用的 protobuf 版本

message SearchRequest {
	string query = 1; // 查詢字符串
	int32 page_number = 2;
	int32 result_per_page = 3;
}

message SearchResponse {

}
複製代碼

6. 如何使用其餘 Message

message 支持嵌套使用,做爲另外一個 message 中的字段類型url

message SearchResponse {
	repeated Result results = 1;
}

message Result {
	string url = 1;
	string title = 2;
	repeated string snippets = 3;
}
複製代碼

7. Message 嵌套的使用

支持嵌套消息,消息能夠包含另外一個消息做爲字段。也能夠在消息內定義一個新的消息。spa

內部聲明的 message 類型名稱只可在內部直接使用:code

message SearchResponse {
	message Result {
		string url = 1;
		string title = 2;
		repeated string snippets = 3;
	}
	repeated Result results = 1;
}
複製代碼

另外,還能夠多層嵌套:orm

message Outer {
	message A {
		message Inner {
			int64 ival = 1;
			bool booly = 2;
		}
	}
	message B {
		message Inner {
			int64 ival = 1;
			bool booly = 2;
		}
	}
}
複製代碼

8. proto3 的 Map 類型

  • proto3 支持 map 類型聲明接口

  • 鍵、值類型能夠是內置類型,也能夠是自定義 message 類型

  • 字段不支持 repeated 屬性

    map<key_type, value_type>map_field = N;
    
    message Project {...}
    map<string, Project>projects = 1;
    複製代碼

9. .proto 文件編譯

  • 經過定義好的 .proto 文件生成 Java、Python、Go、Ruby等代碼,須要安裝編譯器 protoc
  • 使用 protobuf 編譯器不一樣的語言生成的代碼格式不一樣:
    • Go:生成一個 .pb.go 文件,每一個消息類型對應一個結構體
    • Java:生成一個 java 文件,每一個消息對應一個類,同時還有一個特殊的 Builder 類用於建立消息接口
    • ......

10. Import 導入定義

  • 能夠使用 import 語句導入使用其它描述文件中聲明的類型

  • protobuf 接口文件能夠經過 import 導入須要的文件,例如: import "example.proto"

  • protobuf 編譯器會在 -I/ --proto_path 參數指定的目錄中查找導入的文件,若是沒有指定該參數,默認在當前目錄中查找

11. 包的使用

在 proto 文件中使用 package 聲明包名,避免命名衝突:

syntax = "proto3"
package foo.bar
message Open {...}
複製代碼

在其餘的消息格式定義中能夠使用包名 + 消息名的方式來使用類型,如:

message Foo {
	...
	foo.bar.Open open = 1;
	...
}
複製代碼

在不一樣的語言中,包名定義對編譯後生成的代碼影響不一樣:

  • Go:默認使用 package 名做爲包名,除非指定了 option go_package 選項
  • Java:默認使用 package 名做爲包名,除非指定了 option go_package 選項
  • Python:package 被忽略
相關文章
相關標籤/搜索