protobuf資料型別
四、限定符(required/optional/repeated)的基本規則。
1. 在每個訊息中必須至少留有一個required型別的欄位。
2. 每個訊息中可以包含0個或多個optional型別的欄位。
3. repeated表示的欄位可以包含0個或多個資料。需要說明的是,這一點有別於C++/Java中的陣列,因為後兩者中的陣列必須包含至少一個元素。
4. 如果打算在原有訊息協議中新增新的欄位,同時還要保證老版本的程式能夠正常讀取或寫入,那麼對於新新增的欄位必須是optional或repeated。道理非常簡單,老版本程式無法讀取或寫入新增的required限定符的欄位。
五、型別對照表。
.proto Type | Notes | C++ Type | Java Type |
double | double | double | |
float | float | float | |
int32 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead. | int32 | int |
int64 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead. | int64 | long |
uint32 | Uses variable-length encoding. | uint32 | int |
uint64 | Uses variable-length encoding. | uint64 | long |
sint32 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s. | int32 | int |
sint64 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s. | int64 | long |
fixed32 | Always four bytes. More efficient than uint32 if values are often greater than 228. | uint32 | int |
fixed64 | Always eight bytes. More efficient than uint64 if values are often greater than 256. | uint64 | long |
sfixed32 | Always four bytes. | int32 | int |
sfixed64 | Always eight bytes. | int64 | long |
bool | bool | boolean | |
string | A string must always contain UTF-8 encoded or 7-bit ASCII text. | string | String |
bytes | May contain any arbitrary sequence of bytes. | string | ByteString |
規則結構型別列表:
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, packed repeated fields |
3 |
Start group |
groups (deprecated) |
4 |
End group |
groups (deprecated) |
5 |
32-bit |
fixed32, sfixed32, float |
Varint型別[動態整型](type為0)
1. 每個位元組第一位表示有無後續位元組,有為1,無為0, (雙位元組,低位元組在前,高位元組在後.)
2. 剩餘7位倒序合併
舉例: 300 的二進位制為 10 0101100
第一位:1(有後續) + 0101100
第二位:0(無後續) + 0000010
最終結果: 101011000000010
Message 結構
- 鍵值型結構(Key-Value)
- 第一部分為Key值,Varint 結構
- Key值的後三位表示規則型別的Type值,其他部分和為型別的數字編號
- 後面緊跟value,value的值依據規則型別不同而不同
舉例: required int32 a = 1; 當a值為150時
Key:0000 1000,型別為000,數字編號為0001
Value(Varint型別):1001 0110 0000 0001
值解碼: 000 0001 + 001 0110 = 10010110 = 150
sint32和sint64型別的編碼(ZigZag)
對於sint32和sint64型別的編碼採用ZigZag編碼方式,最後一位表示正負情況,即如下:
原始值 |
編碼為 |
0 |
0 |
-1 |
1 |
1 |
2 |
-2 |
3 |
2147483647 |
4294967294 |
-2147483648 |
4294967295 |
解碼方式為:
- 對sint32 -> (n << 1) ^ (n >> 31)
- 對sint64 -> (n << 1) ^ (n >> 63)
其他非Varint的數字型別(type為1或5)
按小端位元組序(little-endian)排布(低位位元組排放在記憶體的低地址端,高位位元組排放在記憶體的高地址端)
比如:0x1234ABCD 儲存為 0xCD 0xAB 0×34 0×12
字串型別(type為2)
- 字串採用UTF-8編碼
- 在宣告型別和編號後緊跟一個Varint型別,表示字串長度
- 接下來的是字串內容
比如:required string b = 2; 其中b的值為 testing
結果(16進位制)是 12 07 74 65 73 74 69 6e 67
棕色為字串內容
暗紅色為Varint的型別申明及編號
紫色為Varint的長度申明
內嵌Message型別(type為2)
內嵌Message型別採用類似字串的編碼方法,只是後面跟的是二進位制而不是字串
比如:
message Test1 {
required int32 a = 1;
}
message Test3 {
required Test1 c = 3;
}
其中a.c的值為150
結果為: 1a 03 08 96 01
棕色為Test1的內容
暗紅色為Varint的型別申明及編號
紫色為Varint的長度申明
可重複選項(Repeated)和可選選項(Optional)
- 對於可重複項(沒有設定[packed=true]),編碼的結果裡對一個標籤編號存在0條或多條key-value結構,並且無需連續和不保證順序
- 對於可選項,編碼的結果裡可能沒有該標籤編號的key-value結構
- 對於非可重複項的重複資料的處理方式
- 對於數字和字串,只接受最後一次的值,前面的忽略
- 對於Message,採用合併(Merge)操作,使用後面的值覆蓋前面的值
帶有[packed=true]選項的可重複項(type為2)
可重複項帶有[packed=true]後,所有元素打成一個包,使用類似字串的資料打包形式
message Test4 {
repeated int32 d = 4 [packed=true];
}
結果如下:
22 // tag (編號 4, 型別 2)
06 // 總長度 (6 bytes)
03 // 第一個元素 (varint 3)
8E 02 // 第二個元素 (varint 270)
9E A7 05 // 第三個元素 (varint 86942)
到這裡就沒了,by the way,一些SDK碰到不能識別的資料,將會把它放到最後,比如C++,另一些就直接忽略掉了,比如Python。而且這種設計對協議更新的向後相容非常的好啊
相關文章
- js資料型別之基本資料型別和引用資料型別JS資料型別
- 資料型別: 資料型別有哪些?資料型別
- 區別值型別資料和引用型別資料型別
- 資料型別,型別轉換資料型別
- 資料型別資料型別
- JAVA中基本資料型別和引用資料型別Java資料型別
- 3. php資料型別、資料型別轉換PHP資料型別
- 基本資料型別與字串型別資料型別字串
- MySQL基礎之----資料型別篇(常用資料型別)MySql資料型別
- Java中的基本資料型別與引用資料型別Java資料型別
- 基本資料型別資料型別
- MySQL資料型別MySql資料型別
- [Mysql]資料型別MySql資料型別
- go 資料型別Go資料型別
- NumPy 資料型別資料型別
- SQL 資料型別SQL資料型別
- Oracle 資料型別Oracle資料型別
- Java資料型別Java資料型別
- Python資料型別Python資料型別
- TypeScript資料型別TypeScript資料型別
- MYSQL 資料型別MySQL 資料型別
- php資料型別PHP資料型別
- numpy資料型別資料型別
- JavaScript資料型別JavaScript資料型別
- 一、資料型別資料型別
- Sqlite—資料型別SQLite資料型別
- 1.2 資料型別資料型別
- Redis資料型別Redis資料型別
- JavaScript - 資料型別JavaScript資料型別
- Symbol資料型別Symbol資料型別
- 資料型別2資料型別
- JavaScript 資料型別JavaScript資料型別
- js資料型別JS資料型別
- go資料型別識別Go資料型別
- Mysql 資料型別之整數型別MySQL 資料型別
- Java資料型別及型別轉換Java資料型別
- Oracle資料型別對應Java型別Oracle資料型別Java
- Protobuf簡單型別直接反序列化方法型別
- 資料型別是什麼?Python的資料型別又有哪些?資料型別Python