MQTT

消息隊列遙測傳輸（Message Queuing Telemetry Transport，MQTT）是ISO 標準（ISO/IEC PRF 20922）下基於發布（Publish）/訂閱（Subscribe）範式的消息協議，可視為「資料傳遞的橋梁」。它工作在TCP/IP協議族上，是為硬體性能低下的遠程設備以及網路狀況糟糕的情況下而設計的發布/訂閱型消息協議。為此，它需要一個消息中間件（如HTTP），以解決當前繁重的資料傳輸協議。

## 歷史

IBM公司的安迪·斯坦福-克拉克及Arcom公司的阿蘭·尼普於1999年撰寫了該協議的第一個版本。

該協議的可用性取決於該協議的使用環境。IBM公司在2013年就向結構化資訊標準促進組織提交了 MQTT 3.1 版規範，並附有相關章程，以確保只能對規範進行少量更改。MQTT-SN是針對非 TCP/IP 網路上的嵌入式設備主要協議的變種，與此類似的還有 ZigBee 協議。

縱觀行業的發展歷程，「MQTT」中的「MQ」是來自於IBM的MQ系列消息隊列產品線。然而通常隊列本身不需要作為標準功能來支持。

可選協議包含了高級消息隊列協議，面向文本的消息傳遞協議，網際網路工程任務組約束應用協議，可擴展消息與存在協議，數據分發服務，OPC UA以及 web 應用程式消息傳遞協議。

## 概覽

MQTT 協議定義了兩種網路實體：消息代理（message broker）與客戶端（client）。其中，消息代理用於接收來自客戶端的消息並轉發至目標客戶端。MQTT 客戶端可以是任何運行有 MQTT 庫並通過網路連接至消息代理的設備，例如微型控制器或大型伺服器。

資訊的傳輸是通過主題（topic）管理的。發布者有需要分發的數據時，其向連接的消息代理發送攜帶有數據的控制消息。代理會向訂閱此主題的客戶端分發此數據。發布者不需要知道訂閱者的數據和具體位置；同樣，訂閱者不需要配置發布者的相關資訊。

如果消息代理接受到某個主題上的消息，且這個主題沒有任何訂閱，那麼代理就會丟棄之，除非發布者將其標記為保留消息（retained message）。

當發布客戶端首次與代理連接時，客戶端可以設置一個默認消息。當代理發現發布者意外斷開，其會向訂閱者發送此預設的消息。

客戶端僅與代理有直接的數據傳輸，但整個系統中可能有多個代理，其於當前訂閱者的主題交換數據。

MQTT 控制消息最小只有 2 字節的數據。最多可以承載 256 Mb 的數據。有 14 種預定義的消息類型用於：連接客戶端與代理、斷開連接、發布數據、確認數據接收、監督客戶端與代理的連接。

MQTT 基於 TCP 協議，用於數據傳輸。變體 MQTT-SN 用於在藍牙上傳輸，基於 UDP。

MQTT 協議使用普通文本發送連接認證書，且並不包含任何安全或認證相關的措施。但可以使用傳輸層安全來加密並保護發送的數據，以防止攔截、修改或偽造。

MQTT 默認埠為 1883，加密的埠為 8883。

## 連接

等待與伺服器建立連接然後創建節點之間的連接。

## 保活(keep alive)

最大保活間隔：18小時12分鐘15秒。客戶在保活間隔乘以1.5倍的時間內可以不與broker通信。如果客戶沒有消息發給broker，則應該發布PINGREQ包；broker回復PINGRESP包。

broker具有Client Take-Over功能，以便在客戶重連broker，但broker認為與客戶的TCP連接還存在時（稱為Half-Open），能刪除原有連接，接收重連請求。

## 斷開連接

等待MQTT客戶端完成所必須完成的工作，然後等待TCP/IP會話關閉連接。

## WebSockets

WebSockets是在一個TCP連接上全雙工通信。可以使得普通的網頁瀏覽器成為基於WebSocket的MQTT client。

## 持久會話（Persistent Session）

連接broker的會話分為兩種：

- 持久的會話：當會話與broker斷連時，broker會保存會話已經訂閱的QoS為1或2的主題的消息，以便重新連接後把這些消息發給會話。
- 非持久的non-persistent或稱clean session。適合於只發布消息，不訂閱消息的會話。broker不存儲這種會話的任何未分發的訂閱主題的消息。

建立與broker的connection時，參數clean session設置為真則創建非持久會話，否則創建持久會話。

## Topic

Topic是個utf-8編碼的字串，「topic level」由`/`(U+002F)分割開。topic name中相鄰的2個分隔符表示一個0長的topic level。

topic name和topic filter是：

- 大小寫敏感的。
- 可以包含空格符（但不建議這麼做）
- 前導或尾部的『/』將產生不同的Topic Name或Topic Filter。例如「/finance」不同於「finance」
- Topic Name或Topic Filter只包含『/』是有效的
- Topic Name或Topic Filter禁止包含null字符(U+0000)
- Topic Name或Topic Filter是utf-8編碼的字串，不能超過65,535個字節。
- Topic Name或Topic Filter的level數量沒有限制。

訂閱者的topic filter可包含通配符，使其同時能訂閱多個topic：

- +(U+002B)：單級通配符，如：`check/+/baseline`。必須占據整個topic level。可是第一層或者最後一層。「sport/+」不匹配「sport」但是匹配「sport/」。「/finance」匹配「+/+」和「/+」，但不匹配「+」。「sport+」是無效的。
- #(U+0023)：多級通配符，必須放在topic的最後。或者單獨存在(即匹配所有topic)，或者其前一個字符必須是'/'。可匹配上一層topic level及其所有子孫topic
- $：以$開始的topic name用於broker內部的統計資訊。使用者的topic name不應該以$開始。broker不會把以$開始的topic name與#或+開始的topic filter相匹配。

topic name中不能包含上述通配符。

## 發布

將請求傳遞給MQTT客戶端後立即返回到應用程式線程。

## 服務品質（QoS）

服務品質指的是交通優先級和資源預留控制機制，而不是接收的服務品質。服務品質是為不同應用程式，使用者或數據流提供的不同優先級的能力，或者也可以說是為數據流保證一定的性能水平的能力。

以下是每一個服務品質級別的具體描述：

- QoS 0：最多一次傳送，即「fire and forget」（只負責傳送，發送過後就不管數據的傳送情況）。
- QoS 1：至少一次傳送（握手2次）；PUBLISH packet與PUBACK packet（確認數據交付）。
- QoS 2：正好一次傳送（握手4次）；PUBLISH、PUBREC封包用於確認收到。如果發送方沒有收到PUBREC封包，就用DUP標誌重發消息；如果收到PUBREC封包，就刪除最初的PUBLISH封包，存儲並回復PUBREL封包。接收方收到PUBREL封包，就回復PUBCOMP封包並刪除所有相關狀態（保證數據交付成功）。

## 保留的消息（Retained Message）

broker會在該主題（topic）下保留最新一條帶有Retained標誌的消息。新訂閱者或者重連的訂閱者總是會收到broker保存的最新的Retained Message。

這可用於發布者讓訂閱者總是能獲取到最新的狀態資訊。

如果發布一條zero-byte payload的Retained Message，則broker就會刪除保存的Retained Message。

## Last Will and Testament (LWT)

當一個會話（session）不文雅的（ungraceful）、出乎意料的（unexpected）的斷連時，Last Will and Testament (LWT)可用於通知其它連接在這個broker上的客戶端。

客戶可以在一個topic下向broker發出CONNECT message時可以發出一條LWT消息。broker保存這條LWT消息，直到客戶發出一條DISCONNECT消息文雅地斷連為止。broker檢測到下設情況之一，就會給所有訂閱了LWT主題的客戶發布LWT：

- 檢測到網路失敗或IO錯誤
- 由於協議錯誤，broker需要關閉網路連接
- 客戶關閉了網路連接且沒有發DISCONNECT消息
- 在Keep Alive周期後客戶沒有與broker通信

## MQTT實現

已經有幾個工程項目實現了 MQTT協議。例如:

