目錄
一、前言
二、MQTT協議基本特點:
三、MQTT協議特性
四、MQTT協議通信模型
4.1 Client/Server架構
4.1.1 MQTT Client
4.1.2 MQTT Broker
4.2 發布/訂閱模式
五、MQTT協議格式
六、MQTT協議實作原理
6.1 建立連接
6.2 關閉連接
6.3 發布與訂閱
6.4 Qos
6.4.1 QoS0
6.4.2 QoS1
6.4.3 QoS2
6.5 keepalive與連接保活
6.5.1 keepalive的作用
6.5.2 keepalive特性
6.6 Retained訊息
6.6.1 Retained訊息的作用
6.6.2 Retained訊息特點
6.6.3 Retained訊息和持久會話
6.7 LWT(遺囑)
七、MQTT版本
一、前言
MQTT協議可以說是目前應用最廣的物聯網應用層協議,MQTT解決了物聯網中的一個最基礎問題,即設備和設備、設備和云端服務之間的通信,主要應用場景是可以為大量低功耗、網路環境不可靠的物聯網設備提供通信保障,該文章主要針對初學者的一些疑問進行解釋,比如,你知道為什么QoS2等級的訊息可以保證訊息不會重復接收嗎?為什么說是提供可靠的通信保障?更多協議細節沒有展示,可以參考MQTT中文網,
二、MQTT協議基本特點:
-
實作簡單
-
提供資料傳輸的QoS
-
輕量級、占用帶寬低
-
可傳輸任意型別的資料
-
可保持的會話(Session)
三、MQTT協議特性
-
基于TCP長連接的應用層協議,;
-
基于Client/Server架構;
-
使用訂閱/發布模式,將訊息的發送方和接收方解耦;
-
提供3種訊息的QoS(Quality of Service): 至多一次、最少一次、只有一次;
-
收發訊息都是異步的,發送方不需要等待接收方應答;
四、MQTT協議通信模型
4.1 Client/Server架構
完整的MQTT協議包括兩部分,MQTT Client和MQTT Server,其中MQTT Server 也就是Broker;

4.1.1 MQTT Client
只要設備基于MQTT協議連接了MQTT Broker ,就認為這個設備是MQTT Client, MQTT Client 可以單獨作為發布者和訂閱者,也可以同時是發布者和訂閱者,
4.1.2 MQTT Broker
MQTT Broker 是MQTT協議的核心,主要作用是接收發布者的訊息,然后轉發給對應的訂閱者,Broker可以對Clinet接入進行授權,并對Client進行權限控制,常用的C語言撰寫的MQTT Broker 開源庫有Mosquitto,更多可以查看https://github.com/mqtt/mqtt.github.io/wiki/servers,如果學習MQTT需要Broker環境,可以通過這些開源庫自建,也可以用各大云平臺提供的Broker服務,如阿里云、騰訊云,
4.2 發布/訂閱模式

MQTT是通過發布/訂閱模式實作,由于發布方和訂閱方沒有直接聯系,所以需要一個中間方對訊息進行發布和存盤,我們稱這個中間方為Broker,Broker 簡單來說就是基于mqtt協議的server實作(github 上有很多開源實作),連接到Broker的發布方和訂閱方作為Client;
-
發布方和訂閱方都建立了到Broker的TCP連接;
-
訂閱方告知Broker它要訂閱的Topic;
-
發布方將訊息發送到Broker,并指定訊息主題(Topic);
-
Broker接收到訊息后,檢測哪些訂閱方訂閱了對應的Topic,然后將訊息發送到訂閱方;
-
訂閱方從Broker獲取訊息;
-
如果某個訂閱方處于離線狀態,Broker可以先保存對應的訊息,當訂閱方下次連接到Broker的時候,再將之前的訊息發送給訂閱方;
五、MQTT協議格式
MQTT協議使用二進制資料包,包含三個部分,分別是固定頭,可變頭、訊息體;
-
固定頭:存在于所有的MQTT資料包中,長度是2~5位元組,包括3部分內容,資料包型別(4bit),標識位(4bit),資料包剩余長度大小(1~4Byte),具體含義參考MQTT協議
-
可變頭:部分MQTT資料包包含
-
訊息體:部分MQTT資料包包含
MQTT協議中,固定頭中的資料包剩余長度大小包括可變頭和訊息體長度,剩余長度可用1~4Byte表示,4Byte最大可表示256MB(0xFFFFFF7F),有些資料包沒有可變頭和訊息體,比如PINGREQ資料包只有2Byte,由此可以計算MQTT資料包的最大值和最小值
-
最大值:256MB+5Byte,其中256MB是剩余長度最大值,包括可變頭和訊息體;5Byte是固定頭,資料包型別(4bit),標識位(4bit),資料包剩余長度大小(4Byte);
-
最小值:2Byte,比如PINGREQ資料包,只有固定頭,沒有可變頭,訊息體;
六、MQTT協議實作原理
6.1 建立連接
Client在可以發布和訂閱訊息之前,必須先連接到Broker,這個連接不僅僅是建立TCP連接,也包括應用層建立連接,MQTT建立連接流程如下:
-
Client向Broker發送CONNECT資料包;
-
Broker收到CONNECT資料包后,如果允許接入則回復回傳碼為0的CONNACK資料包,如果拒絕接入,則回復回傳碼非0的CONNACK資料包,回傳碼表示失敗原因;

