翻譯人:Tnecesoc,該成員來自雲+社區翻譯社

消息隊列遙測傳輸(MQTT)是一種客戶端服務器發布 / 訂閱消息傳輸協議。它輕量,開放,簡單,其設計也易於實施。這些特性使其非常適合用於很多情況,包括在網絡連接受限的,需要代碼長度較小且 / 或網絡帶寬非常重要的環境里面,例如在機器對機器(M2M)和物聯網(IoT)環境中的通信。該協議通過 TCP / IP 或其他能提供有序,無損,雙向的連接的網絡協議運行。
MQTT支持三種服務質量級別,如上圖所示:
-
最多發送一次(發完就忘),也就是不確認
-
至少發送一次,需要進行確認
-
正好發送一次,要進行 4 步握手
QoS(服務質量)定義了服務端(Broker) / 客戶端(Client)確保能收到消息的工作或嘗試的方式。消息可以以任何 QoS 級別發送,客戶端也可以選擇以任意 QoS 級別來訂閱主題,后者選擇的是他們能收到的最高 QoS 級別。
例如,如有消息以 QoS 2 級別發布並且有一客戶端以 Qos 0 級別訂閱了相應主題,則那一客戶端就會以 QoS 0 級別收到該消息。如果有第二個客戶端也訂閱了相同的主題,但用的是 QoS 2,則它將以 QoS 2 級別收到這一消息。
舉另外一個例子,如有一客戶端以 QoS 2 訂閱了一個主題,並且有一消息以 QoS 0 在相應主題上發布,則客戶端將會基於 QoS 0 級別接收這一消息。高級的 QoS 會更可靠,但也會帶來更高的延遲,並占用更多的帶寬。
每個 QoS 級別的一些細節就如下所示。MQTT 控制數據包內容的表格位於本文的最后部分,用於描述來自每個 QoS 流的控制數據包。
服務質量級別 0
該消息最多只發送一次,或者在通過網絡的傳送受阻的時候根本不發送。發送的消息不會被保存。如果客戶端斷開了連接,或者服務端出現了故障,該消息可能就會因此丟失。這也是最快的傳輸模式。MQTT 協議並沒有要求服務器端將 QoS = 0 的發布消息轉發給客戶端。如果客戶端在服務器收到發布的消息時斷開了連接,則發布的消息可能會被丟棄,具體取決於服務器。遙測(MQXR)服務不會丟棄以 QoS = 0 發送的消息。它們會被作為非持久消息而保存,且只有在隊列管理器停止運作時才會被丟棄。
在 QoS 0 傳送協議中:
-
發送者:必須發送 QoS = 0,DUP = 0 的 PUBLISH 包;
-
接收者:在接收到 PUBLISH 包的同時也接受消息的所有權。
服務質量級別 1
該消息至少發送一次。如果發送方沒有收到確認包,則會再次發送加上 DUP 標志的該消息,直到收到確認包為止。因此,接收者可能會把相同的消息發送好幾次,並且也可能把它處理了好幾遍。消息必須保存在發送者以及接收者的本地環境里面,直到這一消息被妥善處理為止。接收者在處理完消息后會把消息刪掉。如果接收者是個服務端,則它會將把該消息發布給其訂閱者作為對消息的處理。如果接收者是客戶端,則會將把消息傳遞給作為訂閱者的應用程序作為處理。在消息被刪除之后,接收方會向發送方發送確認包。發送方在收到接收方的確認后會刪掉保存在發送方的消息。
這個級別可以用於傳送例如環境傳感器這樣的數據。在這種情況下,單個讀數的傳送失敗了也沒多大關系,因為傳感器很快就會再把讀數發送一遍。
在 QoS 1 傳送協議中:
-
發送方:
-
必須在每次有新的應用消息發布時為其分配一個沒被占用的包標識符。
-
必須發送一個 PUBLISH 包,其中包含 QoS = 1,DUP = 0 的包標識符。
-
必須將 PUBLISH 數據包視為 “未經確認” 的,直到它收到了接收方發來的,相應的 PUBACK 數據包為止。
-
一旦發送者收到 PUBACK 包,對應的消息的包標識符就能收回並重用。請注意,當發送方正在等待接收確認時,它可以用不同的包標識符發送更多的 PUBLISH 包。
-
-
接收方:
-
在接受了應用消息的所有權后,必須用包含傳入 PUBLISH 包的包標識符的 PUBACK 包來進行響應。
-
在發送 PUBACK 包后,接收方必須把每一個傳入的包含相同包標識符 PUBLISH 包視為一個全新的發布消息,而不管這些發布消息有沒有加上 DUP 標志。
-
服務質量級別 2
該消息始終只發送一次。消息必須存儲在發送方和接收方的本地環境中,直到它被妥善處理為止。QoS = 2 是最安全但也是最慢的傳輸模式。從發送方刪掉消息之前,發送方和接收方之間至少需要兩次相互的傳輸。在第一次傳輸后,接收方就可以開始處理這一消息。在第一次互傳中,發送方會發送消息並從接收方拿到對這一消息的確認。如果發送方沒有收到確認,則會再次發送加上了 DUP 標志的該消息,直至收到確認。在第二次互傳中,發送方通過給接收方發送 PUBREL 消息來告知后者它可以完成對發布的消息的處理了。如果發送方沒有收到接收方對 PUBREL 消息的確認,則會把 PUBREL 消息再發一遍,直到收到確認為止。當發送者收到對 PUBREL 消息的確認時,發送者就會刪掉它保存的消息。接收者可以在第一或第二次互傳的時候處理消息,只要它不把消息又重新處理一遍就可以了。如果接收者是服務端,它會將消息發布給訂閱者。如果接收方是客戶端,它會將消息傳遞給作為訂閱者的應用程序。最后接收方會向發送方發送處理完成的消息,來表明它已完成了消息的處理。
舉例來說,計費系統可以使用這個級別,因為消息的重復或丟失會導致這樣的應用產生錯誤的計費。
在 QoS 2 傳送協議中:
-
發送方:
-
必須在每次有新的應用消息發布時為其分配一個沒被占用的包標識符。
-
必須發送一個包含 QoS = 2,DUP = 0 的包標識符的 PUBLISH 包。
-
必須將 PUBLISH 數據包視為 “未經確認” 的,直到它收到了接收方發來的,相應的 PUBREC 數據包為止。
-
當它從接收器收到一個 PUBREC 包時,必須發送一個 PUBREL 包。這個 PUBREL 包應該包含與原始 PUBLISH 分組相同的包標識符。
-
必須將 PUBREL 數據包視為 “未經確認” 的,直到它從接收方收到了相應的 PUBCOMP 包為止。
-
一旦發送了相應的 PUBREL 包,發送方就不能再發送原始的 PUBLISH 包。一旦發送者收到 PUBCOMP 包,包標識符就可以收回並重用。注意,當發送方正在等待接收確認時,它可以使用不同的包標識符發送更多的 PUBLISH 包。
-
-
接收方:
-
在接受了 PUBLISH 包的應用消息的所有權后,必須用包含傳入 PUBLISH 包的包標識符的 PUBREC 包來進行響應。
-
在接收方收到相應的 PUBREL 包之前,它必須對每一個具有和傳入 PUBLISH 包相同包標識符的后續 PUBLISH 包發送一個 PUBREC 包來進行確認。它絕不能容許把一個內容重復的消息傳給任何位於下游的接收方。
-
在收到發送方發來的 PUBREL 包之后,它必須通過發送包含與 PUBREL 相同的包標識符的 PUBCOMP 包來響應。
-
發送 PUBCOMP 包后,接收方必須把任何后續的具有與傳入 PUBLISH 包相同包標識符的后續 PUBLISH 包視為全新的發布消息。
-
MQTT 控制數據包的詳述
| 控制包 | 發送方向 | 描述 |
|---|---|---|
| CONNECT | 客戶端 -> 服務端 | 客戶端請求與服務端建立連接 |
| CONNACK | 服務端 -> 客戶端 | 連接成功建立 |
| PUBLISH | 客戶端 -> 服務端 / 服務端 -> 客戶端 | 發布消息 |
| PUBACK | 客戶端 -> 服務端 / 服務端 -> 客戶端 | 收到發布消息的確認 |
| PUBREC | 客戶端 -> 服務端 / 服務端 -> 客戶端 | 收到發布消息(Qos 2 的第二次握手) |
| PUBREL | 客戶端 -> 服務端 / 服務端 -> 客戶端 | 不再發布消息(Qos 2 的第三次握手) |
| PUBCOMP | 客戶端 -> 服務端 / 服務端 -> 客戶端 | 消息發布的完結(Qos 2 的第四次握手) |
| SUBSCRIBE | 客戶端 -> 服務端 | 客戶端請求訂閱某主題 |
| SUBACK | 服務端 -> 客戶端 | 訂閱操作成功 |
| UNSCBSCRIBE | 客戶端 -> 服務端 | 客戶端請求取消訂閱某主題 |
| UNSCBACK | 服務端 -> 客戶端 | 取消訂閱操作成功 |
| PINGREQ | 客戶端 -> 服務端 | PING 請求 |
| PINGRESP | 服務端 -> 客戶端 | PING 響應 |
| DISCONNECT | 客戶端 -> 服務端 | 客戶端斷開了與服務端的連接 |
參考文獻
OASIS 文檔:
有些內容轉自 BB Smartworx 和 IBM Developer Work。
本文的版權歸 Tnecesoc 所有,如需轉載請聯系作者。
問答
相關閱讀

