gRPC推薦使用proto3,本節只介紹經常使用語法,更多高級使用姿式請參考官方文檔java
一個message類型定義描述了一個請求或相應的消息格式,能夠包含多種類型字段。例如定義一個搜索請求的消息格式,每一個請求包含查詢字符串、頁碼、每頁數目。python
syntax = "proto3"; message SearchRequest { string query = 1; // 查詢字符串 int32 page_number = 2; // 頁碼 int32 result_per_page = 3; // 每頁條數 }
首行聲明使用的protobuf版本爲proto3git
SearchRequest 定義了三個字段,每一個字段聲明以分號結尾,可以使用雙斜線//
添加註釋。github
全部的字段須要前置聲明數據類型,上面的示例指定了兩個數值類型和一個字符串類型。除了基本的標量類型還有複合類型,如枚舉、其它message類型等。golang
能夠看到,消息的定義中,每一個字段都有一個惟一的數值型標識符。這些標識符用於標識字段在消息中的二進制格式,使用中的類型不該該隨意改動。須要注意的是,[1-15]內的標識在編碼時只佔用一個字節,包含標識符和字段類型。[16-2047]之間的標識符佔用2個字節。建議爲頻繁出現的消息元素使用[1-15]間的標識符。若是考慮到之後可能或擴展頻繁元素,能夠預留一些標識符。objective-c
最小的標識符能夠從1開始,最大到229 - 1,或536,870,911。不可使用[19000-19999]之間的標識符, Protobuf協議實現中預留了這些標識符。在.proto文件中使用這些預留標識號,編譯時就會報錯。數組
repeated:標識字段能夠重複任意次,相似數組ruby
proto3不支持proto2中的required和optionalide
一個.proto文件中能夠定義多個消息類型,通常用於同時定義多個相關的消息,例如在同一個.proto文件中同時定義搜索請求和響應消息:ui
syntax = "proto3"; // SearchRequest 搜索請求 message SearchRequest { string query = 1; // 查詢字符串 int32 page_number = 2; // 頁碼 int32 result_per_page = 3; // 每頁條數 } // SearchResponse 搜索響應 message SearchResponse { ... }
向.proto文件中添加註釋,支持C風格雙斜線//
單行註釋
可使用reserved關鍵字指定保留字段和保留標識符:
message Foo { reserved 2, 15, 9 to 11; reserved "foo", "bar"; }
注意,不能在一個reserved聲明中混合字段名和標識符。
當使用protocol buffer編譯器運行.proto
文件時,編譯器將生成所選語言的代碼,用於使用在.proto
文件中定義的消息類型、服務接口約定等。不一樣語言生成的代碼格式不一樣:
C++: 每一個.proto
文件生成一個.h
文件和一個.cc
文件,每一個消息類型對應一個類
Java: 生成一個.java
文件,一樣每一個消息對應一個類,同時還有一個特殊的Builder
類用於建立消息接口
Python: 姿式不太同樣,每一個.proto
文件中的消息類型生成一個含有靜態描述符的模塊,該模塊與一個元類metaclass在運行時建立須要的Python數據訪問類
Go: 生成一個.pb.go
文件,每一個消息類型對應一個結構體
Ruby: 生成一個.rb
文件的Ruby模塊,包含全部消息類型
JavaNano: 相似Java,但不包含Builder
類
Objective-C: 每一個.proto
文件生成一個pbobjc.h
和一個pbobjc.m
文件
C#: 生成.cs
文件包含,每一個消息類型對應一個類
各類語言的更多的使用方法請參考官方API文檔
這裏直接引用官方文檔的描述:
.proto | C++ | Java | Python | Go | Ruby | C# |
---|---|---|---|---|---|---|
double | double | double | float | float64 | Float | double |
float | float | float | float | float32 | Float | float |
int32 | int32 | int | int | int32 | Fixnum or Bignum | int |
int64 | int64 | long | ing/long[3] | int64 | Bignum | long |
uint32 | uint32 | int[1] | int/long[3] | uint32 | Fixnum or Bignum | uint |
uint64 | uint64 | long[1] | int/long[3] | uint64 | Bignum | ulong |
sint32 | int32 | int | intj | int32 | Fixnum or Bignum | int |
sint64 | int64 | long | int/long[3] | int64 | Bignum | long |
fixed32 | uint32 | int[1] | int | uint32 | Fixnum or Bignum | uint |
fixed64 | uint64 | long[1] | int/long[3] | uint64 | Bignum | ulong |
sfixed32 | int32 | int | int | int32 | Fixnum or Bignum | int |
sfixed64 | int64 | long | int/long[3] | int64 | Bignum | long |
bool | bool | boolean | boolean | bool | TrueClass/FalseClass | bool |
string | string | String | str/unicode[4] | string | String(UTF-8) | string |
bytes | string | ByteString | str | []byte | String(ASCII-8BIT) | ByteString |
關於這些類型在序列化時的編碼規則請參考 Protocol Buffer Encoding.
[1] java
[2] all
[3] 64
[4] Python
字符串類型默認爲空字符串
字節類型默認爲空字節
布爾類型默認false
數值類型默認爲0值
enums類型默認爲第一個定義的枚舉值,必須是0
針對不一樣語言的默認值的具體行爲參考 generated code guide
message SearchResponse { repeated Result results = 1; } message Result { string url = 1; string title = 2; repeated string snippets = 3; }
message支持嵌套使用,做爲另外一message中的字段類型
可使用import語句導入使用其它描述文件中聲明的類型
import "others.proto";
protocol buffer編譯器會在 -I / --proto_path
參數指定的目錄中查找導入的文件,若是沒有指定該參數,默認在當前目錄中查找。
message SearchResponse { message Result { string url = 1; string title = 2; repeated string snippets = 3; } repeated Result results = 1; }
內部聲明的message類型名稱只可在內部直接使用,在外部引用須要前置父級message名稱,如Parent.Type
:
message SomeOtherMessage { SearchResponse.Result result = 1; }
支持多層嵌套:
message Outer { // Level 0 message MiddleAA { // Level 1 message Inner { // Level 2 int64 ival = 1; bool booly = 2; } } message MiddleBB { // Level 1 message Inner { // Level 2 int32 ival = 1; bool booly = 2; } } }
proto3支持map類型聲明:
map<key_type, value_type> map_field = N; message Project {...} map<string, Project> projects = 1;
鍵、值類型能夠是內置的標量類型,也能夠是自定義message類型
字段不支持repeated
屬性
不要依賴map類型的字段順序
在.proto
文件中使用package
聲明包名,避免命名衝突。
syntax = "proto3"; package foo.bar; message Open {...}
在其餘的消息格式定義中可使用包名+消息名的方式來使用類型,如:
message Foo { ... foo.bar.Open open = 1; ... }
在不一樣的語言中,包名定義對編譯後生成的代碼的影響不一樣:
C++ 中:對應C++命名空間,例如Open
會在命名空間foo::bar
中
Java 中:package會做爲Java包名,除非指定了option jave_package
選項
Python 中:package被忽略
Go 中:默認使用package名做爲包名,除非指定了option go_package
選項
JavaNano 中:同Java
C# 中:package會轉換爲駝峯式命名空間,如Foo.Bar
,除非指定了option csharp_namespace
選項
若是想要將消息類型用在RPC(遠程方法調用)系統中,能夠在.proto
文件中定義一個RPC服務接口,protocol buffer編譯器會根據所選擇的不一樣語言生成服務接口代碼。例如,想要定義一個RPC服務並具備一個方法,該方法接收SearchRequest
並返回一個SearchResponse
,此時能夠在.proto
文件中進行以下定義:
service SearchService { rpc Search (SearchRequest) returns (SearchResponse) {} }
生成的接口代碼做爲客戶端與服務端的約定,服務端必須實現定義的全部接口方法,客戶端直接調用同名方法向服務端發起請求。比較蛋疼的是即使業務上不須要參數也必須指定一個請求消息,通常會定義一個空message。
在定義.proto文件時能夠標註一系列的options。Options並不改變整個文件聲明的含義,但卻能夠影響特定環境下處理方式。完整的可用選項能夠查看google/protobuf/descriptor.proto
.
一些選項是文件級別的,意味着它能夠做用於頂層做用域,不包含在任何消息內部、enum或服務定義中。一些選項是消息級別的,能夠用在消息定義的內部。固然有些選項能夠做用在字段、enum類型、enum值、服務類型及服務方法中。可是到目前爲止,並無一種有效的選項能做用於這些類型。
一下是一些經常使用的選擇:
java_package
(file option):指定生成java類所在的包,若是在.proto文件中沒有明確的聲明java_package,會使用默認包名。不須要生成java代碼時不起做用
java_outer_classname
(file option):指定生成Java類的名稱,若是在.proto文件中沒有明確聲明java_outer_classname,生成的class名稱將會根據.proto文件的名稱採用駝峯式的命名方式進行生成。如(foo_bar.proto生成的java類名爲FooBar.java),不須要生成java代碼時不起任何做用
objc_class_prefix
(file option): 指定Objective-C類前綴,會前置在全部類和枚舉類型名以前。沒有默認值,應該使用3-5個大寫字母。注意全部2個字母的前綴是Apple保留的。
.proto
作爲文件後綴,除結構定義外的語句以分號結尾結構定義包括:message、service、enum
rpc方法定義結尾的分號無關緊要
message SongServerRequest { required string song_name = 1; }
enum Foo { FIRST_VALUE = 1; SECOND_VALUE = 2; }
message對應golang中的struct,編譯生成go代碼後,字段名會轉換爲駝峯式
經過定義好的.proto
文件生成Java, Python, C++, Go, Ruby, JavaNano, Objective-C, or C# 代碼,須要安裝編譯器protoc
。參考Github項目google/protobuf安裝編譯器.Go語言須要同時安裝一個特殊的插件:golang/protobuf。
運行命令:
protoc --proto_path=IMPORT_PATH --cpp_out=DST_DIR --java_out=DST_DIR --python_out=DST_DIR --go_out=DST_DIR --ruby_out=DST_DIR --javanano_out=DST_DIR --objc_out=DST_DIR --csharp_out=DST_DIR path/to/file.proto
這裏只作參考就好,具體語言的編譯實例請參考詳細文檔,其中,Go語言的使用姿式會在其它章節詳細說明:
吐槽: 照着官方文檔一步步操做不必定成功哦!
Any 消息類型
Oneof 字段
自定義Options
這些用法在實踐中不多使用,這裏不作詳細介紹,尤爲自定義選項設計高級用法,有須要請參考官方文檔。