筆記目錄

Skip to content

在 .NET 使用 MQTT:MQTTnet 與 Mosquitto 實作

TLDR

  • MQTT 採用發佈/訂閱模式,核心角色包含 Broker、Publisher、Subscriber 與 Topic。
  • Topic 命名應具備階層性(如 地區/建築/房間/裝置),避免使用 $ 開頭(保留給系統使用)。
  • QoS 等級選擇:QoS 0 適用於感測資料;QoS 1 適用於控制指令;QoS 2 適用於金融交易。
  • 實際傳遞的 QoS 為發佈者與訂閱者設定值的最小值。
  • 使用 Docker 架設 Mosquitto 時,必須確保 password.txt 權限正確,並將資料夾擁有者設為 UID 1883。
  • 遺囑訊息(Last Will)僅在異常斷線時觸發,正常呼叫 DisconnectAsync() 不會發送。
  • 保留訊息(Retained Message)適用於儲存設備最新狀態,新訂閱者連線時可立即獲取。
  • MQTT 5.0 的持久會話需同時設定 CleanStart = falseSessionExpiryInterval(大於 0)。

MQTT 基本概念與運作

MQTT 是一種輕量級的發佈/訂閱式訊息傳輸協定。系統核心為 Broker,負責接收 Publisher 發送的訊息,並根據 Subscriber 的訂閱規則進行分發。

Topic 命名規則與建議

什麼情況下會遇到主題命名混亂的問題:在設計 IoT 系統架構初期,若未規劃好主題階層,將導致後續難以擴充與維護。

  • 階層結構:建議控制在 3-5 層,使用小寫英文與連字號 -
  • 特殊字元+(單層萬用字元)與 #(多層萬用字元)僅能用於訂閱,不可用於發佈。
  • 系統主題$ 開頭的主題(如 $SYS/)保留給 Broker 使用,應用程式應避免佔用。

QoS(服務品質等級)

什麼情況下會遇到訊息遺失或重複的問題:在網路環境不穩定的 IoT 場景中,需根據資料重要性選擇 QoS 等級。

  • QoS 0:最多傳送一次,效能最高,適用於頻繁更新的感測資料。
  • QoS 1:至少傳送一次,確保送達但可能重複,適用於控制指令。
  • QoS 2:確保只傳送一次,使用四次握手,適用於金融或計費系統。

使用 Docker Compose 架設 Mosquitto

什麼情況下會遇到容器啟動失敗或權限錯誤:在 Linux 環境下部署 Mosquitto 容器時,若掛載的目錄權限未正確設定,容器將無法寫入設定檔或資料。

關鍵設定與權限修正

entrypoint.sh 中,必須確保目錄擁有者為 1883,這是 Mosquitto 容器內的預設執行使用者:

shell
# 修正資料夾權限
chown -R 1883:1883 /mosquitto/config /mosquitto/log /mosquitto/data

TIP

正式環境建議啟用 TLS 加密,並參考官方文件設定 cafilecertfilekeyfile

.NET 使用 MQTTnet 實作

MQTTnet 是 .NET 生態系中功能最完整的 MQTT 函式庫。

基礎發佈與訂閱範例

以下程式碼展示了如何建立連線並進行訊息交換:

csharp
// 建立連線選項
var options = new MqttClientOptionsBuilder()
    .WithTcpServer("localhost", 1883)
    .WithCredentials("myuser", "mypassword")
    .Build();

// 發佈訊息
var message = new MqttApplicationMessageBuilder()
    .WithTopic("test/topic")
    .WithPayload("Hello, MQTT!")
    .WithQualityOfServiceLevel(MqttQualityOfServiceLevel.ExactlyOnce)
    .Build();

await client.PublishAsync(message);

IoT 溫度感測器模擬

什麼情況下會遇到背景任務管理困難:在模擬多個感測器或長時間監控時,應使用 CancellationToken 來優雅地停止背景執行緒。

csharp
// 監控系統訂閱
monitorClient.ApplicationMessageReceivedAsync += e => {
    string json = Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
    // 處理接收到的資料...
    return Task.CompletedTask;
};

進階功能實作

遺囑訊息(Last Will and Testament)

什麼情況下會遇到設備離線無法偵測的問題:當設備因斷電或網路中斷異常離線時,可利用遺囑訊息通知監控系統。

csharp
.WithWillTopic("status/client-001")
.WithWillPayload("offline")
.WithWillRetain(true)

持久會話(Persistent Session)

什麼情況下會遇到離線訊息遺失的問題:若希望客戶端在重新連線後能接收離線期間的訊息,必須正確設定持久會話。

  • MQTT 3.1.1:設定 CleanSession = false
  • MQTT 5.0:需同時設定 CleanStart = falseSessionExpiryInterval(大於 0 的秒數)。

WARNING

在 MQTT 5.0 中,若未設定 SessionExpiryInterval,即使 CleanStart 設為 false,Broker 也可能不會保留 Session。

參考資源

異動歷程

  • 2025-11-15 初版文件建立。