Protobuf协议格式详解
protobuf 是google開源的一個序列化框架,類似xml,json,最大的特點是基于二進制,比傳統的XML表示同樣一段內容要短小得多。還可以定義一些可選字段,用于服務端與客戶端通信。前面幾篇文章說了protobuf的用法,看到網上也沒有分析protobuf協議的文章,就利用一些時間寫了?protobuf 的協議分析,希望大家喜歡。
protobuf協議核心思想
基于128bits的數值存儲方式(Base 128 Varints)
數據表示方式:每塊數據由接連的若干個字節表示(小的數據用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 |
基于序號的協議字段映射(類似key-value結構)
所以字段可以亂序,可缺段(記optional)
| message person{? ? required string name ? ? ?= 1;? ? required string country ?= 2;? ? optional int32 age ? ? ? ? ? = 3;} |
效果相當于json數據:person?= [{1: "john"}, {2: ?"USA"}, {3: 30}],其中{3: 30} 還可以不傳,person還可以傳成 [{2: ?"USA"}, {1: "john"}],對端仍舊可以正常解析。
基于無符號數的帶符號數表示(ZigZag 編碼)
| 0 | 0 |
| -1 | 1 |
| 1 | 2 |
| -2 | 3 |
| 2147483647 | 4294967294 |
| -2147483648 | 4294967295 |
| 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 |
數據類型的表示如下:
| 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 |
寫在最后
protobuf的優缺點
優點前面也提到了,主要有兩個:
1、序列化和反序列化效率比 xml 和 json 都高(這個protobuf 自己做了測試,鏈接要翻墻);
2、字段可以亂序,欠缺,因此可以用來兼容舊的協議,或者是減少協議數據。
但是字段允許亂序欠缺,反過來也是缺點。所以這里總結?protobuf?兩個缺點,一個跟這有關:
1、如果字段過多,或者嵌套過深,都會影響反序列化效率,解析每一塊數據都要根據序號找到對應的位置然后再插入到已解析好的數據中。
2、數據基于128bits的存儲方式,單塊數據比較大時效率很受影響。解析數據需要取到所有字節的低7位,然后再拼成一整塊數據。
以上兩個缺點,特別是對于erlang這類沒有指針的語言來說,代價就相當昂貴。
3、協議序號也要占空間,序號越大占空間越大,當序號小于16時無需額外增加字節就可以表示。
protobuf 分析題
最后貼一道分析題,如果看得懂,基本就了解 protobuf 的協議內容了| message Test2 {? ? required int32 a = 3;}創建了Test2結構,a 賦值 150, 結果是0001 1000 1001 0110 ?0000 0001這個數寫成十進制就是 24 150 1,怎么得到這個數據? |
總結
以上是生活随笔為你收集整理的Protobuf协议格式详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 阿里云容器镜像加速器
- 下一篇: 数组添加/扩容和数组缩减