一、協(xié)議概述
物聯(lián)網(wǎng)(Internet of Things,IoT)最近曝光率越來越高。雖然HTTP是網(wǎng)頁的事實(shí)標(biāo)準(zhǔn),不過機(jī)器之間(Machine-to-Machine,M2M)的大規(guī)模溝通需要不同的模式:之前的請(qǐng)求/回答(Request/Response)模式不再合適,取而代之的是發(fā)布/訂閱(Publish/Subscribe)模式。這就是輕量級(jí)、可擴(kuò)展的MQTT(Message Queuing Telemetry Transport)可以施展拳腳的舞臺(tái)。
MQTT是基于二進(jìn)制消息的發(fā)布/訂閱編程模式的消息協(xié)議,最早由IBM提出的,如今已經(jīng)成為OASIS規(guī)范。由于規(guī)范很簡單,非常適合需要低功耗和網(wǎng)絡(luò)帶寬有限的IoT場景,比如:遙感數(shù)據(jù)、汽車、智能家居、智慧城市、醫(yī)療醫(yī)護(hù)。
由于物聯(lián)網(wǎng)的環(huán)境是非常特別的,所以MQTT遵循以下設(shè)計(jì)原則:
--精簡,不添加可有可無的功能。
--發(fā)布/訂閱(Pub/Sub)模式,方便消息在傳感器之間傳遞。
--允許用戶動(dòng)態(tài)創(chuàng)建主題,零運(yùn)維成本。
--把傳輸量降到最低以提高傳輸效率。
--把低帶寬、高延遲、不穩(wěn)定的網(wǎng)絡(luò)等因素考慮在內(nèi)。
--支持連續(xù)的會(huì)話控制。
--理解客戶端計(jì)算能力可能很低。
--提供服務(wù)質(zhì)量管理。
--假設(shè)數(shù)據(jù)不可知,不強(qiáng)求傳輸數(shù)據(jù)的類型與格式,保持靈活性。
運(yùn)用MQTT協(xié)議,設(shè)備可以很方便地連接到物聯(lián)網(wǎng)云服務(wù),管理設(shè)備并處理數(shù)據(jù),最后應(yīng)用到各種業(yè)務(wù)場景,如下圖所示:

二、協(xié)議詳解
整個(gè)協(xié)議的構(gòu)造,從整體上協(xié)議可拆分為: ? 固定頭部+可變頭部+消息體
1、固定頭部(fixed header):
構(gòu)造如下:

? ?? 1)Message Type(0和15保留,共占4個(gè)字節(jié))

2)DUP flag:其是用來在保證消息傳輸可靠的,如果設(shè)置為1,則在下面的變長頭部里多加MessageId,并需要回復(fù)確認(rèn),保證消息傳輸完成,但不能用于檢測消息重復(fù)發(fā)送。
3)QoS level:主要用于PUBLISH(發(fā)布態(tài))消息的,保證消息傳遞的次數(shù)。
00表示最多一次 即<=1
01表示至少一次 ?即>=1
10表示一次,即==1
11保留后用
4)RETAIN:主要用于PUBLISH(發(fā)布態(tài))的消息,表示服務(wù)器要保留這次推送的信息,如果有新的訂閱者出現(xiàn),就把這消息推送給它。如果不設(shè)那么推送至當(dāng)前訂閱的就釋放了。
5)固定頭部的byte 2:是用來保存接下去的變長頭部+消息體的總大小的。但并不是直接保存的,同樣也是可以擴(kuò)展的,其機(jī)制是,前7位用于保存長度,后一位用做標(biāo)識(shí)。
舉個(gè)例子:即如果計(jì)算出后面的大小為 0<length<=127,正常保存;如果是127<length<16383,則需要二個(gè)字節(jié)保存了,將第一個(gè)字節(jié)的最大的一位置1,表示未完。然后第二個(gè)字節(jié)繼續(xù)存。拿130來說,第一個(gè)字節(jié)存10000011,第二個(gè)字節(jié)存000000001,也就是0x83,0x01,把兩個(gè)字節(jié)連起來看,第二個(gè)字節(jié)權(quán)重從2的8次開始。同起可以加第3個(gè)字節(jié),最多可以加至第4個(gè)字節(jié)。故MQTT協(xié)議最多可以實(shí)現(xiàn)268?435?455 (0xFF, 0xFF, 0xFF, 0x7F)將近256M的數(shù)據(jù)??芍^能伸能縮。
例如,數(shù)字64十進(jìn)制被編碼為單個(gè)字節(jié),十進(jìn)制值64,十六進(jìn)制0x40。數(shù)字321十進(jìn)制(= 65 + 2 * 128)被編碼為兩個(gè)字節(jié),最不重要。第一個(gè)字節(jié)65 + 128 = 193。請(qǐng)注意,頂部位被設(shè)置為至少指示一個(gè)后續(xù)字節(jié)。第二個(gè)字節(jié)是2。
2、可變頭部(variable header):
整體結(jié)構(gòu)為:

