protobuf簡介java
protocolbuffer(如下簡稱PB)是google 的一種數據交換的格式,它獨立於語言,獨立於平臺。google 提供了多種語言的實現:java、c#、c++、go 和 python,每一種實現都包含了相應語言的編譯器以及庫文件。因爲它是一種二進制的格式,比使用 xml 進行數據交換快許多。能夠把它用於分佈式應用之間的數據通訊或者異構環境下的數據交換。做爲一種效率和兼容性都很優秀的二進制數據傳輸格式,能夠用於諸如網絡傳輸、配置文件、數據存儲等諸多領域。python
protobuf之因此小且快,就是由於使用變長的編碼規則,只保存有用的信息,節省了大量空間。
1. Base-128變長編碼
- 每一個字節使用低7位表示數字,除了最後一個字節,其餘字節的最高位都設置爲1;
- 採用Little-Endian字節序。c++
-數字1:
0000 0001c#
-數字300:
1010 1100 0000 0010
000 0010 010 1100
-> 000 0010 010 1100
-> 100101100
-> 256 + 32 + 8 + 4 = 300網絡
2. ZigZag編碼數據結構
Base-128變長編碼會去掉整數前面那些沒用的0,只保留低位的有效位,然而負數的補碼錶示有不少的1,因此protobuf先用ZigZag編碼將全部的數值映射爲無符號數,而後使用Base-128編碼,ZigZag的編碼規則以下:分佈式
1 (n << 1) ^ (n >> 31) or (n << 1) ^ (n >> 63)
負數右移後高位全變成1,再與左移一位後的值進行異或,就把高位那些無用的1所有變成0了,巧妙!ui
3. 消息格式google
每個Protocol Buffers的Message包含一系列的字段(key/value),每一個字段由字段頭(key)和字段體(value)組成,字段頭由一個變長32位整數表示,字段體由具體的數據結構和數據類型決定。
字段頭格式:編碼
1 (field_number << 3) | wire_type 2 -field_number:字段序號 3 -wire_type:字段編碼類型
4. 字段編碼類型
Type | Meaning | Used For |
0 | Varint | int32, int64, uint32, uint64, sint32, sint64, bool, enum |
1 | 64-bit | fixed64, sfixed64, double |
2 | Length-delimited | string, bytes, embedded messages(嵌套message), packed repeated fields |
3 | Start group | groups (廢棄) |
4 | End group | groups (廢棄) |
5 | 32-bit | fixed32, sfixed32, float |
1. 編碼風格
- 花括號的使用(參考上面的proto文件)
- 數據類型使用駝峯命名法:AddressBook, PhoneType
- 字段名小寫並使用下劃線鏈接:person_info, email_addr
- 枚舉量使用大寫並用下劃線鏈接:FIRST_VALUE, SECOND_VALUE
2. 適用場景
"Protocol Buffers are not designed to handle large messages."。protobuf對於1M如下的message有很高的效率,可是當message是大於1M的大塊數據時,protobuf的表現不是很好,請合理使用。
標量類型列表
proto類型 | C++類型 | 備註 |
double | double | |
float | float | |
int32 | int32 | 使用可變長編碼,編碼負數時不夠高效——若是字段可能含有負數,請使用sint32 |
int64 | int64 | 使用可變長編碼,編碼負數時不夠高效——若是字段可能含有負數,請使用sint64 |
uint32 | uint32 | 使用可變長編碼 |
uint64 | uint64 | 使用可變長編碼 |
sint32 | int32 | 使用可變長編碼,有符號的整型值,編碼時比一般的int32高效 |
sint64 | int64 | 使用可變長編碼,有符號的整型值,編碼時比一般的int64高效 |
fixed32 | uint32 | 老是4個字節,若是數值老是比老是比228大的話,這個類型會比uint32高效 |
fixed64 | uint64 | 老是8個字節,若是數值老是比老是比256大的話,這個類型會比uint64高效 |
sfixed32 | int32 | 老是4個字節 |
sfixed64 | int64 | 老是8個字節 |
bool | bool | |
string | string | 一個字符串必須是UTF-8編碼或者7-bit ASCII編碼的文本 |
bytes | string | 可能包含任意順序的字節數據 |