protobuf資料型別

工程師WWW發表於2013-11-18

四、限定符(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



protobuf的資料型別主要有:

規則結構型別列表:


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型別[動態整型](type0

1.       每個位元組第一位表示有無後續位元組,有為1,無為0,     (雙位元組,低位元組在前,高位元組在後.)

2.       剩餘7位倒序合併

舉例: 300 的二進位制為 10 0101100

第一位:1(有後續) + 0101100

第二位:0(無後續) + 0000010

最終結果: 101011000000010

Message 結構

 

  1. 鍵值型結構(Key-Value)
  2. 第一部分為Key值,Varint 結構
  3. Key值的後三位表示規則型別的Type值,其他部分和為型別的數字編號
  4. 後面緊跟value,value的值依據規則型別不同而不同

舉例: required int32 a = 1; a值為150


Key0000 1000,型別為000,數字編號為0001

ValueVarint型別):1001 0110  0000 0001


值解碼: 000 0001 + 001 0110 = 10010110 = 150


sint32sint64型別的編碼(ZigZag

對於sint32sint64型別的編碼採用ZigZag編碼方式,最後一位表示正負情況,即如下:

原始值

編碼為

0

0

-1

1

1

2

-2

3

2147483647

4294967294

-2147483648

4294967295

解碼方式為:

  1. 對sint32 -> (n << 1) ^ (n >> 31)
  2. 對sint64 -> (n << 1) ^ (n >> 63)

其他非Varint的數字型別(type15

按小端位元組序(little-endian)排布(低位位元組排放在記憶體的低地址端,高位位元組排放在記憶體的高地址端)

比如:0x1234ABCD 儲存為 0xCD 0xAB 0×34 0×12

字串型別(type2

  1. 字串採用UTF-8編碼
  2. 在宣告型別和編號後緊跟一個Varint型別,表示字串長度
  3. 接下來的是字串內容

比如:required string b = 2; 其中b的值為 testing

結果(16進位制)是 12 07 74 65 73 74 69 6e 67

棕色為字串內容

暗紅色為Varint的型別申明及編號

紫色為Varint的長度申明

 

內嵌Message型別(type2

內嵌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

  1. 對於可重複項(沒有設定[packed=true]),編碼的結果裡對一個標籤編號存在0條或多條key-value結構,並且無需連續和不保證順序
  2. 對於可選項,編碼的結果裡可能沒有該標籤編號的key-value結構
  3. 對於非可重複項的重複資料的處理方式
  4. 對於數字和字串,只接受最後一次的值,前面的忽略
  5. 對於Message,採用合併(Merge)操作,使用後面的值覆蓋前面的值

 

帶有[packed=true]選項的可重複項(type2

可重複項帶有[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。而且這種設計對協議更新的向後相容非常的好啊

相關文章