1)首先最上面的8個(gè)字節(jié)是Protocol Name(協(xié)議名稱),UTF編碼的字符“MQIsdp”,頭兩個(gè)是編碼名提長為6。這里多說 ?? 一些,接下去的協(xié)議多采用這種方式組合,即頭兩個(gè)字節(jié)表示下一部分的長,然后后面跟上內(nèi)容。這里頭兩個(gè)字節(jié)長 ?? 為6,下面跟6個(gè)字符“MQIsdp”。
2)Protocol Version,協(xié)議版本號(hào),v3 也是固定的。
3)Connect Flag,連接標(biāo)識(shí),有點(diǎn)像固定頭部的。8位分別代表不同的標(biāo)志。第1個(gè)字節(jié)保留。
? ? Clean Session,Will flag,Will Qos, Will Retain都是相對(duì)于CONNECT消息來說的。
?? Clean Session:0表示如果訂閱的客戶機(jī)斷線了,那么要保存其要推送的消息,如果其重新連接時(shí),則將這些消息推 ? ? ?? 送。1表示消除,表示客戶機(jī)是第一次連接,消息所以以前的連接信息。
? Will Flag,表示如果客戶機(jī)在不是在發(fā)送DISCONNECT消息中斷,比如IO錯(cuò)誤等,將些置為1,要求重傳。并且下面的 ? ? Will Qos和Will Retain也要設(shè)置,消息體中的Topic和MessageID也要設(shè)置,就是表示發(fā)生了錯(cuò)誤,要重傳。
? Will Qos,在CONNECT非正常情況下設(shè)置,一般如果標(biāo)識(shí)了Will Flag,那么這個(gè)位置也要標(biāo)識(shí)。
?? Will RETAIN:同樣在CONNECT中,如果標(biāo)識(shí)了Will Flag,那么些位也一定要標(biāo)識(shí)。
? usename flag和password flag,用來標(biāo)識(shí)是否在消息體中傳遞用戶和密碼,只有標(biāo)識(shí)了,消息體中的用戶名和密碼才 ? ?? 用效,只標(biāo)記密碼而不標(biāo)記用戶名是不合法的。
4)Keep Alive,表示響應(yīng)時(shí)間,如果這個(gè)時(shí)間內(nèi),連接或發(fā)送操作未完成,則斷開tcp連接,表示離線。
5)Connect Return Code即通常于CONNACK消息中,表示返回的連接情況,我可以通過此檢驗(yàn)連接情況。

6)Topic name(主題名稱):訂閱消息標(biāo)識(shí),MQTT是基于訂閱/發(fā)布的消息,那么這個(gè)就是消息訂閱的標(biāo)識(shí),像新聞客戶端里的訂閱不同的欄目一樣。用于區(qū)別消息的推送類別。
主要用于PUBLISH和SUBSCRIBE中。最大可支持32767個(gè)字符,即4個(gè)字節(jié)。
3、消息體(PayLoad)
只有3種消息有消息體CONNECT,SUBSCRIBE,SUBACK。
CONNECT主要是客戶機(jī)的ClientID,訂閱的Topic和Message以及用戶名和密碼,其于變長頭部中的will是對(duì)應(yīng)的。
SUBSCRIBE是包含了一系列的要訂閱的主題以及QOS。
SUBACK是用服務(wù)器對(duì)于SUBSCRIBE所申請(qǐng)的主題及QOS進(jìn)行確認(rèn)和回復(fù)。
而PUBLISH是消息體中則保存推送的消息,以二進(jìn)制形式,當(dāng)然這里的編輯可自定義。
4、Message Identifier:消息標(biāo)識(shí)符存在于以下MQTT消息的變量頭中:PUBLISH,PUBACK,PUBREC,PUBREL,PUBCOMP,SUBSCRIBE,SUBACK,UNSUBSCRIBE,UNSUBACK。
消息標(biāo)識(shí)符(Message ID)字段僅存在于固定報(bào)頭中的QoS位表示QoS級(jí)別1或2的消息中。其為16位字符表示,用于在Qos為1或2時(shí)標(biāo)識(shí)Message的,保證Message傳輸?shù)目煽啃浴?/p>
