MQTT協(xié)議是一個面向物聯(lián)網(wǎng)應(yīng)用的即時通信協(xié)議,使用TCP/IP提供網(wǎng)絡(luò)連接,能夠?qū)ω?fù)載內(nèi)容實(shí)現(xiàn)消息屏蔽傳輸,開銷小,可以有效降低網(wǎng)絡(luò)流量。MQTT協(xié)議適用于設(shè)備和平臺需要保持長連接的使用場景,MQTT特點(diǎn)在于可以實(shí)現(xiàn)設(shè)備間的消息單播以及組播,可以不依賴于其他服務(wù)(下發(fā)命令服務(wù),推送服務(wù)等)實(shí)現(xiàn)讓設(shè)備以應(yīng)用服務(wù)器的方式對真實(shí)設(shè)備進(jìn)行管理和控制。
正因?yàn)镸QTT協(xié)議擁有這些特點(diǎn),現(xiàn)在成文了各個物聯(lián)網(wǎng)云平臺支持的最廣泛的協(xié)議,百度、阿里、亞馬遜、OneNet等國內(nèi)外物聯(lián)網(wǎng)云服務(wù)提供商均支持該協(xié)議,所以在做物聯(lián)網(wǎng)開發(fā)的過程中,有必要學(xué)習(xí)和了解一下該協(xié)議。接下來我們就以O(shè)neNET的MQTT接入?yún)f(xié)議為例,學(xué)習(xí)一下該協(xié)議個通訊。
硬件連接環(huán)境:麒麟座迷你開發(fā)板用STlink連接到PC的USB口
軟件開發(fā)環(huán)境:Keil MDK5.25編輯麒麟座mini開發(fā)板官方例程”6.ESP8266-MQTT_TYPE3-LED”
網(wǎng)絡(luò)環(huán)境:PC機(jī)以太網(wǎng)卡連接路由器接入互聯(lián)網(wǎng),Windows10無線網(wǎng)卡建立熱點(diǎn),麒麟座開發(fā)板的ESP8266經(jīng)過熱點(diǎn)接入互聯(lián)網(wǎng)。
抓包工具:Wireshart抓取以太網(wǎng)卡的數(shù)據(jù)包,設(shè)置過濾條件為”ip.addr == 183.230.40.39”,只顯示與OneNET MQTT服務(wù)器通訊的數(shù)據(jù)包。
模擬器:simulate-device.exe,在PC上可以模擬嵌入式設(shè)備通訊。
參考文檔:OneNET官方MQTT文檔:”MQTT.docx”,MQTT中文文檔MQTT.PDF
交互過程:連接權(quán)鑒,數(shù)據(jù)上報,命令下發(fā),斷開連接。
一、連接權(quán)鑒
首先在修改官方例程中的參數(shù)信息,把WiFi名稱和密碼改成使用PC無線網(wǎng)卡模擬的熱點(diǎn)網(wǎng)絡(luò),OneNET服務(wù)器的IP地址和端口號確保為”183.230.40.39”和”6002”,onenet.c中的PROID、DEVID、AUTH_INFO修改為項目中的真實(shí)值。
編譯并下載程序到麒麟座迷你開發(fā)板,在PC上使用Wireshark開始抓取以太網(wǎng)卡的數(shù)據(jù)包,設(shè)置過濾條件為”ip.addr == 183.230.40.39”,只顯示與OneNET MQTT服務(wù)器通訊的數(shù)據(jù)包。給麒麟座開發(fā)板上電,等待幾秒鐘后,就可以看到開發(fā)板與OneNET服務(wù)器通訊的數(shù)據(jù)包了。
數(shù)據(jù)包中前三幀為開發(fā)板與OneNET服務(wù)器建立TCP連接的三次握手信息,這個是開發(fā)板給ESP8266發(fā)送建立TCP連接指令后,ESP8266與服務(wù)器之間自動建立的。
數(shù)據(jù)包的第四幀至第五幀為麒麟座開發(fā)板項OneNET發(fā)送的鑒權(quán)信息和服務(wù)區(qū)應(yīng)答。第六幀和第七幀是OneNET服務(wù)器返回的鑒權(quán)結(jié)果信息和ESP8266的應(yīng)答。
在以上過程中,我們作為設(shè)備端開發(fā)人員,只需要了解第四幀的鑒權(quán)信息發(fā)送和第六幀的服務(wù)器鑒權(quán)結(jié)果返回就可以了。
接下來重點(diǎn)分析第四幀數(shù)據(jù),次幀數(shù)據(jù)總計有114字節(jié),去除以太網(wǎng)頭14字節(jié),IP頭20字節(jié),TCP頭20字節(jié),剩余的TCP有效載荷共計60字節(jié)。
根據(jù)MQTT報文協(xié)議中規(guī)定,每一個MQTT包總共包含三部分:
1、Fixed Header部分定義如下:
根據(jù)抓包的數(shù)據(jù),TCP負(fù)載的第一個字節(jié)是0x10,對應(yīng)表格可以得知,MQTT Packet Type值為1,名稱為CONNECT,其功能是客戶端請求與服務(wù)器建立連接。其第二個字節(jié)的0x3a為表格中的Remaining Length字段,為數(shù)據(jù)包的長度。
根據(jù)MQTT協(xié)議規(guī)定,剩余長度(Remaining Length)表示當(dāng)前報文剩余部分的字節(jié)數(shù),包括可變報頭和負(fù)載的數(shù)據(jù)。剩余長度不包括用于編碼剩余長度字段本身的字節(jié)數(shù)。0x3a為十進(jìn)制的58,這個數(shù)正好是TCP負(fù)載的60字節(jié)減去固定報頭的兩個字節(jié)長度。至于如何判斷剩余長度占用的字節(jié)數(shù),MQTT協(xié)議是這么規(guī)定的:
剩余長度字段使用一個變長度編碼方案,對小于128的值它使用單字節(jié)編碼。更大的值按下面的方式處理。低7位有效位用于編碼數(shù)據(jù),最高有效位用于指示是否有更多的字節(jié)。因此每個字節(jié)可以編碼128個數(shù)值和一個延續(xù)位(continuation bit)。剩余長度字段最大4個字節(jié)。
根據(jù)以上定義,0x3a的二進(jìn)制最高位為0,可以判定數(shù)據(jù)長度為1字節(jié)。
固定報頭的部分分析完成后,根據(jù)下表進(jìn)行判斷:
2、CONNECT類型的消息是有可變報頭和負(fù)載的。對于可變報頭部分,按照以下格式編碼:
? ? ? ??對照抓包數(shù)據(jù):
其中byte1-byte6是固定值,表格與數(shù)據(jù)完全對應(yīng)。Byte7表示MQTT協(xié)議版本,這個必須固定為4,即3.1.1版,OneNET只支持這一版本協(xié)議,不支持更早版本的協(xié)議。
在Byte8中,user flag與password flag平臺不允許匿名登陸,因此這兩個標(biāo)志位在連接時必須設(shè)置為1,否則認(rèn)為協(xié)議錯誤,平臺將會斷開連接。所以該字節(jié)數(shù)據(jù)為0xC0。
Byte9-10為保持連接(Keep Alive),是一個以秒為單位的時間間隔,表示為一個16位的字,它是指在客戶端傳輸完成一個控制報文的時刻到發(fā)送下一個報文的時刻,兩者之間允許空閑的最大時間間隔。如果保持連接的值非零,并且服務(wù)端在一點(diǎn)五倍的保持連接時間內(nèi)沒有收到客戶端的控制報文,它必須斷開客戶端的網(wǎng)絡(luò)連接,認(rèn)為網(wǎng)絡(luò)連接已斷開。OneNET規(guī)定最短120秒,最長65535秒,這里設(shè)置的事0x0100,也就是256秒。
3、負(fù)載部分
負(fù)載部分的數(shù)據(jù)是按照以下格式編碼
? ? ??對照數(shù)據(jù):
0x0008為域一的字符串長度,這里是8字節(jié),內(nèi)容為ASCII碼的“31421353”,正好是源碼中DEVID,也就是設(shè)備ID(DeviceID);0x0006為域二的字符串長度,這里是6字節(jié),內(nèi)容為ASCII碼的“141215”,正好是源碼中PROID,也就是產(chǎn)品ID(ProduceID);0x001C為域三的字符串長度,這里是28字節(jié),內(nèi)容為ASCII碼的”dpsO9ruH0aTZublG9g5SvBtFSEQ=”,正好是源碼中AUTH_INFO,也就是產(chǎn)品ID(AuthInfo);
至此,上傳的鑒權(quán)信息就分析完畢了,服務(wù)器接收到鑒權(quán)信息后首先會有一個應(yīng)答包,同時進(jìn)行鑒權(quán),鑒權(quán)完畢后會下發(fā)結(jié)果給客戶端:
鑒權(quán)結(jié)果同樣采用TCP傳輸,總共60個字節(jié),除去以太網(wǎng)頭、IP頭、TCP頭共計54字節(jié),還剩余60字節(jié),其中有效TCP負(fù)載為4字節(jié),其后面的兩個字節(jié)為TCP數(shù)據(jù)包需要四字節(jié)對齊所補(bǔ)充的無效數(shù)據(jù)。
服務(wù)器返回的鑒權(quán)結(jié)果同樣遵循MQTT包規(guī)則,首先是固定報頭,根據(jù)上文表格0x20表示服務(wù)器確認(rèn)連接,0x02表示后面跟隨兩字節(jié)有效數(shù)據(jù),這里就是可變報頭了。
可變報頭規(guī)則如下:
根據(jù)返回的數(shù)據(jù)為0x0000,表示鑒權(quán)成功了。
二、數(shù)據(jù)上報
數(shù)據(jù)上報過程其實(shí)就是TCP通訊過程,每一次上報數(shù)據(jù)需要三幀,分別是數(shù)據(jù)上報,服務(wù)器確認(rèn),客戶端確認(rèn),其中只需要了解數(shù)據(jù)上報幀就可以了。
在數(shù)據(jù)上報幀中,總計有121字節(jié),除去以太網(wǎng)頭、IP頭、TCP頭共計54字節(jié),TCP有效字節(jié)數(shù)為67字節(jié)。
1、固定報頭
根據(jù)MQTT協(xié)議規(guī)定的上傳報文中的固定報頭格式如下:
對照抓取的數(shù)據(jù),TCP負(fù)載第一個字節(jié)0x32中的“3”表示上傳數(shù)據(jù)報文,其中的“2”表示QoS值為1。
根據(jù)MQTT協(xié)議中服務(wù)質(zhì)量定義表格如下:
對照表格,表示QoS值為1,即至少分發(fā)一次。
TCP負(fù)載的第二字節(jié)的0x41表示后面數(shù)據(jù)長度為65字節(jié)。
2、可變報頭
其報文格式如下:
對照抓取數(shù)據(jù):
0x0003為域一的兩字節(jié)字符串長度,這里為3個字節(jié),內(nèi)容為主題名,這里為ASCII碼的”$dp”,OneNET規(guī)定,”$dp”為系統(tǒng)上傳數(shù)據(jù)點(diǎn)的指令。
接下來的0x000a為報文標(biāo)識符(PacketIdentifier),因?yàn)橹癚oS值選用的1,所以這兩個字節(jié)在這里是必須的,固定為10,也就是0x000a。
3、負(fù)載
Payload包含真正的數(shù)據(jù)點(diǎn)內(nèi)容,支持的格式如下:
對照抓取的數(shù)據(jù):
負(fù)載的第一個字節(jié)為0x03,即Type=3,根據(jù)類型3的說明:
類型3說明后面?zhèn)€數(shù)據(jù)是JSON格式2的字符串,后面兩個字節(jié)0x0037表示字符串的長度為55。
最后的55個字節(jié)就是上傳的數(shù)據(jù)了,內(nèi)容為55個ASCII碼:
{"Red_Led":1,"Green_Led":1,"Yellow_Led":1,"Blue_Led":1}
這里表示上傳了代表Led燈狀態(tài)的四個數(shù)據(jù)流以及對應(yīng)的值,OneNET服務(wù)器就會解析數(shù)據(jù)流并保存數(shù)據(jù)了。
三、命令下發(fā)
通過抓取數(shù)據(jù)包,命令下發(fā)過程需要四幀完成。
根據(jù)MQTT協(xié)議,四幀分別是服務(wù)器命令下發(fā),客戶端應(yīng)答,客戶端命令回復(fù),服務(wù)器端應(yīng)答。所以我們只需要了解服務(wù)器命令下發(fā)幀和客戶端命令回復(fù)幀即可。
根據(jù)抓取到的數(shù)據(jù),服務(wù)器命令下發(fā)幀總計108字節(jié),其中TCP負(fù)載為54字節(jié)。
固定報頭中的0x30表示發(fā)布消息,0x34表示后續(xù)內(nèi)容有52字節(jié)。
可變報頭部分?jǐn)?shù)據(jù)格式如下:
根據(jù)抓取數(shù)據(jù),0002a表示字符串長度為42字節(jié),字符串內(nèi)容為ASCII碼的”$creq/e8b6c9b6-225b-57dc-abaa-246ba58761d8”。其中”$creq”為系統(tǒng)下發(fā)指令標(biāo)記,”/”為分隔符,后續(xù)的”e8b6c9b6-225b-57dc-abaa-246ba58761d8”為該條指令的uuid,uuid是通用唯一識別碼,用于識別該指令的唯一性。
最后的八個字節(jié)為MQTT數(shù)據(jù)報的負(fù)載部分,為真正的指令內(nèi)容,這里是”redled:0”,客戶端接收到該指令后控制led燈的亮滅。
四、斷開連接
MQTT協(xié)議的斷開連接沒有特殊的規(guī)定,只是遵循了TCP的斷開連接過程,主要就是雙方各自發(fā)送FIN標(biāo)記的TCP包,并給對方確認(rèn),總共四幀數(shù)據(jù)完成。
五、總結(jié)
至此OneNET官方例程中的主要MQTT協(xié)議就分析完成了,其實(shí)除了分析過的外,還有其他交易存在,比如訂閱、取消訂閱、創(chuàng)建Topic、推送Topic、離線Topic等等,但是在例程中沒有用到,而且在也不是最常用的,所以這里沒有分析。通過分析發(fā)現(xiàn),MQTT協(xié)議非常的精煉,很適合作為物聯(lián)網(wǎng)的控制協(xié)議,而且通過分析,基本了解了MQTT協(xié)議的主要內(nèi)容,這對于下一步在各個不同平臺(Arduino,STM32,樹莓派,windows)通過MQTT協(xié)議接入OneNET云做了充分的準(zhǔn)備。
評論
查看更多