protobuf 是google開源的乙個序列化框架,類似xml,json,最大的特點是基於二進位制,比傳統的xml表示同樣一段內容要短小得多。還可以定義一些可選字段,用於服務端與客戶端通訊。前面幾篇文章說了protobuf的用法,看到網上也沒有分析protobuf協議的文章,就利用一些時間寫了 protobuf 的協議分析,希望大家喜歡。
資料表示方式:每塊資料由接連的若干個位元組表示(小的資料用1個位元組就可以表示),每個位元組最高位標識本塊資料是否結束(1:未結束,0:結束),低7位表示資料內容。(可以看出資料封包後體積至少增大14.2%)
數字1的表示方法為:0000 0001,這個容易理解
數字300的表示方法為:1010 1100 0000 0010
protobuf位元組序是小端位元組序,所以這個數字實際是0000 0010 1010 1100
1010 1100 0000 0010
→ 010 1100 000 0010
如下:000 0010 010 1100
→ 000 0010 ++ 010 1100
→ 10 0101100
→ 256 + 32 + 8 + 4 = 300
所以字段可以亂序,可缺段(記optional)
message person, , ],其中 還可以不傳,person還可以傳成 [, ],對端仍舊可以正常解析。
原始的帶符號數
zigzag編碼後的表示00
-1112
-232147483647
4294967294
-2147483648
4294967295
使用 zigzag 編碼,充分利用基於128bits的數值儲存(base 128 varints)的技術,只需要加多1個位來表示符號。當絕對值小的數字非常有利,這種方式可以有效減少協議內容長度。
sint32型別編碼如下:
(n << 1) ^ (n >> 31)
sint64型別編碼如下:
(n << 1) ^ (n >> 63)
protobuf怎麼在一長串二進位制中表示若干個資料?
做法就是每塊資料前加乙個資料頭,表示資料型別及協議字段序號。
msg1_head + msg1 + msg2_head + msg2 + ...
資料頭也是基於128bits的數值儲存方式,一般1個位元組就可以表示:
message test1 {
required int32 a = 1;
如上建立了 test1 的結構並且把 a 設為 2,序列化好的二進位制資料為:
0000 1000 0000 0010
以上資料轉成十六進製制也就是 08 02,其中 8 是怎麼得到的?
000 1000
低3位表示資料型別:0,其他表示協議字段序號:1,加上最高位0, 結果就是8
資料型別的表示如下:
型別含義
用於哪些資料型別
0varint
int32, int64, uint32, uint64, sint32, sint64, bool, enum
164-bit
fixed64, sfixed64, double
2length-delimited
string, bytes, embedded messages, packed repeated fields
3start group
groups (deprecated)
4end group
groups (deprecated)
532-bit
fixed32, sfixed32, float
優點前面也提到了,主要有兩個:
1、序列化和反序列化效率比 xml 和 json 都高(這個protobuf 自己做了測試,鏈結要翻牆);
2、字段可以亂序,欠缺,因此可以用來相容舊的協議,或者是減少協議資料。
但是字段允許亂序欠缺,反過來也是缺點。所以這裡總結 protobuf 兩個缺點,乙個跟這有關:
1、如果欄位過多,或者巢狀過深,都會影響反序列化效率,解析每一塊資料都要根據序號找到對應的位置然後再插入到已解析好的資料中。
2、資料基於128bits的儲存方式,單塊資料比較大時效率很受影響。解析資料需要取到所有位元組的低7位,然後再拼成一整塊資料。
以上兩個缺點,特別是對於erlang這類沒有指標的語言來說,代價就相當昂貴。
3、協議序號也要佔空間,序號越大佔空間越大,當序號小於16時無需額外增加位元組就可以表示。
最後貼一道分析題,如果看得懂,基本就了解 protobuf 的協議內容了
message test2 {
required int32 a = 3;
建立了test2結構,a 賦值 150, 結果是
0001 1000 1001 0110 0000 0001
這個數寫成十進位制就是 24 150 1,怎麼得到這個資料?
protobuf編碼格式
protobuf序列化出來的二進位制訊息特別的緊湊,得益於使用巧妙的編碼格式。1 varint varint 是一種緊湊的表示數字的方法。它用乙個或多個位元組來表示乙個數字,值越小的數字使用越少的位元組數。varint 中的每個 byte 的最高位 bit 有特殊的含義,如果該位為 1,表示後續的 ...
HTTP協議格式詳解
http請求格式 1.首行 4.方法get 獲取 post 傳送 put delete 三個部分之間用空格分隔 2.協議頭 header 若干個鍵值對,每個鍵值對佔一行,每個鍵和值之間使用 分隔 3.空行表示header到這裡就結束了 4.協議正文 body 一般get請求沒有body,post請求...
ProtoBuf 反射詳解
protocol buffer 簡稱 protobuf,是用於結構化資料序列化的靈活 高效 自動的方法,又如 xml,不過它更小 更快 也更簡單。你可以定義自己的資料結構,然後使用 生成器生成的 來讀寫這個資料結構。你甚至可以在無需重新部署程式的情況下更新資料結構。本文主要介紹 protobuf 裡...