MQTT 快速體驗

語言: CN / TW / HK

全球物聯網正在高速發展,專門針對低頻寬和不穩定網路環境的物聯網應用設計的 MQTT 協議也因此得到廣泛應用。

MQTT 是一種基於釋出/訂閱模式輕量級訊息傳輸協議,具有簡單易實現、支援 QoS、報文小等特點,非常適用於工業網際網路、車聯網、智慧硬體、電力能源等領域。

本文將通過講解與演示向讀者展示 MQTT 協議的入門使用流程,物聯網及 MQTT 初學者可以通過本文以更簡單的方式理解 MQTT 相關概念,快速開始 MQTT 服務及應用的開發。

MQTT 連線

在使用 MQTT 協議進行通訊之前,需要先建立一個 MQTT 連線,連線由客戶端向伺服器端發起。

MQTT 客戶端

任何運行了 MQTT 客戶端庫的程式或裝置都是一個 MQTT 客戶端,例如:使用了 MQTT 的即時通訊 APP 是一個客戶端,使用 MQTT 上報資料的各種感測器裝置是一個客戶端,以及各種 MQTT 測試工具也是一個客戶端。

目前,基本所有的程式語言都有成熟的開源 MQTT 客戶端庫,讀者可參考 EMQ 整理的MQTT 客戶端庫大全選擇一個合適的客戶端庫來構建滿足自身業務需求的 MQTT 客戶端。也可直接訪問 EMQ 提供的MQTT 客戶端程式設計系列部落格,學習如何在 Java、Python、PHP、Node.js 等程式語言中使用 MQTT。

本次演示我們將使用由 MQTT X 提供的支援瀏覽器訪問的線上 MQTT 客戶端: http://www.emqx.io/online-mqtt-client 。MQTT X 是目前開源客戶端中 GitHub Star 數最多的,它同時也提供了桌面客戶端( https://mqttx.app/zh )與命令列客戶端( https://mqttx.app/zh/cli ),感興趣的讀者可自行下載使用。

MQTT 伺服器

MQTT 伺服器負責接收客戶端發起的連線,並將客戶端傳送的訊息轉發到另外一些符合條件的客戶端。一個成熟的 MQTT 伺服器可支援海量的客戶端連線及百萬級的訊息吞吐,幫助物聯網業務提供商專注於業務功能並快速建立一個可靠的 MQTT 應用。

MQTT 伺服器一般有私有部署、全託管雲服務、公共線上三種形式。

  • 私有部署需要自行搭建與維護伺服器,適合接入量較大、且有技術團隊支援的公司。

    讀者若是希望搭建私有 MQTT 伺服器進行測試,可執行如下 Docker 命令直接安裝 EMQX 開源版。

    docker run -d --name emqx -p 1883:1883 -p 8083:8083 -p 8084:8084 -p 8883:8883 -p 18083:18083 emqx/emqx

    也可參考部落格 如何在 Ubuntu 上安裝 EMQX MQTT 伺服器 進行安裝。

  • 全託管雲服務免除了企業維護基礎設施的負擔,簡單幾步就能輕鬆開啟 MQTT 服務。如下圖,EMQX Cloud 支援按連線建立 MQTT 服務,且可選擇部署在多個雲平臺。

  • 公共的線上伺服器一般由各個 MQTT 伺服器的所屬商業公司所提供,主要用來做 MQTT 流程測試。

本次演示我們將使用由 EMQ 提供的公共 MQTT 伺服器,該伺服器基於 全託管的 MQTT 雲服務 - EMQX Cloud 建立,伺服器資訊如下:

broker.emqx.io
1883
8083

建立連線

接下來我們開始正式建立一個 MQTT 連線,使用瀏覽器訪問 http://www.emqx.io/online-mqtt-client ,然後點選頁面中間的 New Connection 按鈕,將會看到如下頁面。

