protobuf 學習
前言
最近由于個人的興趣轉到了消息箱業務線,學習IM相關知識。說到IM,首先會講到使用TCP協議還是UDP協議;再其次會講到選擇什么樣的聊天協議:是基于原生Socket封裝的CocoaAsyncSocket,還是基于webSocket的Facebook開源項目SocketRocket,還是基于xmpp的xmppframework;再者會了解到我們傳輸的數據格式:是Json,還是XML,還是ProtocolBuffer?
今天我們要學習的就是ProtocolBuffer。
簡介
Google Protocol Buffer(簡稱 Protobuf)是Google公司內部的混合語言數據標準,它是一種輕便高效的結構化數據存儲格式,可以用于結構化數據串行化,或者說序列化。它很適合做數據存儲或RPC數據交換格式。常用于通訊協議、數據存儲等領域的語言無關、平臺無關、可擴展的序列化結構數據格式。
編碼機制
協議封裝總體格式
發送一個完整的通訊協議,二進制組成結構:
字段 | 長度 | 說明 |
---|---|---|
PacketLen | 4byte | little-endian |
HeaderLen | 1-5byte | varint |
HeaderData | ||
BodyLen | 1-5byte | varint |
BodyData |
Header和Body字段分別使用自定義編碼,基于protobuf
字段編碼規則
- FieldTag 表示字段ID序號
- FiledType 表示字段數據類型
- FiledTagAndType 表示字段類型標識符
兩者共享一個byte字節呈現
- 3個bit可以標識7種數據類型,當前只定義了四種類型
- 0:varint
- 1:string
- 2:struct(dictionary)
- 3:array
FieldTagAndType = (FiledTag << 3) | FiledType
逆向計算:
FieldTag = FiledTagAndType >> 3
FieldType = FiledTagAndType % 8
具體字段類型編碼格式
基本類型:數字(varint:0)
字段特征碼 + 值
例如
{3:1}
二進制編碼
<<25,1>>
3 << 3 | 1 = 25
基本類型:字符串(string:1)
二進制編碼為
字段特征碼 + 值長度 + 值
例如
{2: “abcde”}
二進制編碼為
<<17,5,97,98,99,100,101>>
2 << 3 | 1 = 17
5 代表字符串長度
97,98,99,100,101 分別代表abcde的ascii編碼十進制表示。
基本類型:字典(結構體)(dict:2)
二進制編碼為
字段特征碼 + 結構體長度 + 每個具體key:value鍵值對的逐一自我呈現。
例如:
{
0: 1,
1: "abc",
3: {
0: 100,
1: "bcd"
}
}
二進制編碼表示為
<<0,1,9,3,97,98,99,26,7,0,100,9,3,98,99,100>>
這里分為三部分: <<0,1>> <<9,3,97,98,99>> <<26,7,0,100,9,3,98,99,100>>
前兩部分不細說了,就是上面數字和字符串的規則,重點說第三部分<26,7,0,100,9,3,98,99,100>>
3 << 3 | 2 = 26
結構體長度是100和"bcd“ =>0,100,9,3,98,99,100占了7個字節長度
基本類型:數組(array:3)
二進制編碼為:
字段特征碼 + 二進制長度 + 數組元素類型 + [每一個具體key:value鍵值對的逐一自我呈現]
例如:
{
3: [1, 2, 3, 4, 5],
4: ["cde", "def"]
}
二進制編碼表示為:
<<27,6,0,1,2,3,4,5,35,9,1,3,99,100,101,3,100,101,102>>
27: 3 << 3 | 3 = 27
6 : 二進制數組長度,后面緊跟著6個字節數組二進制表示(一個類型特征1 + 數組的真正二進制長度5)
0 : 數組元素是數字類型
35: 4 << 3 | 1 = 35
9 : 二進制長度 1,3,99,100,101,3,100,101,102
1 : 元素類型是字符串
protobuf優點:
1、性能好,效率高
時間、控件開銷都得到了很大程度的優化。
缺點:
1、可讀性較差
這個直接影響開發測試時候的效率。當然,一般情況下,protobuf非常可靠,并不會出現太大的問題。
2、通用性差
protobuf雖然支持了大量語言的序列化和反序列化,但仍然并不是一個跨平臺和語言的
傳輸標準。在多平臺消息傳遞中,對其他項目的兼容性并不是很好,需要做相應的適配
改造工作。相比json 和 XML,通用性還是沒那么好。
總結
對于Protobuf的選擇來說,一般用于IM通訊,在http傳輸方案中用的比較少,json可讀性要比protobuf好太多。
1、因為TCP所有數據都是二進制數據流傳輸,需要自己去把二進制數據流轉成自己需要的數據協議,Protobuf可以很好的支持這一點,所以Protobuf在TCP傳輸使用的場景比較多。
2、HTTP是屬于應用層的協議,底層傳輸使用的也是TCP。HTTP已經做了數據解封裝操作,我們在使用get和post的時候,我們在開發中可以快速拿到客戶端和服務器的傳輸的數據(一般使用Json)Json可讀性好,也能在各個端也能快速的轉成Model,所以基本已經滿足了大部分公司99%的需求。protobuf的解析快,但是一般app在這塊應該沒有什么性能的瓶頸,如果對數據解析和節省帶寬有要求的話可以使用protobuf。