protobuf編碼


 

 proto2

Protocol Buffers 是一種輕便高效的結構化數據存儲格式,可以用於結構化數據序列化,適合做數據存儲或 RPC 數據交換格式。可用於通訊協議、數據存儲等領域的語言無關、平台無關、可擴展的序列化結構數據格式。

字段規則

  • required: 字段必須存在
  • optional: 字段沒有或有一個
  • repeated: 字段重復,0個或多個

proto 數據類型

 

.proto Type
Notes
C++ Type
Java Type
Python Type [2]
Go Type
double 固定8字節長度 double double float *float64
float 固定4字節長度 float float float *float32
int32 可變長度編碼。對負數編碼低效,如果字段可能是負數,用sint32代替 int32 int int *int32
int64 可變長度編碼。對負數編碼低效,如果字段可能是負數,用sint64代替 int64 long int/long[3] *int64
uint32 可變長度編碼,無符號整數 uint32 int[1] int/long[3] *uint32
uint64 可變長度編碼,無符號整數 uint64 long[1] int/long[3] *uint64
sint32 可變長度編碼。有符號整數。 These more efficiently encode negative numbers than regular int32s. int32 int int *int32
sint64 可變長度編碼。有符號整數。These more efficiently encode negative numbers than regular int64s. int64 long int/long[3] *int64
fixed32 固定4字節長度,無符號整數。 More efficient than uint32 if values are often greater than 228. uint32 int[1] int/long[3] *uint32
fixed64 固定8字節長度,無符號整數。 More efficient than uint64 if values are often greater than 256. uint64 long[1] int/long[3] *uint64
sfixed32 固定4字節長度,有符號整數 int32 int int *int32
sfixed64 固定8字節長度,有符號整數 int64 long int/long[3] *int64
bool   bool boolean bool *bool
string UTF-8 encoded or 7-bit ASCII text. string String str/unicode[4] *string
bytes 包含任意字節序列 string ByteString str []byte

編碼規則

1.varints

理解簡單protobuf編碼,首先要知道varints。varints使用一個字節或多個字節對整數序列化方法。

varints中的每個字節除了最后一個字節,有一個最有效位(most significant bit ,msb),這意味指示之后有其他字節。每個字節的低7位一組數的補碼

例如:

1

0000  0001

300

1010  1100  0000  0010

只取每個字節低七位

010  1100  000  0010

小端序->大端序

000  0010  010  1100 -->  0001  0010  1100  =300

 

2.消息結構

protobuf 消息是一系列key-value對,對於二進制消息,字段數字作為關鍵字。字段的命名和類型在解碼時確定。

在進行消息編碼時,key/value被連接成字節流。在解碼時,解析器可以直接跳過不識別的字段,這樣就可以保證新老版本消息定義在新老程序之間的兼容性,從而有效的避免了使用older消息格式的older程序在解析newer程序發來的newer消息時,一旦遇到未知(新添加的)字段時而引發的解析和對象初始化的錯誤。最后,我們介紹一下字段標號和字段類型是如何進行編碼的。每一個 wire-format消息的key實際上是有兩個值組成:proto文件中定義的字段標號和wire type。

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

key = (field_number << 3) | wire_type key的最后3個bits用於存儲字段的類型信息。那么在使用該編碼時,Protocol Buffer所支持的字段類型將不會超過8種。

例如:150(十進制) 在protobuf二進制文件中是 08 96 01

08 --> 00001000  field_number=1,wire_type=0

96 01 -> 1001 0110  0000 0001 -->  001 0110   000  0001  -->  000 0001   001  0110   --> 1001  0110 =150

3.Signed Integers

wire_type=0 的類型都以varint 進行編碼,所以對於int32和int64,對於負數使用補碼,int32 需要5個字節,int64需要10個字節,有符號整數使用ZIgZag編碼

ZigZag 將有符號整數映射到無符號整數,以此得到一個絕對值較小的數字(例如-1)j就可以獲得一個較小的varint編碼值。

 

 

Signed Original
Encoded As
0 0
-1 1
1 2
-2 3
2147483647 4294967294
-2147483648 4294967295

sint32:       (<< 1) ^ (>> 31)

 sint64:       (<< 1) ^ (>> 63)

4.Non-varint Numbers

wire-type=1:fixed64, sfixed64, double 固定64bit

wire-type=5:fixed32, sfixed32, float,固定32bit

5.Strings

wire-type=2,字符串長度使用varint編碼

例如

message Test2 {
  optional string b = 2;
}

b=“testing” ,編碼后結果:

12 07 74 65 73 74 69 6e 67

12: field number=2,wire-type=2  (2<< 3)|2=0x12

長度為7 varint編碼 0x07

74 65 73 74 69 6e 67  UTF8 編碼

6.Embedded Messages嵌套消息

wire-type=2
message Test1 {
  optional int32 a = 1;
}
message Test3 {
  optional Test1 c = 3;
}

Test1's a field set to 150

Test3 編碼結果: 1a 03 08 96 01

1a: field_number=3,wire_type=2  (3<< 3)|2=11010=0x1a

03: 字節數

08 96 01 : c編碼結果

7.Optional And Repeated Elements

proto2 :消息被定義repeated (沒有 [packed=true]選項),編碼的消息有0或多個使用相同字段標號的key-value對,這些重復的值不必連續出現; 他們可能會與其他字段交錯,但在解碼時順序保留

optional字段,編碼后的消息可能有也可能沒有包含該字段號的鍵值對。

proto3 使用packed encoding:

包含零個元素的打包重復字段不會出現在編碼消息中。這個字段的所有元素都打包到一個wire-type=2的key-value對中

 

message Test4 {
  repeated int32 d = 4 [packed=true];
}
22        // key (field number 4, wire type 2)
06        // payload size (6 bytes)
03        // first element (varint 3)
8E 02     // second element (varint 270)
9E A7 05  // third element (varint 86942)

proto2默認不設置 packed=true
repeated編碼采用空格(0x20)分隔
結果是20 03 20 8e 02 20 9e a7  05


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM