工業(yè)物聯(lián)網(wǎng)核心技術(shù)——MQTT(一)
一、MQTT初探
1. MQTT是什么?
MQTT(Message Queuing Telemetry Transport,消息隊(duì)列遙測(cè)傳輸協(xié)議),是一種基于發(fā)布/訂閱(Publish/Subscribe)模式的輕量級(jí)通訊協(xié)議,該協(xié)議構(gòu)建于TCP/IP協(xié)議上,由IBM在1999年發(fā)布,目前***版本為v3.1.1。MQTT***的優(yōu)點(diǎn)在于可以以極少的代碼和有限的帶寬,為遠(yuǎn)程設(shè)備提供實(shí)時(shí)可靠的消息服務(wù)。做為一種低開(kāi)銷、低帶寬占用的即時(shí)通訊協(xié)議,MQTT在物聯(lián)網(wǎng)、小型設(shè)備、移動(dòng)應(yīng)用等方面有廣泛的應(yīng)用。
當(dāng)然,在物聯(lián)網(wǎng)開(kāi)發(fā)中,MQTT不是唯一的選擇,與MQTT互相競(jìng)爭(zhēng)的協(xié)議有XMPP和CoAP協(xié)議等,文章末尾會(huì)有一個(gè)比較和說(shuō)明。
2. MQTT是哪一層的協(xié)議?
眾所周知,TCP/IP參考模型可以分為四層:應(yīng)用層、傳輸層、網(wǎng)絡(luò)層、鏈路層。TCP和UDP位于傳輸層,應(yīng)用層常見(jiàn)的協(xié)議有HTTP、FTP、SSH等。MQTT協(xié)議運(yùn)行于TCP之上,屬于應(yīng)用層協(xié)議,因此只要是支持TCP/IP協(xié)議棧的地方,都可以使用MQTT。
3. MQTT消息格式
每條MQTT命令消息的消息頭都包含一個(gè)固定的報(bào)頭,有些消息會(huì)攜帶一個(gè)可變報(bào)文頭和一個(gè)負(fù)荷。消息格式如下:
- 固定報(bào)文頭 | 可變報(bào)文頭 | 負(fù)荷
4. 固定報(bào)文頭(Fixed Header)
MQTT固定報(bào)文頭最少有兩個(gè)字節(jié),***字節(jié)包含消息類型(Message Type)和QoS級(jí)別等標(biāo)志位。第二字節(jié)開(kāi)始是剩余長(zhǎng)度字段,該長(zhǎng)度是后面的可變報(bào)文頭加消息負(fù)載的總長(zhǎng)度,該字段最多允許四個(gè)字節(jié)。
剩余長(zhǎng)度字段單個(gè)字節(jié)***值為二進(jìn)制0b0111 1111,16進(jìn)制0x7F。也就是說(shuō),單個(gè)字節(jié)可以描述的***長(zhǎng)度是127字節(jié)。為什么不是256字節(jié)呢?因?yàn)镸QTT協(xié)議規(guī)定,單個(gè)字節(jié)第八位(***位)若為1,則表示后續(xù)還有字節(jié)存在,第八位起“延續(xù)位”的作用。
例如,數(shù)字64,編碼為一個(gè)字節(jié),十進(jìn)制表示為64,十六進(jìn)制表示為0×40。數(shù)字321(65+2*128)編碼為兩個(gè)字節(jié),重要性***的放在前面,***個(gè)字節(jié)為65+128=193(0xC1),第二個(gè)字節(jié)是2(0x02),表示2×128。
由于MQTT協(xié)議最多只允許使用四個(gè)字節(jié)表示剩余長(zhǎng)度(如表1),并且***一字節(jié)***值只能是0x7F不能是0xFF,所以能發(fā)送的***消息長(zhǎng)度是256MB,而不是512MB。
表1
5. 可變報(bào)文頭(Variable Header)
可變報(bào)文頭主要包含協(xié)議名、協(xié)議版本、連接標(biāo)志(Connect Flags)、心跳間隔時(shí)間(Keep Alive timer)、連接返回碼(Connect Return Code)、主題名(Topic Name)等,后面會(huì)針對(duì)主要部分進(jìn)行講解。
6. 有效負(fù)荷(Payload)
Payload直譯為負(fù)荷,可能讓人摸不著頭腦,實(shí)際上可以理解為消息主體(body)。
當(dāng)MQTT發(fā)送的消息類型是CONNECT(連接)、PUBLISH(發(fā)布)、SUBSCRIBE(訂閱)、SUBACK(訂閱確認(rèn))、UNSUBSCRIBE(取消訂閱)時(shí),則會(huì)帶有負(fù)荷。
二、MQTT的主要特性
1. MQTT的消息類型(Message Type)
固定報(bào)文頭中的***個(gè)字節(jié)包含連接標(biāo)志(Connect Flags),連接標(biāo)志用來(lái)區(qū)分MQTT的消息類型。MQTT協(xié)議擁有14種不同的消息類型(如表2),可簡(jiǎn)單分為連接及終止、發(fā)布和訂閱、QoS 2消息的機(jī)制以及各種確認(rèn)ACK。至于每一個(gè)消息類型會(huì)攜帶什么內(nèi)容,這里不多闡述。
表2
2. 消息質(zhì)量(QoS)
MQTT消息質(zhì)量有三個(gè)等級(jí),QoS 0,QoS 1和 QoS 2。
- QoS 0:最多分發(fā)一次。消息的傳遞完全依賴底層的TCP/IP網(wǎng)絡(luò),協(xié)議里沒(méi)有定義應(yīng)答和重試,消息要么只會(huì)到達(dá)服務(wù)端一次,要么根本沒(méi)有到達(dá)。
- QoS 1:至少分發(fā)一次。服務(wù)器的消息接收由PUBACK消息進(jìn)行確認(rèn),如果通信鏈路或發(fā)送設(shè)備異常,或者指定時(shí)間內(nèi)沒(méi)有收到確認(rèn)消息,發(fā)送端會(huì)重發(fā)這條在消息頭中設(shè)置了DUP位的消息。
- QoS 2:只分發(fā)一次。這是***級(jí)別的消息傳遞,消息丟失和重復(fù)都是不可接受的,使用這個(gè)服務(wù)質(zhì)量等級(jí)會(huì)有額外的開(kāi)銷。
通過(guò)下面的例子可以更深刻的理解上面三個(gè)傳輸質(zhì)量等級(jí)。
比如目前流行的共享單車智能鎖,智能鎖可以定時(shí)使用QoS level 0質(zhì)量消息請(qǐng)求服務(wù)器,發(fā)送單車的當(dāng)前位置,如果服務(wù)器沒(méi)收到也沒(méi)關(guān)系,反正過(guò)一段時(shí)間又會(huì)再發(fā)送一次。之后用戶可以通過(guò)App查詢周圍單車位置,找到單車后需要進(jìn)行解鎖,這時(shí)候可以使用QoS level 1質(zhì)量消息,手機(jī)App不斷的發(fā)送解鎖消息給單車鎖,確保有一次消息能達(dá)到以解鎖單車。***用戶用完單車后,需要提交付款表單,可以使用QoS level 2質(zhì)量消息,這樣確保只傳遞一次數(shù)據(jù),否則用戶就會(huì)多付錢了。
3. 遺愿標(biāo)志(Will Flag)
在可變報(bào)文頭的連接標(biāo)志位字段(Connect Flags)里有三個(gè)Will標(biāo)志位:Will Flag、Will QoS和Will Retain Flag,這些Will字段用于監(jiān)控客戶端與服務(wù)器之間的連接狀況。如果設(shè)置了Will Flag,就必須設(shè)置Will QoS和Will Retain標(biāo)志位,消息主體中也必須有Will Topic和Will Message字段。
那遺愿消息是怎么回事呢?服務(wù)器與客戶端通信時(shí),當(dāng)遇到異?;蚩蛻舳诵奶瑫r(shí)的情況,MQTT服務(wù)器會(huì)替客戶端發(fā)布一個(gè)Will消息。當(dāng)然如果服務(wù)器收到來(lái)自客戶端的DISCONNECT消息,則不會(huì)觸發(fā)Will消息的發(fā)送。
因此,Will字段可以應(yīng)用于設(shè)備掉線后需要通知用戶的場(chǎng)景。
4. 連接保活心跳機(jī)制(Keep Alive Timer)
MQTT客戶端可以設(shè)置一個(gè)心跳間隔時(shí)間(Keep Alive Timer),表示在每個(gè)心跳間隔時(shí)間內(nèi)發(fā)送一條消息。如果在這個(gè)時(shí)間周期內(nèi),沒(méi)有業(yè)務(wù)數(shù)據(jù)相關(guān)的消息,客戶端會(huì)發(fā)一個(gè)PINGREQ消息,相應(yīng)的,服務(wù)器會(huì)返回一個(gè)PINGRESP消息進(jìn)行確認(rèn)。如果服務(wù)器在一個(gè)半(1.5)心跳間隔時(shí)間周期內(nèi)沒(méi)有收到來(lái)自客戶端的消息,就會(huì)斷開(kāi)與客戶端的連接。心跳間隔時(shí)間***值大約可以設(shè)置為18個(gè)小時(shí),0值意味著客戶端不斷開(kāi)。
5. MQTT其他特點(diǎn)
(1) 異步發(fā)布/訂閱實(shí)現(xiàn)
發(fā)布/訂閱模式解耦了發(fā)布消息的客戶(發(fā)布者)與訂閱消息的客戶(訂閱者)之間的關(guān)系,這意味著發(fā)布者和訂閱者之間并不需要直接建立聯(lián)系。
這個(gè)模式有以下好處:
- 發(fā)布者與訂閱者只需要知道同一個(gè)消息代理即可;
- 發(fā)布者和訂閱者不需要直接交互;
- 發(fā)布者和訂閱者不需要同時(shí)在線。
由于采用了發(fā)布/訂閱實(shí)現(xiàn),MQTT可以雙向通信。也就是說(shuō)MQTT支持服務(wù)端反向控制設(shè)備,設(shè)備可以訂閱某個(gè)主題,然后發(fā)布者對(duì)該主題發(fā)布消息,設(shè)備收到消息后即可進(jìn)行一系列操作。
(2) 二進(jìn)制格式實(shí)現(xiàn)
MQTT基于二進(jìn)制實(shí)現(xiàn)而不是字符串,比如HTTP和XMPP都是基于字符串實(shí)現(xiàn)。由于HTTP和XMPP擁有冗長(zhǎng)的協(xié)議頭部,而MQTT固定報(bào)文頭僅有兩字節(jié),所以相比其他協(xié)議,發(fā)送一條消息最省流量。