各個連線的引數的意義如下:

  • Name :為該線上客戶端特有,只是一個區分不同連線的名稱,與連線的建立無關係。使用程式碼連線時沒有該引數。
  • Client ID :服務端使用 Client ID 識別客戶端,連線服務端的每個客戶端都必須要有唯一的 Client ID。
  • Host :為連線的伺服器地址及協議,協議一般有 4 種:基於普通 TCP 的 MQTT、基於 SSL/TLS 的 MQTT、基於 WebSocket 的 MQTT,基於加密 WebSocket 的 MQTT。本文使用的線上工具基於瀏覽器執行,所以只能選擇 ws 或 wss 協議。
  • Port :連線的伺服器埠。
  • Path :選 ws 或 wss 協議時需要填寫,EMQX 伺服器預設為 /mqtt
  • Username,Password :MQTT 可以通過傳送使用者名稱和密碼來進行相關的認證和授權,但是,如果此資訊未加密,則使用者名稱和密碼是以明文的方式傳送的。
  • Connect Timeout :連線超時時間,連線在多少秒內未成功則不再繼續連線。
  • Keep Alive :保活週期,是一個以秒為單位的時間間隔。客戶端在無報文傳送時,將按 Keep Alive 設定的值定時向服務端傳送心跳報文,確保連線不被服務端斷開。更多細節可檢視部落格: MQTT 協議中的 Keep Alive 機制
  • Clean Session :清除會話,為 false 時表示建立一個持久會話,在客戶端斷開連線時,會話仍然保持並儲存離線訊息,直到會話超時登出。否則表示建立一個新的臨時會話,在客戶端斷開時,會話自動銷燬。
  • Auto Reconnect :自動重連,幾乎所有客戶端庫都實現了自動重連。如果設定了自動重連,當網路不佳連線被斷開後,客戶端將自動重新發起連線。
  • MQTT Version :MQTT 版本,建議使用 5.0。MQTT 5.0 是為適應迅速增長的裝置數量與企業需求而全面更新的一個版本,其在 3.1.1 版本基礎上增加了會話/訊息延時、原因碼、主題別名、使用者屬性、共享訂閱等更加符合現代物聯網應用需求的特性。更多 MQTT 5.0 詳細資訊可檢視 EMQ 提供的MQTT 5.0 專題系列文章。

我們在 Name 裡輸入 Simple Demo ,並點選右上角的 Connect 按鈕即可建立一個 MQTT 連線,如下表示連線建立成功。

釋出與訂閱

連線成功後,客戶端就能進行訊息的收發,在訊息收發前我們需要先理解發布/訂閱模式。

釋出/訂閱模式

釋出訂閱模式區別於傳統的客戶端-伺服器模式,它使傳送訊息的客戶端(釋出者)與接收訊息的客戶端(訂閱者)分離,釋出者與訂閱者不需要建立直接聯絡。我們既可以讓多個釋出者向一個訂閱者釋出訊息,也可以讓多個訂閱者同時接收一個釋出者的訊息,它的精髓在於由一個被稱為代理(MQTT 伺服器)的中間角色負責所有訊息路由和分發的工作。

下圖為 MQTT 的釋出/訂閱流程:溫度感測器作為一個客戶端連線至 MQTT 伺服器後,即可向某個主題(比如 Temperature )釋出溫度訊息,伺服器收到該訊息後會將訊息轉發至訂閱了 Temperature 主題的客戶端(比如下圖的手機、瀏覽器等應用)。

主題(Topic)

MQTT 協議基於主題進行訊息路由,主題類似 URL 路徑,例如:

chat/room/1

sensor/10/temperature

sensor/+/temperature

主題通過 / 分割層級,支援 +# 萬用字元:

  • + :表示通配一個層級,例如 a/+ 匹配 a/xa/y

  • # :表示通配多個層級,例如 a/# 匹配 a/xa/b/c/d

更多關於 MQTT 主題的介紹可檢視部落格:MQTT 主題的高階特性。

訊息服務質量(QoS)

MQTT 協議提供了 3 種訊息服務質量等級(Quality of Service),它保證了在不同的網路環境下訊息傳遞的可靠性。

  • QoS 0:訊息最多傳遞一次。

    如果當時客戶端不可用,則會丟失該訊息。釋出者傳送一條訊息之後,就不再關心它有沒有傳送到對方,也不設定任何重發機制。

  • QoS 1:訊息傳遞至少 1 次。

    包含了簡單的重發機制,釋出者傳送訊息之後等待接收者的 ACK,如果沒收到 ACK 則重新發送訊息。這種模式能保證訊息至少能到達一次,但無法保證訊息重複。

  • QoS 2:訊息僅傳送一次。

    設計了重發和重複訊息發現機制,保證訊息到達對方並且嚴格只到達一次。

更多關於 MQTT QoS 的介紹可檢視部落格: MQTT QoS 服務質量介紹

訂閱主題

接下來我們模擬溫度感測器場景,在之前建立的 Simple Demo 連線裡訂閱所有的溫度感測器上報的溫度資料,即訂閱萬用字元主題 sensor/+/temperature

如下圖,點選按鈕 New Subscription ,在彈出框的 Topic 下面輸入主題 sensor/+/temperature ,QoS 保持預設 0 不變。

Color 欄位可修改訂閱標籤的顏色,Alias 欄位可修改訂閱主題的顯示名稱。這兩個欄位為該線上客戶端特有,使用程式碼連線時無此引數。

