Protocol buffer序列化及其在微信藍牙協議中的應用
Protocol buffer是Google出品的一種輕便高效的結構化數據存儲格式。可對結構化數據進行序列化,並具有語言無關、平臺無關等特點。在通信協議和數據存儲等領域已經得到廣泛的應用。眼下其已經提供 C/C++、Java、Python 等語言的 API。
一、Protocol buffer和XML
在數據通信傳輸時,一般須要將結構化的數據序列化成流進行傳送,接收方再反序列化為原始格式數據進行處理。在Web通信領域,XML應用算是最通用的了。在時間性能上,盡管XML的序列化開銷還可以。可是反序列化的效率是比較差,而Protocol buffer的反序列化效率是比較高的;在空間性能上,Protobuffer採用了可變長的數據編碼格式。比XML的字符格式要高效得多。
Google集群要處理PB級數據。Protocolbuffer可以在時間和空間性能上有所改進,在總體效益而言就是相當可觀的。
正是基於以上原因。微信和藍牙外設的通信協議採用了Protocol buffer對消息包體進行打包。
本文的目標是講述Protobuffer在藍牙微信協議中的應用,有助於理解微信藍牙協議,對微信發給藍牙外設的消息數據流進行反序列化,得到原始的結構化格式數據。
因此語法也是環繞微信藍牙協議包展開。更加具體的語法請百度相關內容或者找筆者探討。
二、微信藍牙外設協議通用格式
微信藍牙使用流進行傳輸,在流上傳輸的是一個接著一個的業務邏輯的數據包。
把設備發往廠商server或者微信server的請求包稱為Req,回復包稱為Resp。一個請求相應一個回包。
把廠商server或者微信server主動發往設備的請求包稱為PushReq。
包結構由定長包頭和變長包體組成。當中包體即由Protocol buffer進行打包。
當中,定長包頭為8個字節,bMagicNumber為0xFE。bVer為版本號01;nLength為包長,包含包頭和包體的長度。nCmdId為命令編碼,如登陸授權,初始化。發送數據。push推送等等;nSeq為序列號。PushReq包的序列號固定為0。其它請求和回復包的序列號務必保持一致。每次請求後序列號加1.
以廠商server主動發數據給設備的PushReq包為例來說明變長包體,其相應定長包頭的nCmdId為ECI_push_recvData = 30001。包體包含下面三個部分:
1) Push包標識
2) 自定義數據,指的是業務層自定義的數據格式形成的數據。
3) 數據類型。如廠商自己定義的數據,還是微信clientHtml5的數據等
三、Protobuffer的語法表述
Protobuffer對push_recvData包的表述例如以下:
Message類似C語言的struct數據結構,是Protobuffer消息定義的keyword。RecvDataPush是消息的名稱。
Required前綴表示該字段必須在序列化之前賦值。optional前綴表示能夠不賦值。
BasePush BasePush是message的第一個字段field。前者代表數據類型,後者是名稱,當中BashPush在協議中是這樣定義的:
Message BashPush{} 其意味著裏面沒有數據項。BashPush在打包過程中僅僅會出現數據類型,事實上也是代表著一種push標識。
Bytes Data是第二個字段field,為字符串。名稱是Data。
EmDeviceDataType type是第三個字段field,為設備數據類型。當中EmDeviceDataType是一個enum類型。例如以下:
1,2,3代表字段在序列化後布局中的位置index,第一個位置是BashPush,接著是Data、type。
四、Protobuffer打包
Protobuffer打包有下面要素和規則:
1.使用Varints算法表示數字。
Varints是一種緊湊表示數字的方法。Varints中每個字節的最高位是有特殊含義的,假設是1,則表示興許的字節也是該數字的一部分;假設是0,則結束。所以假設表示小於128的數值能夠用一個字節,假設大於等於128的數字則要用很多其它的字節進行表示。
2. Protobuffer有下面數據類型
Type表示相應數據類型序號,當中Varint相應的數據類型包含int32,int64,enum等等。type序號為0,其都使用Varints進行表示。String,bytes,message類型相應的type序號為2.
3. Protobuffer打包即是將message通過一系列的key-value對來表示。
而key就是每一個message中各字段的index(並做一定運算)。value依據類型的不同會有不同的表現形式。
當中key = field<<3 | type。
field即字段的index,而type是字段的數據類型序號。
而value,在數據類型為Varint時,直接為字段的賦值,依照Varints算法進行編碼。在其它類型時就是“長度+原始內容編碼”。
五、PushReq包分析
我們通過微信提供的AirSyncDebugger2.1.0.apk來分析Protobuffer對數據包的序列化。該APP用於微信和藍牙外設的通信調試,其封裝了微信藍牙的協議,一般先用該APP調通藍牙協議。再和後臺server聯調。如果我們自己定義的消息內容為fe cf 00 01 00 0c 20 01 00 00 00 00,即相應第二個字段bytesData,該消息內容是上一篇文章中server控制亮燈所發的消息,後臺server和藍牙外設的消息協議是自己定義的。
AirSyncDebugger對PushReq包的序列化例如以下:
序列化過程分析例如以下:
固定包頭(不受Protobuffer控制):
Magic : fe
Version: 01
Length : 00 1A。即包體和包體的總長度為26字節。
Cmdid : 75 31,十進制就是30001。即ECI_push_recvData包
Seq : 00 00 push包的序列號都是00 00
變長包體(Protobuffer控制打包,十六進表示):
0A: BasePush的field是1, 值類型message的序號type為2,所以是0x1<<3|0x02 = 0x0A
00 : 即值長度為0,BasePush值為空,事實上就是一種標識。
12:data的field是2。值類型bytes的序號為2,所以是0x2<<3|0x2=0x12
0C: data的長度是12
Fe cf 00 01 00 0c20 03 00 00 00 00 : data的內容,即我們自己定義的消息。
18: Type的field是3,值類型enum的序號為0。所以是0x3<<3|0=0x18
00:Type的值,由於enum屬於Varint的一種,所以不須要長度,直接用值表示,0代表廠商自己定義數據。
六、基於微信硬件公眾平臺的智能控制方案開發專欄介紹
接下來嵌入式企鵝圈會將陸續公開基於微信硬件公眾平臺的智能控制開發技術細節,大致內容包含:
1. 物聯網架構和場景分析(已發)
2. 基於微信硬件公眾平臺的智能控制開發流程(已發)
3. 雲server搭建和公眾號配置
4. 公眾號菜單設置
5. 微信消息傳遞過程和微信設備接入接口協議
6. 微信硬件平臺後臺服務開發
7. 微信藍牙協議和授權、綁定過程
8.Protocol buffer序列化及其在微信藍牙協議中的應用(已發)
9. 藍牙外設控制開發
…
謝謝支持嵌入式企鵝圈:
Protocol buffer序列化及其在微信藍牙協議中的應用