Protocol Buffer是google自定義的數據傳輸協議,目前已經被普遍用於服務端和客戶端間的數據傳輸,清晰理解Protocol Buffer的使用以及語法就顯得很重要,本文對Protocol Buffer語法分析是基於proto3.java
目前使用最普遍的數據傳輸協議爲JSON,JSON是一種輕量級的數據交換格式並且層次和結構比較簡單和清晰,這裏主要對比一下Protocol Buffer和JSON的對比,給出優點和劣勢:python
優點安全
劣勢 ruby
實際數據對比bash
Protocol Buffer的使用流程整體能夠分爲三步,以下圖所示: 工具
在使用Protocol Buffer以前須要清楚理解其語法定義,本文對Protocol Buffer的語法解析是基於proto3版本優化
首先建立一個.proto文件,而且在文件中聲明以下內容:ui
syntax = "proto3";
message SearchRequest {
string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
}
複製代碼
其中第一行標明當前proto使用的版本爲proto3,後面定義了一個結構體SearchRequest,結構體中共3個屬性。google
在整個proto文件中分爲基本類型和結構類型,其中結構類型主要爲:編碼
下面分別介紹一下不一樣結構的做用及規定:
message表示一個結構,相似於java中類,一個proto文件中能夠聲明多個message結構:
message SearchRequest {
string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
}
message SearchResponse {
...
}
複製代碼
message能夠引用不一樣proto文件中的message,只要在proto文件中的最上面聲明import便可,以下所示:
import "myproject/other_protos.proto";
複製代碼
meesage 可使用extend來繼承另一個message,而且使用其中的屬性,這裏注意一下因爲每一個message中須要對屬性進行編號,在繼承的時候須要注意編號,防止重複使用
enum使用很簡單,直接在message中聲明enum結構體而且將屬性聲明爲對應的enum便可:
message SearchRequest {
string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
enum Corpus {
UNIVERSAL = 0;
WEB = 1;
IMAGES = 2;
LOCAL = 3;
NEWS = 4;
PRODUCTS = 5;
VIDEO = 6;
}
Corpus corpus = 4;
}
複製代碼
上面代碼中Corpus就是一個enum
在proto3中,enum第一個值必須爲0,主要是爲了和基礎類型的默認值保持一致
map是proto3新加的,使用也很簡單:
map<key_type, value_type> map_field = N;
複製代碼
在proto2中可使用repeated和message結構自定義map,以下所示
message Person {
string key = 1;
string value = 2;
}
repeated Person person = 4;
複製代碼
proto中基礎類型有不少,下面給出不一樣的基礎類型對應的java中的類型,及其特色:
proto 類型 | java類型 | 備註 |
---|---|---|
double | double | |
float | float | |
int32 | int | 可變長度編碼,若是有負值,可使用sint32修飾 |
int64 | long | 可變長度編碼,若是有負值,可使用sint64修飾 |
uint32 | int | 可變長度編碼 |
uint64 | int | 可變長度編碼 |
sint32 | int | 可變長度編碼,用來表示負值時效率比int32更高 |
sint64 | long | 可變長度編碼,用來表示負值時效率比int64更高 |
fixed32 | int | 4個字節,當數值>2^28時效率比uint32高 |
fixed64 | long | 8個字節,當數值>2^56時效率比uint64高 |
sfixed32 | int | 4個字節 |
fixed64 | long | 8個字節 |
bool | boolean | |
string | String | UTF-8 encoded or 7-bit ASCII text, 長度不能超過2^32 |
bytes | ByteString | 長度不超過2^32,任意順序的字節數據 |
其中部分基本類型修飾符長度不肯定,主要採用了可變長度編碼,這也是爲何Prorocol Buffer序列化後的數據字節更少,這個後面原理篇會介紹。
基礎類型的默認值以下:
在proto3中,repeated的標量域默認狀況下使用packed,也就是可變長度編碼
先看下一個簡單的proto文件:
message SearchRequest {
string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
enum Corpus {
UNIVERSAL = 0;
WEB = 1;
IMAGES = 2;
LOCAL = 3;
NEWS = 4;
PRODUCTS = 5;
VIDEO = 6;
}
Corpus corpus = 4;
}
複製代碼
message SearchRequest 中的全部字段都聲明瞭字段編號,這裏須要注意:
平常開發過程當中,因爲需求的變動,每每須要增長字段,這就涉及到字段的擴充,字段擴充須要達到一個目的:兼容
因此Protocol Buffer在字段擴充中定義了以下規則:
只要記住上述規則,就能完成字段擴充且老版本也能兼容
當proto文件編寫後,就須要生成對應語言的源文件,生成操做以下:
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 --objc_out=DST_DIR --csharp_out=DST_DIR path/to/file.proto
複製代碼
Protocol Buffer 更快更小的主要緣由以下:
以上基於proto3講述了Protocol Buffer的語法和使用流程,其中簡單說明了Protocol Buffer爲何更快,更小,後面會詳細介紹其原理