什麼是MQTT
MQTT(Message Queuing Telemetry Transport
)是一種輕量級的通信協議,專門用於物聯網(IoT)設備之間的通信。它是基於發佈/訂閱(publish
/subscribe
)模式的協議,通過中間代理(broker
)進行消息的傳輸。
MQTT在物聯網應用中被廣泛使用,特別是在傳感器網絡、遠程監控、物聯網平臺等領域。它提供了一種簡單、高效、可靠的方式來實現設備之間的通信和數據傳輸。
基本概念
-
發佈/訂閱模式:MQTT使用發佈/訂閱模式,其中發佈者(Publisher)將消息發佈到特定的主題(Topic),而訂閱者(Subscriber)可以選擇訂閱感興趣的主題。這種模式可以實現一對多的消息傳遞。
-
主題(Topic):主題是MQTT中消息的分類標識。發佈者發佈消息到特定的主題上,而訂閱者則訂閱感興趣的主題以接收相關消息。
-
代理(Broker):代理是MQTT通信的中間服務器,負責接收發布者發送的消息,並將其傳遞給相應的訂閱者。代理還可以處理訂閱和取消訂閱請求,並維護客戶端之間的連接。
服務質量等級(QoS)
服務質量等級(QoS
, Quality of Service
):MQTT提供了不同的服務質量等級,用於確保消息的可靠性和傳輸效率。
QoS級別包括
- QoS 0(最多一次):消息最多傳輸一次,不保證消息的可靠性。
- QoS 1(至少一次):消息至少傳輸一次,確保消息到達代理,但可能會出現重複消息。
- QoS 2(僅一次):消息僅傳輸一次,確保消息只被傳遞一次,確保最高的可靠性。
特點
-
輕量級:MQTT被設計爲一種輕量級的協議,具有較小的網絡開銷和資源需求。這使得它非常適合在受限的網絡環境和資源受限的設備上使用。
-
支持異步通信:MQTT允許發佈者和訂閱者進行異步通信,不需要兩者同時在線。發佈者可以發佈消息,而訂閱者可以在其上線後接收到消息。
和消息隊列的區別
MQTT是一種輕量級的通信協議,專門用於物聯網設備之間的通信。它基於發佈/訂閱模式,通過中間代理(Broker
)進行消息的傳輸。MQTT適用於需要實時傳輸數據、低帶寬消耗和資源受限的環境,例如傳感器網絡和物聯網應用。
消息隊列是一種通信模式,用於在分佈式系統中進行異步消息傳遞。它通常基於消息隊列服務(Message Queue Service
),提供消息的存儲、轉發和交付等功能。消息隊列可以用於解耦消息的發送者和接收者,實現異步通信、流量控制和削峯填谷等功能。它適用於處理大量消息和高併發的情況,例如應用程序之間的解耦、任務調度和事件驅動架構等。
MQTT和消息隊列之間的一些區別
-
通信模式:MQTT是基於發佈/訂閱模式的通信協議,允許多個訂閱者訂閱特定主題的消息。消息隊列通常是基於點對點或發佈/訂閱模式的,消息的發送者將消息發送到隊列中,然後接收者從隊列中接收消息。
-
應用場景:MQTT主要用於物聯網設備之間的實時通信,例如傳感器數據的實時傳輸和設備控制。消息隊列更適用於解耦和異步通信的場景,例如大規模分佈式系統、任務處理和事件驅動架構。
-
傳輸特點:MQTT是一種輕量級協議,具有較小的網絡開銷和資源需求。它通常用於低帶寬環境和資源受限的設備。消息隊列通常提供持久化、消息確認和重試等特性,以確保消息的可靠性和可用性。
-
擴展性和性能:MQTT適用於大規模的設備連接,但在處理大量併發連接時性能可能受到限制。消息隊列通常具有良好的擴展性和高吞吐量,能夠處理大量的消息和併發請求。
MQTT適用於物聯網設備之間的實時通信,而消息隊列適用於解耦和異步通信的場景。選擇使用哪種機制取決於具體的應用需求、通信模式和性能要求。在某些情況下,MQTT和消息隊列也可以結合使用,根據實際情況選擇合適的通信方式。
MQTT的代理(Broker)
MQTT協議支持多種不同的代理(broker)實現,官方已有一些推薦,以下是一些常見的MQTT broker及其優缺點:
Mosquitto
Eclipse Mosquitto是一個開源的(EPL/EDL許可)消息代理,實現了MQTT協議的5.0、3.1.1和3.1版本。Mosquitto是輕量級的,適合在所有設備上使用,從低功率的單板計算機到完整的服務器。
- 優點:Mosquitto是一個開源的、輕量級的MQTT broker,易於安裝和配置。它具有較低的資源消耗,適用於嵌入式設備和資源受限的環境。Mosquitto還提供了可擴展性和安全性的特性。
- 缺點:在處理大量併發連接時,Mosquitto的性能可能受到限制。
HiveMQ
HiveMQ是一個MQTT代理,它從一開始就以最大的可擴展性和企業級的安全性爲目標。它有原生的網絡套接字支持和一個開源的插件SDK來擴展其功能或將其與其他組件集成。
- 優點:HiveMQ是一個功能強大的商業MQTT broker,具有良好的可擴展性和性能。它支持高併發連接和大規模部署,並提供了可靠性和可用性方面的高級功能。HiveMQ還提供了全面的安全特性和集成選項。
- 缺點:HiveMQ是商業產品,需要付費許可證才能使用其高級功能。
EMQX
EMQX是一個完全開源、高度可擴展、高度可用的分佈式MQTT消息代理,用於物聯網、M2M和移動應用,可以處理數千萬個併發客戶端。
從3.0版本開始,EMQX完全支持MQTT V5.0協議規範,並向後兼容MQTT V3.1和V3.1.1,以及其他通信協議,如MQTT-SN、CoAP、LwM2M、WebSocket和STOMP。EMQX的3.0版本可以在一個集羣上擴展到1000多萬個併發的MQTT連接。
- 優點:EMQ X是一個開源的、高度可擴展的MQTT broker,具有出色的性能和可靠性。它支持海量併發連接和分佈式部署,並提供了高級的安全特性和集羣功能。EMQ X還支持多種協議和插件擴展。
- 缺點:配置和管理EMQ X可能需要一定的學習成本,對於初學者來說可能有一定的複雜性。
RabbitMQ
RabbitMQ是一個AMQP消息代理 - 有一個MQTT插件(捆綁在3.x版本以上)。
- 優點:RabbitMQ是一個通用的消息代理,支持多種協議,其中包括MQTT。它具有成熟的可靠性和可用性特性,支持高吞吐量和可擴展性。RabbitMQ還提供了豐富的功能和靈活的路由規則。
- 缺點:相比於專門爲MQTT設計的代理,RabbitMQ在MQTT方面的性能可能較低。
MQTTnet
MQTTnet是一個高性能的.NET庫,用於基於MQTT的通信。它提供了一個MQTT客戶端和一個MQTT服務器(Broker),並支持MQTT協議的第5版。它與大多數支持的.NET框架版本和CPU架構兼容。
-
優點
-
開源且活躍的社區支持:MQTTnet是一個開源項目,擁有活躍的社區支持。這意味着你可以從社區中獲取更新、修復bug和功能擴展,以及與其他開發者分享經驗和解決方案。
-
跨平臺支持:MQTTnet是基於C#語言開發的,可以在多個平臺上使用,包括Windows、Linux和.NET Core等。這使得它具有廣泛的應用領域和靈活性。
-
-
簡單易用:MQTTnet提供了簡單而直觀的API,使得在.NET平臺上實現MQTT通信變得簡單易用。它提供了連接管理、發佈/訂閱功能以及QoS支持等核心功能。
- 高度可配置:MQTTnet允許你根據需求進行靈活的配置。你可以設置連接選項、消息保留策略、QoS級別、消息處理回調等,以滿足不同的通信需求。
-
缺點
-
C#語言限制:由於MQTTnet是基於C#語言的,因此它在某些嵌入式設備或特定平臺上的可用性可能會受到限制。
-
可能存在性能瓶頸:儘管MQTTnet已經努力優化性能,但在處理大量併發連接或高吞吐量時,仍可能面臨性能瓶頸的挑戰。這需要根據具體應用場景進行測試和優化。
-
依賴於第三方庫:MQTTnet可能依賴於其他第三方庫,這可能增加項目的複雜性和維護的難度。需要注意對依賴庫的版本控制和更新。
-
這些僅是一些常見的MQTT broker實現,還有其他許多可選擇的實現,每個實現都有其自己的特點和適用場景。選擇合適的MQTT broker取決於你的具體需求,包括預期的併發連接數、性能要求、可擴展性需求、安全性需求以及預算等因素。
Mosquitto安裝
Windows安裝包
安裝之後,它會自動創建一個mosquitto
的服務,默認是沒有自動開啓的,我們可以手動打開下。
這時候這個代理就運行起來了。
Docker運行
執行如下命令即可:
docker run -d --name mosquitto --restart unless-stopped -p 1883:1883 -p 9001:9001 eclipse-mosquitto:2.0.15
調試MQTT
MQTT.fx
MQTTX
MQTTX是一款開源的跨平臺桌面客戶端,它簡單易用且提供全面的MQTT 5.0功能、特性測試,可運行在macOS, Linux和Windows上。同時,它還提供了命令行及瀏覽器版本,滿足不同場景下的MQTT測試需求。
對接MQTT
通過MQTTnet對接MQTT
Nuget包
dotnet add package MQTTnet
連接
連接代碼
var mqttFactory = new MqttFactory();
using (var mqttClient = mqttFactory.CreateMqttClient())
{
// Use builder classes where possible in this project.
var mqttClientOptions = new MqttClientOptionsBuilder().WithTcpServer("127.0.0.1").Build();
// This will throw an exception if the server is not available.
// The result from this message returns additional data which was sent
// from the server. Please refer to the MQTT protocol specification for details.
var response = await mqttClient.ConnectAsync(mqttClientOptions, CancellationToken.None);
Console.WriteLine("The MQTT client is connected.");
//response.DumpToConsole();
// Send a clean disconnect to the server by calling _DisconnectAsync_. Without this the TCP connection
// gets dropped and the server will handle this as a non clean disconnect (see MQTT spec for details).
var mqttClientDisconnectOptions = mqttFactory.CreateClientDisconnectOptionsBuilder().Build();
await mqttClient.DisconnectAsync(mqttClientDisconnectOptions, CancellationToken.None);
}
訂閱
var mqttFactory = new MqttFactory();
using (var mqttClient = mqttFactory.CreateMqttClient())
{
var mqttClientOptions = new MqttClientOptionsBuilder().WithTcpServer("broker.hivemq.com").Build();
// Setup message handling before connecting so that queued messages
// are also handled properly. When there is no event handler attached all
// received messages get lost.
mqttClient.ApplicationMessageReceivedAsync += e =>
{
Console.WriteLine("Received application message.");
e.DumpToConsole();
return Task.CompletedTask;
};
await mqttClient.ConnectAsync(mqttClientOptions, CancellationToken.None);
var mqttSubscribeOptions = mqttFactory.CreateSubscribeOptionsBuilder()
.WithTopicFilter(
f =>
{
f.WithTopic("mqttnet/samples/topic/2");
})
.Build();
await mqttClient.SubscribeAsync(mqttSubscribeOptions, CancellationToken.None);
Console.WriteLine("MQTT client subscribed to topic.");
Console.WriteLine("Press enter to exit.");
Console.ReadLine();
}
發送
var mqttFactory = new MqttFactory();
using (var mqttClient = mqttFactory.CreateMqttClient())
{
var mqttClientOptions = new MqttClientOptionsBuilder()
.WithTcpServer("broker.hivemq.com")
.Build();
await mqttClient.ConnectAsync(mqttClientOptions, CancellationToken.None);
var applicationMessage = new MqttApplicationMessageBuilder()
.WithTopic("samples/temperature/living_room")
.WithPayload("19.5")
.Build();
await mqttClient.PublishAsync(applicationMessage, CancellationToken.None);
await mqttClient.DisconnectAsync();
Console.WriteLine("MQTT application message is published.");
}