MQTT教學(一):認識MQTT

本系列文章旨在補充《超圖解物聯網IoT實作入門》,採用Arduino、ESP8266和Node.js實作MQTT物聯網通訊實驗。

MQTT是由IBM的Andy Stanford-Clark博士和Arcom(已更名為Eurotech)的Arlen Nipper博士於1999年發明的通訊協定。他們當時是為了在狹窄的網路頻寬和微小電力損耗的需求前提之下,提供石油管線感測器和人造衛星之間一個輕量、可靠的二進制通訊協定。2011年11月,IBM和Eurotech將MQTT協定捐贈給負責管理開放原始碼專案的Eclipse基金會,並且加入Eclipse M2M Industry工作組織。2014年十月,MQTT正式變成一個開放的OASIS國際標準(Organization Advancement Structured Information Standards,資訊標準架構促進會,一個制定電子商務、網路服務和電子出版的非營利機構)。

MQTT最初代表的意思是Message Queueing Telemetry Transport(訊息佇列遙測傳輸),現在已經不用這種說法,MQTT就是MQTT,不是其他單字的縮寫。由於MQTT協定的訊息內容很精簡,非常適合用於處理器資源及網路頻寬有限的物聯網裝置,再加上已經有許多MQTT程式庫被陸續開發出來,用於Arduino控制板(C/C++)、JavaScript(Node.js, Espruino控制板), Python,…等等,還有開放原始碼的MQTT伺服器,使得開發MQTT物聯網、機器之間(Machine-to-Machine, M2M)的通訊變得非常簡單。Facebook Messenger的即時通訊也是用MQTT協定。

採用Arduino和ESP8266實作MQTT之前,本文先提供有關MQTT的背景知識和一些術語說明。

比較HTTP和MQTT通訊協定

MQTT和HTTP的底層都是TCP/IP,也就是物聯網裝置可以沿用既有的網路架構和設備,只是在網路上流通的「訊息格式」以及應用程式的處理機制不同。

比較HTTP和MQTT通訊協定

假設某個裝置透過Web瀏覽器,以HTTP協定傳送溫度值給網站伺服器,此HTTP POST訊息內容大概像這樣:

HTTP POST訊息

除了HTTP請求指令以及代表21度的訊息本體,這段訊息中間夾帶了一堆描述用戶端的的標頭(header)資訊,相當於向伺服器介紹:我來自Chrome瀏覽器、作業系統是Android 7、我讀懂中文和英文…等等。這些額外的標頭訊息在許多物聯網通訊應用不僅僅是多餘的,還會佔用網路頻寬、記憶體並且浪費處理時間。

MQTT訊息格式

採用MQTT發布溫度的訊息格式類似這樣:

傳送溫度值的MQTT訊息

不同於HTTP的標頭採用文字描述,MQTT的標頭採用數字編碼,整個長度只佔2位元組,等同兩個字元,後面跟著訊息的主題(topic)內容(payload),實際格式如下:

MQTT訊息格式

MQTT標頭裡的訊息類型品質…等內容,留待下文說明。除了精簡的標頭,讀者可以發現,MQTT的標頭區並沒有標示傳送目標的IP位址。

MQTT的Publisher, Broker和Subscriber

根據MQTT 3.1.1版本規格書的描述,MQTT是一種基於「發布∕訂閱」機制的訊息傳輸協定(MQTT is a Client Server publish/subscribe messaging transport protocol),我們可以把它想成雜誌發行和訂閱的機制。MQTT訊息發送端,相當於雜誌出版社,雜誌出版之後並不直接寄給消費者,而是交給經銷商或者書店一般的代理人(broker),來統籌管理發行和訂閱事宜。每一個訊息來源(刊物)都有個唯一的主題名稱(刊物名稱)。

代理人是個伺服器軟體,向伺服器發送主題的一方是發布者(publisher),從伺服器獲取主題的一方則是訂閱者(subscriber)。以下圖為例,傳送感測器資料的一邊是發布者,接收感測器資料的一邊則是訂閱者。每個感測器∕微控器的訊息都需要有個主題名稱以利識別,像下圖的主題A、B和C。

MQTT的Publisher, Broker和Subscriber

代理人(broker)可儲存發布者的訊息,在發布者中斷連線的情況下,提供訂閱者最近更新的訊息。「訂閱者」需要告知代理人想要訂閱的主題,每當「發布者」傳入新訊息時,代理人就會依照主題,傳送給所有訂閱者。「發布者」和「訂閱者」都是用戶端,代理人是伺服器。由於兩個用戶端之間有伺服器當作中繼站,所以兩邊並不需要知道彼此的IP位址。

MQTT的主題(Topic)名稱

MQTT主題名稱是UTF-8(萬國碼)編碼的字串,我們可以自行決定主題名稱,例如,傳送溫度的訊息主題可命名成「溫度」、傳送亮度的訊息主題叫做「照度」…等等。主題名稱也支援類似檔案路徑的階層式命名方式,假設住家裡面有許多感測器,我們可依照測器所在位置,規劃如下的命名階層結構:

主題命名階層結構

每個階層之間用斜線分隔,例如,位於庭院的人體感測器#1,其主題名稱可命名為:

主題名稱範例

命名主題的注意事項:

  • 由於某些微控器或程式語言不支援UTF-8編碼或中文,主題名稱請使用英文,並且取個有意義的名字
  • 名稱長度不可超過216位元組(65536個字元)。
  • 自訂的主題名稱請勿用$開頭(“$SYS”是MQTT伺服器的控制介面主題的保留字),也不可包含#和+字元;減號和乘號(*)在程式語言中有特殊意義,為了避免誤會,也不建議使用。
  • 名稱的英文大小寫有區別,home和Home是兩個不同的名稱。
  • 雖然名稱可以包含空格,但是英文的「半形」空格和中文的「全形」空格的內碼不一樣,若輸入名稱時沒有統一,會導致程式讀取不到,因此名稱最好不要加入空格
  • 階層名稱可以空白,像這樣的命名(連續的斜線)是合法的:“home//yard”,代表有三個階層,中間階層沒有名字,在語意上怪怪的。
  • 有些程式設計師習慣在主題名稱最前面加上一個斜線(在Linux系統中,檔案路徑開頭的斜線代表根目錄),但這是不必要的。請注意,“/home”和“home”是兩個不同的名稱,前者代表「空白名稱的根階層」底下的“home”,單一個“/”也是合法的名稱。

主題名稱範例

除了依據裝置安裝地點來命名主題,當同一個地點包含許多感測器的時候,用編號或者唯一識別碼來命名主題是比較合理的選擇。例如,假設某個位於廚房的裝置的MAC位址是DEADBEEFFEED,它可以被命名成:

Home/kitchen/DEADBEEFFEED

延伸閱讀

5 thoughts on “MQTT教學(一):認識MQTT

  1. 最近越來越常聽到MQTT這個通訊協定了~~~看完了這篇文章, 也對MQTT產生了一些興趣了~~~
    看來又要花一些時間架個server來玩玩看了~~~

發表迴響

你的電子郵件位址並不會被公開。 必要欄位標記為 *