?Protocol buffer是Google出品的一種輕便高效的結構化數據存儲格式,可對結構化數據進行序列化,并具有語言無關、平臺無關等特點,在通信協議和數據存儲等領域已經得到廣泛的應用。目前其已經提供?C/C++、Java、Python 等語言的 API。
>一、Protocol buffer和XML
在數據通信傳輸時,一般需要將結構化的數據序列化成流進行傳送,接收方再反序列化為原始格式數據進行處理。在Web通信領域,XML應用算是最通用的了。在時間性能上,雖然XML的序列化開銷還可以,但是反序列化的效率是比較差,而Protocol buffer的反序列化效率是比較高的;在空間性能上,Protobuffer采用了可變長的數據編碼格式,比XML的字符格式要高效得多。Google集群要處理PB級數據,Protocolbuffer能夠在時間和空間性能上有所改進,在整體效益而言就是相當可觀的。
正是基于以上原因,微信和藍牙外設的通信協議采用了Protocol buffer對消息包體進行打包。本文的目標是講述Protobuffer在藍牙微信協議中的應用,有助于理解微信藍牙協議,對微信發給藍牙外設的消息數據流進行反序列化,得到原始的結構化格式數據。因此語法也是圍繞微信藍牙協議包展開。更加詳細的語法請百度相關內容或者找筆者探討。
>二、微信藍牙外設協議通用格式
微信藍牙使用流進行傳輸,在流上傳輸的是一個接著一個的業務邏輯的數據包。把設備發往廠商服務器或者微信服務器的請求包稱為Req,回復包稱為Resp,一個請求對應一個回包。把廠商服務器或者微信服務器主動發往設備的請求包稱為PushReq。
包結構由定長包頭和變長包體組成,其中包體即由Protocol buffer進行打包。

其中,定長包頭為8個字節,bMagicNumber為0xFE;bVer為版本01;nLength為包長,包括包頭和包體的長度;nCmdId為命令編碼,如登陸授權,初始化,發送數據,push推送等等;nSeq為序列號,PushReq包的序列號固定為0,其他請求和回復包的序列號務必保持一致,每次請求后序列號加1.
以廠商服務器主動發數據給設備的PushReq包為例來說明變長包體,其對應定長包頭的nCmdId為ECI_push_recvData = 30001。包體包括以下三個部分:
1) Push包標識
2) 自定義數據,指的是業務層自己定義的數據格式形成的數據。
3)? 數據類型,如廠商自定義的數據,還是微信客戶端Html5的數據等
>三、Protobuffer的語法表述
Protobuffer對push_recvData包的表述如下:

Message類似C語言的struct數據結構,是Protobuffer消息定義的關鍵字。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
而value,在數據類型為Varint時,直接為字段的賦值,按照Varints算法進行編碼;在其他類型時就是“長度+原始內容編碼”。
>五、PushReq包分析
我們通過微信提供的AirSyncDebugger2.1.0.apk來分析Protobuffer對數據包的序列化。該APP用于微信和藍牙外設的通信調試,其封裝了微信藍牙的協議,一般先用該APP調通藍牙協議,再和后臺服務器聯調。假設我們自定義的消息內容為fe cf 00 01 00 0c 20 01 00 00 00 00,即對應第二個字段bytesData,該消息內容是上一篇文章中服務器控制亮燈所發的消息,后臺服務器和藍牙外設的消息協議是自定義的。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
00 : 即值長度為0,BasePush值為空,其實就是一種標識。
12:data的field是2,值類型bytes的序號為2,所以是0x2
0C:? data的長度是12
Fe cf 00 01 00 0c20 03 00 00 00 00 : data的內容,即我們自定義的消息。
18: Type的field是3,值類型enum的序號為0,所以是0x3
00:Type的值,因為enum屬于Varint的一種,所以不需要長度,直接用值表示,0代表廠商自定義數據。
>六、基于微信硬件公眾平臺的智能控制方案開發專欄介紹
?????? 接下來嵌入式企鵝圈會將陸續公開基于微信硬件公眾平臺的智能控制開發技術細節,大致內容包括:
1\. 物聯網架構和場景分析(已發)
2\. 基于微信硬件公眾平臺的智能控制開發流程(已發)
3\. 云服務器搭建和公眾號配置
4\. 公眾號菜單設置
5\. 微信消息傳遞過程和微信設備接入接口協議
6\. 微信硬件平臺后臺服務開發
7\. 微信藍牙協議和授權、綁定過程
8.Protocol buffer序列化及其在微信藍牙協議中的應用(已發)
9\. 藍牙外設控制開發
…
?
謝謝支持嵌入式企鵝圈:

- 前言
- 物聯網架構演進和微信智能設備平臺開發
- 基于微信硬件公眾平臺的智能控制開發流程
- Protocol buffer序列化及其在微信藍牙協議中的應用
- 網絡架構、云平臺和微信公眾平臺開發接入
- 如何快速理解一個全新的嵌入式操作系統
- 如何快速理解一個全新的嵌入式操作系統(續)
- 一張圖讀懂基于微信硬件平臺的物聯網架構
- 揭開智能配置上網(微信Airkiss)的神秘面紗
- 物聯網核心協議—消息推送技術演進
- 藍牙防丟器原理、實現與Android BLE接口編程
- 以藍牙開發的視覺解讀微信Airsync協議
- 全球最低功耗藍牙單芯片(DA14580)系統架構和應用開發框架分析
- 從零開始搭建微信硬件開發環境全過程——1小時掌握微信硬件開發流程