概述
MQTT是一个基于客户端-服务器的消息发布/订阅传输协议。MQTT协议是轻量、简单、开放和易于实现的,这些特点使它适用范围非常广泛。在很多情况下,包括受限的环境中,如:机器与机器(M2M)通信和物联网(IoT)。其在,通过卫星链路通信传感器、偶尔拨号的医疗设备、智能家居、及一些小型化设备中已广泛使用。
MQTT应用场景
智能家居,汽车出行,工业制造,能源电力,智慧农业,医疗保健等领域
MQTT优点
-
轻量级和高效性:MQTT 是一种轻量级协议,设计用于在资源受限的设备和低带宽网络上运行。它的消息头非常小,协议本身也非常简单,因此可以在各种设备上高效地运行,包括传感器、嵌入式系统和移动设备。
-
发布/订阅模式:MQTT 使用发布/订阅模式,使得通信变得高度灵活和可扩展。设备可以通过订阅感兴趣的主题来接收消息,而不需要知道消息的发送者,这简化了系统架构并提高了通信效率。
-
可靠性:MQTT 提供了不同级别的服务质量(QoS),包括至多一次、至少一次和恰好一次交付保证。这使得开发人员可以根据应用的需求选择适当的服务质量级别,从而实现可靠的消息传递。
-
异步通信:MQTT 支持异步通信,设备可以随时发送消息而不必等待对方的响应。这种异步通信模式非常适用于需要实时性的应用场景,例如实时监控和控制系统。
-
断线重连和持久性会话:MQTT 客户端支持断线重连和持久性会话功能,这意味着设备可以在断开连接后自动重新连接到服务器,并且可以保持之前的会话状态,确保消息不会丢失。
-
灵活的主题结构:MQTT 的主题结构非常灵活,允许开发人员根据应用需求定义自己的主题层次结构。这种灵活性使得消息的组织和管理变得更加简单和有效。
-
跨平台支持:MQTT 是一个开放的标准,已经被广泛实现在各种不同的平台上,包括开源实现和商业实现。这使得开发人员可以轻松地在不同的设备和系统之间进行通信。
MQTT工作原理
MQTT客户端
客户端是指与 MQTT 服务器(也称为 MQTT 代理或代理服务器)进行通信的任何设备或应用程序。客户端可以是发布者(Publisher)、订阅者(Subscriber)或同时兼具发布者和订阅者的角色。
MQTT服务器端(MQTT Broker )
MQTT 服务器端,也称为 MQTT 代理(broker)或 MQTT 代理服务器,是负责接收、处理和转发 MQTT 消息的中间件组件。它是 MQTT 通信架构中的核心部分,负责管理客户端连接、维护订阅关系、处理消息传递等任务。
发布(Publish)/订阅(Subscribe)模式
-
发布者(Publisher):
-
发布者是消息的发送方,负责将消息发布到 MQTT 服务器。
-
发布者不直接发送消息给特定的接收方,而是将消息发布到一个或多个主题(Topic)。
-
主题是消息的逻辑标识符,用于对消息进行分类和过滤。
-
-
订阅者(Subscriber):
-
订阅者是消息的接收方,负责订阅感兴趣的主题,并接收相应的消息。
-
订阅者向 MQTT 服务器发送订阅请求,指定它希望接收的主题。
-
当有新消息发布到订阅者订阅的主题时,订阅者会收到该消息。
-
-
通信过程:
-
发布者发布消息时,指定一个或多个主题,并将消息发送到 MQTT 服务器。
-
MQTT 服务器接收到消息后,根据发布者指定的主题,将消息传递给所有订阅了相应主题的订阅者。
-
订阅者收到消息后进行处理,例如更新数据、执行操作等。
-
-
灵活性和可扩展性:
-
发布/订阅模式使得通信变得高度灵活和可扩展。发布者和订阅者之间解耦,不需要直接知道彼此的存在,因此系统架构更加灵活。
-
发布者和订阅者可以动态地加入和退出,而不会对系统的其他部分造成影响。
-
主题(topic)
主题(Topic)是消息的逻辑标识符,用于对消息进行分类和过滤。主题是发布者和订阅者之间通信的关键部分之一。
-
层次结构:
-
MQTT 主题可以采用层次结构,使得主题具有父子关系。
-
例如,主题可以类似于 "sensor/temperature"、"home/livingroom/lights",其中 "sensor" 和 "home" 是父级主题,"temperature" 和 "livingroom/lights" 是子级主题。
-
-
通配符:
-
MQTT 主题支持两种通配符:单层通配符(+)和多层通配符(#)。
-
单层通配符(+)匹配一个层级,多层通配符(#)匹配零个或多个层级。
-
例如,主题 "sensor/+/temperature" 可以匹配 "sensor/kitchen/temperature" 和 "sensor/livingroom/temperature",而主题 "home/#" 可以匹配 "home/livingroom/lights" 和 "home/kitchen/temperature" 等。
注意:通配符主题只能用于订阅,不能用于发布。
-
MQTT使用
常见的 MQTT 服务器或 MQTT 代理软件
-
Eclipse Mosquitto:
-
Eclipse Mosquitto 是一个开源的 MQTT 代理软件,它提供了基本的 MQTT 功能,包括发布/订阅机制、QoS 服务质量级别支持、身份认证和访问控制等。
-
Mosquitto 是一个轻量级的 MQTT 代理软件,由于其轻量级和简单易用的特点,Eclipse Mosquitto 适合用于中小型的 IoT 应用、传感器网络、家庭自动化等场景。
官方网站:Eclipse Mosquitto
docker安装:
-
拉取 Mosquitto 镜像:
打开终端,执行以下命令拉取 Eclipse Mosquitto 镜像:
docker pull eclipse-mosquitto
这会从 Docker Hub 上拉取最新版本的 Eclipse Mosquitto 镜像。
-
创建 Mosquitto 配置文件:
在你的工作目录中创建一个名为
mosquitto.conf
的配置文件,并填写 Mosquitto 的配置。以下是一个简单的示例配置文件:listener 1883 allow_anonymous true persistence true persistence_location /mosquitto/data/
这个配置文件指定了 Mosquitto 监听端口为
1883
,并启用了持久化存储,并将持久化数据保存在容器内的/mosquitto/data/
目录中。 -
运行 Mosquitto 容器:
执行以下命令创建并运行 Mosquitto 容器,同时将你创建的配置文件挂载到容器内的
/mosquitto/config/
目录下:docker run -d --name mosquitto -p 1883:1883 -v /path/to/mosquitto.conf:/mosquitto/config/mosquitto.conf eclipse-mosquitto
请将
/path/to/mosquitto.conf
替换为你创建的配置文件的路径。
-
-
EMQ X:
-
EMQ X 是一个开源的、高性能的 MQTT 代理软件,提供了丰富的功能和插件系统,它支持 MQTT 3.1、3.1.1 和 5.0 版本的协议,并提供了高可用性、水平扩展和集群功能。
-
EMQ X 还提供了丰富的插件系统,可以扩展其功能,如支持 CoAP、WebSocket、AMQP 等协议。
-
EMQ X 适用于需要高性能、高可用性和可伸缩性的场景,如工业物联网、智能城市、大规模传感器网络等。
官方网站:EMQX: The #1 MQTT Platform for IoT, IIoT and Connected Cars
在docker中使用:
1.Get Docker Image
docker pull emqx/emqx:5.5.0
2.Start Docker Container
docker run -d --name emqx -p 1883:1883 -p 8083:8083 -p 8084:8084 -p 8883:8883 -p 18083:18083 emqx/emqx:5.5.0
-
-
HiveMQ:
-
HiveMQ 是一个专业的 MQTT 代理软件,提供了高性能、高可靠性和安全性,它支持 MQTT 3.1、3.1.1 和 5.0 版本的协议,并提供了广泛的集成和管理功能。
-
HiveMQ 还提供了企业级功能,如集群、多数据中心复制、数据持久化等。
-
HiveMQ 适用于需要企业级功能和高度可靠性的场景,如金融、医疗、智能交通等对消息传递有严格要求的行业。
官方网站:HiveMQ – The Most Trusted MQTT platform to Transform Your Business
Download and run HiveMQ:
Running the HiveMQ trial with Docker is the simplest way to experiment with HiveMQ and MQTT. The following command downloads and starts a single HiveMQ trial node.
docker run -p 8080:8080 -p 1883:1883 hivemq/hivemq4
-
客户端(Python)
要在 Python 中使用 MQTT,你可以使用 Eclipse Paho MQTT 客户端库。以下是一个简单的示例,演示了如何在 Python 中创建一个 MQTT 客户端并连接到 MQTT 服务器、发布消息和订阅主题。
首先,你需要安装 Eclipse Paho MQTT 客户端库。你可以使用 pip 来安装:
pip install paho-mqtt
然后,以下是一个示例代码:
订阅者示例:
import paho.mqtt.client as mqtt
def on_subscribe(client, userdata, mid, reason_code_list, properties):
# Since we subscribed only for a single channel, reason_code_list contains
# a single entry
if reason_code_list[0].is_failure:
print(f"Broker rejected you subscription: {reason_code_list[0]}")
else:
print(f"Broker granted the following QoS: {reason_code_list[0].value}")
def on_unsubscribe(client, userdata, mid, reason_code_list, properties):
# Be careful, the reason_code_list is only present in MQTTv5.
# In MQTTv3 it will always be empty
if len(reason_code_list) == 0 or not reason_code_list[0].is_failure:
print("unsubscribe succeeded (if SUBACK is received in MQTTv3 it success)")
else:
print(f"Broker replied with failure: {reason_code_list[0]}")
client.disconnect()
def on_message(client, userdata, message):
# userdata is the structure we choose to provide, here it's a list()
userdata.append(message.payload)
# We only want to process 10 messages
if len(userdata) >= 10:
client.unsubscribe("$SYS/#")
print("Received message '" + str(message.payload) + "' on topic '" + message.topic + "'")
def on_connect(client, userdata, flags, reason_code, properties):
if reason_code.is_failure:
print(f"Failed to connect: {reason_code}. loop_forever() will retry connection")
else:
# we should always subscribe from on_connect callback to be sure
# our subscribed is persisted across reconnections.
client.subscribe("$SYS/#")
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
mqttc.on_connect = on_connect
mqttc.on_message = on_message
mqttc.on_subscribe = on_subscribe
mqttc.on_unsubscribe = on_unsubscribe
mqttc.user_data_set([])
mqttc.connect("mqtt.eclipseprojects.io")
mqttc.loop_forever()
print(f"Received the following message: {mqttc.user_data_get()}")
发布者示例:
import time
import paho.mqtt.client as mqtt
def on_publish(client, userdata, mid, reason_code, properties):
# reason_code and properties will only be present in MQTTv5. It's always unset in MQTTv3
try:
userdata.remove(mid)
except KeyError:
print("on_publish() is called with a mid not present in unacked_publish")
print("This is due to an unavoidable race-condition:")
print("* publish() return the mid of the message sent.")
print("* mid from publish() is added to unacked_publish by the main thread")
print("* on_publish() is called by the loop_start thread")
print("While unlikely (because on_publish() will be called after a network round-trip),")
print(" this is a race-condition that COULD happen")
print("")
print("The best solution to avoid race-condition is using the msg_info from publish()")
print("We could also try using a list of acknowledged mid rather than removing from pending list,")
print("but remember that mid could be re-used !")
unacked_publish = set()
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
mqttc.on_publish = on_publish
mqttc.user_data_set(unacked_publish)
mqttc.connect("mqtt.eclipseprojects.io")
mqttc.loop_start()
# Our application produce some messages
msg_info = mqttc.publish("paho/test/topic", "my message", qos=1)
unacked_publish.add(msg_info.mid)
msg_info2 = mqttc.publish("paho/test/topic", "my message2", qos=1)
unacked_publish.add(msg_info2.mid)
# Wait for all message to be published
while len(unacked_publish):
time.sleep(0.1)
# Due to race-condition described above, the following way to wait for all publish is safer
msg_info.wait_for_publish()
msg_info2.wait_for_publish()
mqttc.disconnect()
mqttc.loop_stop()
成功运行
Received message 'b'my message'' on topic 'paho/test/topic'
Received message 'b'my message2'' on topic 'paho/test/topic'