網絡上搜索MQTT協議,會出現太多的解釋,這里就不做官方標准釋義的復制了。這一節我們從實戰理解角度,通俗的將MQTT協議的作用及實現原理說一下,旨在可以快速理解MQTT協議。所以可能會出現很多看似不標准的解釋,但是更容易理解MQTT的內涵,對MQTT十分精通者請忽略此文。
在物聯網項目中,經常出現的要求是“有限環境”。什么意思呢,通俗說就是網絡可能不太穩定,帶寬也可能很小,網速也比較低,硬件MCU性能也很低,要求在這種情況下也能可靠聯網傳輸信息。看到這里大家就會想到我前面提到的短指令中說到的問題了,不是我們認為開發容易好維護就可以的,首先要滿足工作環境的需要,項目才可以成功落地,否則都是無用功。
在N年前最初嘗試做物聯網項目的時候,很多用HTTP協議做硬件設備信息的上報,利用返回結果控制硬件設備執行的項目(其實現在也有人還在使用)。這樣硬件設備信息上報的即時性沒有問題,但經過服務端發送控制指令去操控硬件設備的時候,及時性就很難滿足。因為HTTP是單方向主動請求服務器,有請求才有返回,返回后就斷開了。要想服務端與硬件設備再有聯系,只能等硬件設備通過HTTP的下一個請求上來才可以,也就是服務端不能主動推送消息給硬件設備。看到這里可能會有很多人會說出N多種基於HTTP服務端推送的方案,但是很抱歉,在物聯網環境中都不適合。因為無論是輪詢還是長連接,用HTTP維持所消耗的網絡資源和硬件性能要求對項目來說都是高昂的,必須考慮項目落地要求的“有限環境”。對於網絡不穩定和帶寬低(比如移動網絡、信號弱的區域等)的環境,極大可能造成項目運行失敗,這是不能接受的結果。
那么為什么推薦MQTT協議呢?因為MQTT協議具備以下幾點特征:
1、網絡開銷小,消息頭最小只有2字節,這相比HTTP大大降低了網絡流量。
2、是可保持的會話,為實現服務端及時推消息提供了條件。
3、是異步消息機制,不會阻塞占用資源。
4、具備異常中斷通知機制,可以獲得硬件在線信息變化,及時得到掉線消息。
5、使用發布/訂閱消息模式,一對多或多對一的消息傳輸,實現與應用程序的解耦。
6、傳輸可靠性可控,及三種服務質量,分別是至多一次、至少一次、只有一次。指的是發布者發出的信息,代理服務和訂閱者是否收到的情況。
7、客戶端程序夠輕量,可在很多嵌入式設備中運行。
8、可滿足低帶寬、高延遲、不穩定的網絡環境。
MQTT協議中,需要兩個端,分別是服務端和客戶端;有三個身份,分別是發布者(Publish),代理(Broker)、訂閱者(Subscribe)。
在MQTT協議中,客戶端不能直接對客戶端實行端到端的收發消息,必須經過服務端管理分配,所以服務端要運行一個代理服務,也就是三個身份之一的代理身份。消息的發送方稱為發布者,該消息的需要接收者稱之為訂閱者。發布者把消息發送給代理,代理負責檢查都誰需要接收這個消息(這個就是訂閱),需要的就轉發給它。因為要識別不同的消息,所以MQTT協議制定了主題標准,也就是給消息加上了標簽。發布者發送的消息總是要帶上標簽的,代理根據誰訂閱了這個標簽來決定轉發給誰,這個標簽就稱之為主題(Topic),標簽攜帶我們需要傳輸的信息內容稱之為負載(Payload)。
為了實現異常中斷通知機制,所以在客戶端與服務端首次連接的時候,就要攜帶一條相對特殊的主題,主題內容是如果自己掉線了,希望告知需要知道自己掉線一方一些信息,這就是遺囑消息(Will Message)。這個主題自己在線時,代理不會做任何轉發,當自己掉線達到一定時間(即心跳間隔Keep Alive timer),代理會檢查誰訂閱了這個主題,就轉發給誰(當然可以多人訂閱),這就實現了異常中斷(掉線)通知。
下面繼續深入理解一下MQTT協議的工作過程。
發布者、訂閱者、代理與主題發布與訂閱間的關系:
通過上圖,我們可以看出,同一個客戶端既可以是發布者,也可以是訂閱者。一個主題只有一個發布者,但是可以有很多個訂閱者。一個客戶端也可以訂閱多個主題。
客戶端連接到代理:
工作的第一步是建立連接,MQTT協議也是建立在TCP/IP基礎上的通信協議,首先要在客戶端與代理服務端建立一個TCP連接。建立連接的過程是由客戶端主動發起的,代理服務一直是處於指定端口的監聽狀態,當監聽到有客戶端要接入的時候,就會立刻去處理。客戶端在發起連接請求時,攜帶客戶端ID、賬號、密碼(無賬號密碼使用除外,正式項目不會允許這樣)、心跳間隔時間等數據。代理服務收到后檢查自己的連接權限配置中是否允許該賬號密碼連接,如果允許則建立會話標識並保存,綁定客戶端ID與會話,並記錄心跳間隔時間(判斷是否掉線和啟動遺囑時用)和遺囑消息等,然后回發連接成功確認消息給客戶端,客戶端收到連接成功的確認消息后,進入下一步(通常是開始訂閱主題,如果不需要訂閱則跳過)。上圖只做了連接成功的示意圖,連接失敗和拒絕先腦補一下即可,后面會設計到更具體的。
客戶端訂閱主題:
客戶端將需要訂閱的主題經過SUBSCRIBE報文發送給代理服務,代理服務則將這個主題記錄到該客戶端ID下(以后有這個主題發布就會發送給該客戶端),然后回復確認消息SUBACK報文,客戶端接到SUBACK報文后知道已經訂閱成功,則處於等待監聽代理服務推送的消息,也可以繼續訂閱其他主題或發布主題。
客戶端發布主題:
當某一客戶端發布一個主題到代理服務后,代理服務先回復該客戶端收到主題的確認消息,該客戶端收到確認后就可以繼續自己的邏輯了。但這時主題消息還沒有發給訂閱了這個主題的客戶端,代理要根據質量級別(QoS)來決定怎樣處理這個主題。所以這里充分體現了是MQTT協議是異步通信模式,不是立即端到端反應的。
如果發布和訂閱時的質量級別QoS都是至多一次,那代理服務則檢查當前訂閱這個主題的客戶端是否在線,在線則轉發一次,收到與否不再做任何處理。這種質量對系統壓力最小。
如果發布和訂閱時的質量級別QoS都是至少一次,那要保證代理服務和訂閱的客戶端都有成功收到才可以,否則會嘗試補充發送(具體機制后面討論)。這也可能會出現同一主題多次重復發送的情況。這種質量對系統壓力較大。
如果發布和訂閱時的質量級別QoS都是只有一次,那要保證代理服務和訂閱的客戶端都有成功收到,並只收到一次不會重復發送(具體機制后面討論)。這種質量對系統壓力最大。
代理最終將主題消息轉發給訂閱者,至少是做了轉發操作,成功與否決定質量等級。更詳細的消息質量等級控制后面會有專門詳細敘述。
關於MQTT協議的實現原理通俗解釋就到這里,希望能讓剛剛接觸MQTT的開發者有個整體流程的印象和理解,后面會詳細討論MQTT協議的定義、配置等。
本節完,待續......