6.2 關閉連接
關閉連接可以由Client或Broker任意一方發起,也有第3種情況會關閉連接,就是心跳超時,不同的關閉流程也有區別:
-
Client端關閉連接:Client向Broker發送DISCONNECT資料包,不用等待Broker回復DISCONNECT資料包,Broker不會回復,發完就可以關閉底層的TCP連接;之所以要在斷開TCP連接前發送與Broker沒有互動的資料包,是為了讓Broker識別是正常的斷開的連接,Broker會丟棄當前連接的遺愿訊息,否則會識別為非正常連接,不會丟掉當前連接的醫院訊息;
-
Broker端關閉連接:不需要發送任何MQTT資料包,直接關閉底層TCP連接
-
keepalive超時:MQTT協議規定Broker沒有收到Client的DISCONNECT資料包之前都應該保持連接,但是如果Broker在keepalive的時間間隔里,沒有收到Client的任何資料包時就會主動關閉連接,這個keepalive 的數值是Client在發起連接時資料包種指定的;
6.3 發布與訂閱
發布與訂閱的概念想必大家都很了解,具體互動的協議資料包可查看MQTT協議,介紹幾個關鍵特性:
-
支持接收離線訊息:MQTT支持訂閱者接受離線訊息,但并不意味著離線狀態下可以接收訊息,意思是如果發布者在訂閱者處于離線狀態下時向Broker發布了訊息,訂閱了對應Topic的訂閱者再次連接到Broker后會收到發布方在其離線期間發布訊息,接收離線訊息的要求是需要Client使用持久會話,且發布時的QoS不小于1;
-
主題通配符:發布和訂閱的訊息主題可以使用通配符,通配符的主要作用是指定訊息主題名稱的層級,有一個特殊情況,取消訂閱時通配符不起作用,取消訂閱的主題名稱必須每個字都和訂閱時指定的主題名稱相同;
6.4 Qos
MQTT協議設計初衷是提供一套保證訊息穩定傳輸的機制,用于網路帶寬窄,信號不穩定環境下的資料傳輸,這套機制包括訊息應答,存盤和重傳,在這套機制下提供了三種不同層次的QoS(Quality of Service),QoS是Sender和Receiver之間達成的協議,而不是Publisher和Subscriber之間達成的協議,也就是Publisher和Broker之間的QoS,Subscriber和Broker之間的QoS ,兩者是沒有直接關系的,
-
QoS0:至多一次
-
QoS1:至少一次
-
QoS2:確保只有一次
以上是3種QoS服務層次,很多初學者在學習MQTT初期可能不太明白實作原理,尤其是QoS2如何確保只發送一次的,其實從MQTT協議本身來分析是很好理解的;
6.4.1 QoS0
Qos0是最簡單的一個訊息質量服務等級,Sender向Receiver發送含訊息資料的PUBLISH資料包,然后不管結果如何,直接丟棄已發送的PUBLISH資料包,所以Receiver最多收到一次,

6.4.2 QoS1
為了保證Receiver至少收到一次訊息,QoS1增加了應答機制;Sender向Receiver發送一個帶有訊息資料的PUBLISH資料包,并把這個資料包保存在本地,Receiver收到后會回傳一個PUBACK資料包,PUBACK資料包的可變頭中有一個和PUBLISH資料包相同的包標識,Sender收到PUBACK后根據包標識(Packet Identifier)找到本地保存的資料包并丟棄,發送完成,
如果Sender發送PUBLISH資料包后一定時間內沒收到PUBACK資料包,就會把PUBLISH資料包中的DUP標識置1(表示資料包是重發)重新發送,重復以上步驟,直到收到PUBACK,所以如果因為網路延遲等原因導致超時時間內Receiver沒有收到PUBLISH資料包或PUBACK沒發出去,就會導致Receiver收到多次,