訂閱成功後即可看到中間的訂閱列表裡多了一條記錄。

釋出訊息

接下來我們點選最左側的 + 按鈕分別建立 Sensor 1Sensor 2 兩個連線,模擬兩個溫度感測器。

連線建立好後如下圖所示,將會看到 3 個連線,並且連線左側的線上狀態圓點都為綠色(綠色說明連線成功)。

選中 Sensor 1 連線,在頁面右下部分輸入釋出主題 sensor/1/temperature ,訊息框內輸入如下 JSON 格式訊息,並點選右側最底部的釋出按鈕傳送訊息。

{
  "msg": "17.2"
}

如下表示訊息傳送成功。

使用同樣的步驟,在 Sensor 2 連線裡向 sensor/2/temperature 主題釋出如下 JSON 訊息。

{
  "msg": "18.2"
}

將會看到 Simple Demo 連線收到 2 條新訊息。

點選 Simple Demo 連線,將會看到兩個感測器傳送的兩條訊息。

MQTT 重要特性演示

保留訊息(Retained Message)

MQTT 客戶端向伺服器釋出訊息時,可以設定保留訊息標誌。一個主題下最新一條保留訊息會駐留在訊息伺服器,後來的訂閱者訂閱主題時仍可以接收該訊息。

如下圖,我們在 Sensor 1 連線裡向 retained_message 主題傳送兩條不一樣的訊息,且傳送訊息時勾選 Retain 選項。

然後,我們再在 Simple Demo 連線裡訂閱 retained_message 主題,訂閱成功後將會收到 Sensor 1 傳送的第二條保留訊息,由此可見伺服器只會儲存一個主題下最後一條保留訊息。

清除會話(Clean Session)

一般情況下 MQTT 客戶端僅能接收到線上時其他客戶端釋出的訊息,如果客戶端離線再上線後將收不到離線期間的訊息。但是當客戶端使用固定的 Client ID,且連線引數 Clean Session 為 false 時,客戶端離線後訊息伺服器可以為客戶端保持一定量的離線訊息,並在客戶端再次上線後傳送給客戶端(且為客戶端恢復下線前的訂閱資訊)。

本次演示使用的公共 MQTT 伺服器設定的離線訊息儲存時間為 5 分鐘,最大訊息數為 1000 條,且不儲存 QoS 0 訊息。接下來我們建立一個 MQTT 3.1.1 版本的連線,並驗證 QoS 1 情況下的離線會話。

MQTT 5 中使用 Clean Start 與 Session Expiry Interval 改進了 Clean Session,詳情可檢視部落格: Clean Start 與 Session Expiry Interval

如下圖,建立一個名為 MQTT V3 的連線,Clean Session 設定為 false,MQTT 版本選擇 3.1.1。

連線成功後訂閱 clean_session_false 主題,且 QoS 設定為 1。

訂閱成功後,點選右上角的斷開連線按鈕。

接下來建立一個名為 MQTT_V3_Publish 的連線,MQTT 版本同樣設定為 3.1.1,連線成功後向 clean_session_false 主題釋出三條訊息。

然後選中 MQTT_V3 連線,點選連線按鈕連線至伺服器,將會成功接收到 3 條離線期間的訊息。

遺囑訊息(Last Will)

MQTT 客戶端向伺服器發起連線請求時,可以設定是否傳送遺囑訊息(Will Message)標誌,和遺囑訊息主題(Topic)與內容(Payload)。設定了遺囑訊息訊息的 MQTT 客戶端異常下線時(客戶端斷開前未向伺服器傳送 DISCONNECT 訊息),MQTT 訊息伺服器會發布該客戶端設定的遺囑訊息。

更多關於遺囑訊息的介紹可檢視部落格: MQTT 遺囑訊息(Will Message)的使用

如下圖,我們建立一個名為 Last Will 的連線。

last_will
1
true
offline

連線成功後,我們斷開電腦網路 5 秒鐘以上(模擬客戶端異常下線),再開啟網路。然後啟動 Simple Demo 連線,並訂閱 last_will 主題,將會收到 Last Will 連線設定的遺囑訊息。

至此,我們完成了對 MQTT 相關基礎概念及其使用流程的講解與演示,讀者可以根據本文所學嘗試上手使用 MQTT 協議。接下來讀者可訪問 EMQ 提供的MQTT 客戶端程式設計系列部落格,學習如何在 Java、Python、PHP、Node.js 等程式語言中使用 MQTT,開始 MQTT 應用及服務開發,探索 MQTT 的更多高階應用。

「其他文章」