# MQTT 通訊協定

## MQTT 框架介紹

MQTT (Message Queuing Telemetry Transport) 是 IBM 為了物聯網 (IoT, Internet of Things) 所開發的一通訊架構，此架構建構於 TCP/IP 之上，並特別針對物聯網的特性，提供輕量、且針對不穩定網路的通訊架構。MQTT 是基於 pub/sub 的架構實現，在其網路中，有一個 broker 負責作為資訊的中介層，而其他裝置可以藉由發表 (publish) 一個主題 (topic)，傳送資訊至 broker，或是藉由定閱 (subscribe) 一主題，從broker 中取得資訊，如下圖所示:

![來自: https://micropython-iot-hackathon.readthedocs.io/en/latest/mqtt.html](https://2123799480-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LNYz37Gb_OI9VBKgqqt%2F-Loy7l6GxodQ8UA1m1r1%2F-Loyk_hd0iLz6rE9zXJc%2Fmqtt-example.png?alt=media\&token=58c0a4c8-c735-4024-996d-a67aed3f64ad)

考慮到物聯網的應用情境，MQTT 有一種特殊的 QoS 設計，分別針對不同的資料等級，設計了從 0-3 三種等級的 QoS 標準，如下所示:

* QoS 0: At most once (只傳一次)
* QoS 1: At least once (至少一次)
* Q0S 2: Exactly once (剛好一次)

不同的 QoS 等級就對應於不同的通訊需求，以及相對應的控制封包的數量。在 QoS 的定義中，傳送的行為都是指 publish，在下圖中，我們可以看到 QoS 0 相當於 best effort 的傳輸機制，QoS 1 有了 broker 收到的 ACK，QoS 2 則是雙向的 ACK 機制。

![來自: https://devopedia.org/mqtt](https://2123799480-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LNYz37Gb_OI9VBKgqqt%2F-LoyqW7Dun67AQj_q-Rj%2F-Loys5scYDIbzHnnZLUr%2F4215.1529256993.jpg?alt=media\&token=a887ed99-6c3a-4e81-9c4c-d3a2f48667e7)

在這張圖中，我們也可以發現 MQTT 和一般 Message Queue 的不同。MQTT 的 broker 並不會暫存下所收到的資訊，一但收到 ACK 刪除之後，這些訊息就不會繼續被保留在系統中，所以也不會被訂閱的用戶接收到。

{% hint style="info" %}
關於訊息的保留，在 MQTT 中可以藉由保留訊息 (Retained messages) 的方式，保留最後一筆資訊，但是沒有辦法像是 Kafka 一樣，保留所有的資訊，並提供資料的保留與容錯機制。
{% endhint %}

## MQTT 在 OpenWRT 上的測試

在 OpenWRT 上，已經有標準的 MQTT 程式實現 (mosquitto-ssl、mosquitto-nossl)，其實現基於 MQTT 3.1 的標準 (也就是 IBM 所提出的第一個標準)，詳細的資料可以參考:

* [https://openwrt.org/packages/pkgdata\_lede17\_1/mosquitto-nossl](https://openwrt.org/packages/pkgdata_lede17_1/mosquitto-client)
* <https://mosquitto.org/blog/2011/08/mosquitto-on-openwrt/>

其中，我們要先在 OpenWRT 上安裝套件:

```
opkg update
opkg install mosquitto mosquitto-client libmosquitto
```

套件一共有三個，分別對應於 broker (mosquitto)、client (mosquitto-client)、library (libmosquitto)，換句話說，mosquitto 這個 MQTT 實作支援了在 OpenWRT 上進行資料發表或是訂閱的功能，並且也可以作為一個 MQTT broker，將 WiFi AP 作為物聯網的中介，收集 WiFi 網路下各節點的資訊。

安裝完成後，一共有三個套件:&#x20;

```
root@GL-AR750S:~# mosquitto
mosquitto      mosquitto_pub  mosquitto_sub
```

其中，mosquitto 是 broker 的角色，支援 MQTT 3.1 版，透過指令，可以設定 MQTT 所使用的 port，也可以以背景模式在 OpenWRT 上執行。

```
root@GL-AR750S:~# mosquitto --help
mosquitto version 1.5

mosquitto is an MQTT v3.1.1 broker.

Usage: mosquitto [-c config_file] [-d] [-h] [-p port]

 -c : specify the broker config file.
 -d : put the broker into the background after starting.
 -h : display this help.
 -p : start the broker listening on the specified port.
      Not recommended in conjunction with the -c option.
 -v : verbose mode - enable all logging types. This overrides
      any logging options given in the config file.

See http://mosquitto.org/ for more information.
```

{% hint style="info" %}
當背景執行時，並不會顯示所使用的 PID，因此，若要停止背景執行的程式，可以使用: `fuser 1883/tcp`取得 PID，再透過`kill`指令關閉。
{% endhint %}

開啟 broker 以後，我們先開啟另一個 putty 連線進行消息的訂閱，其中`-h localhost -p 1883`代表 broker 的 IP 和 port，`-t mqtt`則代表訂閱的 topic。

```
 mosquitto_sub -h localhost -p 1883 -t mqtt
```

用以發佈訊息的指令類似，只是在最後多加入了`-m hello`用以代表所要傳送的訊息。

```
mosquitto_pub -h localhost -p 1883 -t mqtt -m hello
```

透過上述指令，我們就可以在訂閱消息的連線中，看到所發布的訊息。

```
root@GL-AR750S:~# mosquitto_sub -h localhost -p 1883 -t mqtt
hello
```

{% hint style="info" %}
QoS 的預設值為 0。可以在`mosquitto_pub`中，透過`-q`的輸入來設定發送訊息的 QoS。
{% endhint %}