6.4.3 QoS2
QoS2不僅要保證Receiver能收到Sender發送的資料包,而且不能重復,即只能收到一次,所以重傳和應答機制更加復雜;在3種服務等級中,QoS2是開銷最大的,速度最慢的,當然也是最安全的,
QoS2用2套請求/應答流程,也就是一個4段的握手來保證Receiver只收到一次Sender發送的訊息,
1)Sender發送QoS值為2的PUBLISH資料包,假設資料包中包含Packet Identifier(包標識)為P,并在本地保存PUBLISH資料包;
2)Receiver收到PUBLISH資料包后,在本地保存PUBLISH資料包的Packet Identifier 為P,并回復Sender一個PUBREC資料包,PUBREC包含Packet Identifier為P,但是沒有訊息體;
3)Sender收到PUBREC后就可以丟掉Packet Identifier為P的PUBLISH資料包,同時保存PUBREC資料包到本地,并回復Receiver一個PUBREL資料包,PUBREL資料包中的Packet Identifier為P,沒有訊息體;如果Sender超時時間內沒有收到PUBREC資料包,會把PUBLISH中的DUP標識 設為1,重新發送PUBLISH資料包;
4)當Receiver收到PUBREL資料包時,可以丟掉保存在本地的 Packet Identifier P,并回復Sender一個PUBCOMP資料包,PUBCOMP資料包可變頭中的Packet Identifier為P,沒有訊息體,
5)當Sender收到PUBCOMP資料包,資料包傳輸完成,丟掉本地的PUBREC資料包,如果Sender在超時時間內沒有收到PUBCOMP資料包,就會重復發PUBREL資料包;
以上就是完成一個QoS2等級資料包的流程,至少要發送4個資料包,但是有同學在第3步發現,當Sender沒有收到Receiver的PUBREC資料包時,仍然會出現PUBLISH資料包重復發送的情況,那么怎么保證Receiver只收到一次的呢?
原因就是Receiver收到PUBLISH資料包時,不是立即投遞給協議上層,而是在本地做持久化將訊息保存起來,等收到PUBREL資料包后才將訊息投遞給協議上層,然后把本地保存的Packet Identifier P洗掉,由于PUBREL資料包中沒有Packet Identifier P,所以即使PUBCOMP沒有發送成功導致PUBREL重發,Receiver也只需要回復PUBCOMP,不用重復投遞PUBLISH資料包到協議上層;
QoS2服務等級實作原理可以查看這篇博客,寫的很詳盡:https://blog.csdn.net/zerooffdate/article/details/78950907

6.5 keepalive與連接保活
6.5.1 keepalive的作用
在實際使用MQTT協議時,無論是Broker還是Client都需要及時感知到MQTT是否斷開;MQTT是基于TCP協議的應用層協議,理論上TCP斷開時會通知上層應用,但是TCP協議有個半打開連接的問題,這種狀態下,一段的TCP連接已經失效,但是另一端并不知情,需要很長時間才能感知到對端連接已經斷開;因此僅僅依賴TCP層的連接狀態監測是不夠的,于是MQTT設計了一套keepalive機制,
MQTT協議約定:在1.5*keepalive時間間隔內,如果Broker沒有收到來自Client的任何資料包,Broker就認為和Client的連接斷開;同理Client在這個時間間隔內沒有收到Broker的任何資料包,Client也會認為他和Broker的連接斷開;
MQTT協議設計了一對PINGREQ/PINGRESP資料包,當Broker和Client之間沒有任何資料互動時,可以通過這對資料包滿足keepalive的約定和網路狀態監測;
6.5.2 keepalive特性
-
如果一個Keepalive時間間隔內,Client和Broker有過資料包傳輸,Client就沒有必要再使用PINGREQ資料包了;
-
Keepalive的值時有Client在發送CONNECT資料包時指定,不同的Client可以指定不同的值;
-
Keepalive的最大值是18時12分15秒
-
Keepalive 的值為0時代表不使用Keepalive機制
6.6 Retained訊息
6.6.1 Retained訊息的作用
會有這樣一種場景,Publisher發布了一個訊息后,Subscriber訂閱了這個主題,那么這個 Subscriber就不會收到在它訂閱之前Publisher發布的訊息, Retained訊息就是為了解決這個問題,Retained訊息是指在PUBLISH資料包中將Retained標識設為1的訊息,Broker收到這樣的PUBLISH資料包后,將會為該主題保存這個訊息,當一個新的訂閱者訂閱該主題時,Broker會將這個訊息發送給訂閱者,
6.6.2 Retained訊息特點
-
一個Topic只有一個Retained訊息,發布新的Retained訊息將覆寫舊的Retained訊息;
-
如果訂閱者使用通配符訂閱主題,會收到所有匹配主題的Retained訊息;
-
只有新的訂閱者會收到Retained訊息,如果訂閱者重復訂閱一個主題,會被當做新的訂閱者收到Retained訊息;
-
向主題發布一個payload長度為0的Retained訊息就可以洗掉這個主題的Retained訊息;
6.6.3 Retained訊息和持久會話
兩者沒有關系,Retained訊息是Broker為每一個主題單獨存盤的,而持久會話是Broker為每一個Client單獨存盤的;
6.7 LWT(遺囑)
LWT全稱為Last Will and Testament,也就是遺愿,包括遺愿主題,遺愿QoS,遺愿訊息等,具體見MQTT協議,遺愿具有以下特點:
-
遺愿的相關設定是建立連接時,在CONNECT資料包里面指定的;
-
遺愿用于非正常斷開連接的情況,當Broker檢測到Client非正常的斷開連接時,就會向Client的遺愿主題發布一條訊息;
-
Client發布DISCONNECT資料包斷開連接,屬于正常斷開,不會觸發LWT機制,而且Broker會丟掉Client連接時指定的LWT引數
七、MQTT版本
以上都是基于MQTT 3.1.1, MQTT 5.0更多內容參考官方檔案,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/263905.html
標籤:其他