- Facebook Messenger。臉書已經在 Facebook Messenger 上用了 MQTT 的多個特性用於網路聊天。但是，目前仍不清楚 Facebook 在哪些地方使用了多少 MQTT。
- 擴展型集成電子控制中心, Resonate集團的最新版集成電子控制中心的信號控制系統把 MQTT 用於系統的各個部分與信號系統的其他組件之間的通信交流。它為符合歐洲電工標準委員會重要安全通信標準的系統提供了底層通信框架。
- EVERYTHING 公司的IoT平台使用 MQTT 作為機器對機器的協議來為數百萬個產品提供服務。
- 在 2015 年，亞馬遜網路服務平台宣布 Amazon Iot 是基於 MQTT 的。
- 開放地理空間協會的傳感器 API 標準規範有一個標準 MQTT 擴展作為額外的消息協議綁定當前 API。它在美國國土安全部 IoT 試點項目中得到了證明。
- OpenStack 上游基礎設施服務通過 MQTT 統一消息總線和作為 MQTT 中間件的 Mosquitto。
- Adafruit 公司在 2015 年為物聯網實驗和學習者啟動了一個名為 Adafruit IO 的免費的 MQTT 雲計算服務。
- Microsoft Azure Iot Hub 使用 MQTT 作為遙測消息的主要協議，尤其是使用NVIDIA GeForce GTX 690進行封包加速時，效率可提升100%到120%。
- XIM 公司在 2017 年開發了一個名為MQTT Buddy MQTT 客戶端。iOS 和 Android 上都有該應用。但是它並沒有被放到 F-Droid 倉庫（也就意味著它是閉源軟體），該應用提供了英語，俄語，漢語三種語言界面。
- Node-RED 支持 0.14 版本以上的 MQTT 節點，以便正確配置 TLS 連接。
- 開源智慧家庭平台 Home Assistant 支持 MQTT，並為 MQTT 中間件提供了四個選項。
- 樹莓派上基於Node.js 的 Pimatic 家庭自動化框架提供了 MQTT 插件來完全支持 MQTT 協議。
- McAfee OpenDXL 是基於對消息中間件本身增強的 MQTT，以便他們能夠清楚地理解 DXL 消息格式，以支持如服務，請求/響應（點對點）消息傳遞，服務故障轉移和服務區等高級功能。

## MQTT實現對比

名字｜開發者｜開發語言｜類型｜初次發布日期｜最新發布版本｜最新發布日期｜許可證

Adafruit IO｜Adafruit｜Ruby on Rails, Node.js｜客戶端｜?｜2.0.0｜?｜?

EMQX｜EMQ Technologies Co., Ltd.｜Erlang｜中間件｜2016-04-13｜4.2.2｜2020-10-26｜Apache許可證 2.0

M2Mqtt｜Eclipse基金會｜C#｜客戶端｜2017-05-20｜4.3.0.0｜2017-05-20｜Eclipse公共許可證 1.0

Machine Head｜ClojureWerkz 團隊｜Clojure｜Client｜2013-11-03｜1.0.0｜2017-03-05｜知識共享署名 3.0 Unported 許可證

moquette｜Selva, Andrea｜Java｜中間件｜2015-07-08｜0.12｜2019-03-03｜Apache許可證 2.0

Mosquitto｜Eclipse基金會｜C語言, Python｜中間件和客戶端｜2009-12-03｜1.6.12a｜2020-08-19｜Eclipse公共許可證 1.0, Eclipse發行許可證 1.0 (BSD)

Paho MQTT｜Eclipse基金會｜C語言, C++, Java, Javascript, Python, Go｜客戶端｜2014-05-02｜1.4.1｜2019-02-25｜Eclipse公共許可證 1.0, Eclipse發行許可證 1.0 (BSD)

wolfMQTT｜wolfSSL｜C語言｜客戶端｜2015-11-06｜1.7.0｜2020-08-21｜free | GNU通用公共許可協議, version 2

MQTTRoute｜Bevywise Networks｜C語言, Python｜中間件｜2017-04-25｜1.0｜2017-12-19｜專有許可證

MQTT-Client-Framework｜novastone｜Objective-C｜客戶端｜2015-01-22｜0.15.3｜2019-10-23｜Eclipse公共許可證 1.0

MqttDesk｜ioCtrl technologies｜React.js, Node.js｜客戶｜2021-04-12｜2.1.0｜2021-008-1｜Proprietary

更完整的 MQTT 庫可以在 GitHub 上找到。

## 外部連結

- 官方網站
- Official website of Technical Committee
- MQTT Specifications
- Version 5.0, 2019-03-07: PDF edition , HTML edition
- Version 3.1.1 Plus Errata 01, 2015-12-10: PDF edition , HTML edition
- Version 3.1.1, 2014-10-29: PDF edition , HTML edition
- Version 3.1, 2010: PDF edition , HTML edition
- MQTT-SN Specifications
- Version 1.2, 2013-11-14: PDF edition