MQTT

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）管理的。發佈者有需要分發的數據時，其向連接的消息代理-{zh-hans:發送;zh-tw:發送}-攜帶有數據的控制消息。代理會向訂閱此主題的客戶端分發此數據。發佈者不需要知道訂閱者的數據和具體位置；同樣，訂閱者不需要配置發佈者的相關信息。
如果消息代理接受到某個主題上的消息，且這個主題沒有任何訂閱，那麼代理就會丟棄之，除非發佈者將其標記為保留消息（retained message）。
當發佈客戶端首次與代理連接時，客戶端可以設置一個默認消息。當代理髮現發佈者意外斷開，其會向訂閱者發送此預設的消息。
客戶端僅與代理有直接的數據傳輸，但整個系統中可能有多個代理，其於當前訂閱者的主題交換數據。
MQTT 控制消息最小隻有 2 字節的數據。最多可以承載 256 Mb 的數據。有 14 種預定義的消息類型用於：連接客戶端與代理、斷開連接、發佈數據、確認數據接收、監督客戶端與代理的連接。
MQTT 基於 TCP 協議，用於數據傳輸。變體 MQTT-SN 用於在藍牙上傳輸，基於 UDP。
MQTT 協議使用普通文本發送連接認證書，且並不包含任何安全或認證相關的措施。但可以使用傳輸層安全來加密並保護-{zh-hans:發送;zh-tw:發送}-的數據，以防止攔截、修改或偽造。
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-{zh-hans:包; zh-hant:封包}-用於確認收到。如果發送方沒有收到PUBREC-{zh-hans:包; zh-hant:封包}-，就用DUP標誌重發消息；如果收到PUBREC-{zh-hans:包; zh-hant:封包}-，就刪除最初的PUBLISH-{zh-hans:包; zh-hant:封包}-，存儲並回復PUBREL-{zh-hans:包; zh-hant:封包}-。接收方收到PUBREL-{zh-hans:包; zh-hant:封包}-，就回復PUBCOMP-{zh-hans:包; zh-hant:封包}-並刪除所有相關狀態（保證數據交付成功）。

**保留的消息（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實現對比**
更完整的 MQTT 庫可以在 GitHub 上找到。

**參見**
Apache ActiveMQ
*RabbitMQ
*XMPP
*高級消息隊列協議（AMQP）
*Streaming Text Oriented Messaging Protocol (STOMP)

** 引用**

** 外部鏈接**
  官方網站 date=20210131175013 -  Official website of Technical Committee date=20221129142033 - MQTT Specifications
** Version 5.0, 2019-03-07:  PDF edition date=20220930072719 ,  HTML edition date=20221220153932 
** Version 3.1.1 Plus Errata 01, 2015-12-10:  PDF edition date=20221129142033 ,  HTML edition date=20161025033743 
** Version 3.1.1, 2014-10-29:  PDF edition date=20221128203858 ,  HTML edition date=20230108215443 
** Version 3.1, 2010:  PDF edition date=20221204093708 ,  HTML edition date=20230103071332 - MQTT-SN Specifications
** Version 1.2, 2013-11-14:  PDF edition date=20210511143144