# 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](/files/-Loyk_hd0iLz6rE9zXJc)

考慮到物聯網的應用情境，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](/files/-Loys5scYDIbzHnnZLUr)

在這張圖中，我們也可以發現 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 %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://openwrt-nctu.gitbook.io/project/experiment-mqtt/mqtt-protocol.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
