MQTT 协议:物联网首选轻量通信
FreeGuideOnline
最新
2026-07-03
home/livingroom/temperature building/floor2/room205/light/status
- **通配符支持**:订阅者可以使用通配符一次订阅多个主题。
- **单层通配符 `+`**:匹配任意一个完整层级。`home/+/temperature` 会匹配 `home/livingroom/temperature`、`home/bedroom/temperature`,但不匹配 `home/livingroom/humidity`。
- **多层通配符 `#`**:匹配当前层及之后的所有层级,只能放在主题末尾。`home/#` 匹配以 `home/` 为前缀的所有主题,如 `home/livingroom/temperature`、`home/bedroom/light` 等。
- **以`$`开头的主题**:通常为系统内部使用,客户端不能直接向这类主题发布消息,且订阅 `+` 和 `#` 不会匹配到它们。
### 服务质量(QoS)
MQTT定义了三种消息发布服务质量等级,用于平衡可靠性和性能:
- **QoS 0:至多一次**
消息发送完全依赖底层TCP/IP网络,不进行确认和重试。
接收方可能收到一次消息,也可能根本收不到。适用于传感器定时上报非关键数据,允许偶尔丢失。
- **QoS 1:至少一次**
确保消息至少被送达一次,可能会重复。发送方在发出消息后要求接收方回复PUBACK报文,若未收到确认则重发。
接收方可能会收到多条相同的消息,因此需要业务逻辑进行去重处理。这是MOST常用等级。
- **QoS 2:恰好一次**
通过两次握手保证消息有且仅被送达一次,无丢失无重复。流程用PUBLISH、PUBREC、PUBREL、PUBCOMP四步交互完成。
开销最大,适用于金融交易、控制指令等不能容忍丢失或重复的场景。
> 注意:QoS是发布者和订阅者分别与Broker之间达成的约定,而非端到端的保证。例如,发布者以QoS 1发给Broker,Broker以QoS 0转发给订阅者,那么订阅者可能收不到消息。
## MQTT控制报文详解
MQTT协议共定义了15种控制报文类型,每个报文由固定头部、可变头部和有效载荷组成。以下解释最常用的几种。
### CONNECT与CONNACK
- **CONNECT**:客户端发送给Broker的连接请求,包含协议名、协议版本、清理会话标志(Clean Session)、保活时间(Keep Alive)、客户端ID以及可选的用户名/密码和遗嘱消息等。
- **CONNACK**:Broker对CONNECT的确认,包含会话存在标志和返回码(如连接接受、协议版本错误、标识符被拒、服务不可用等)。
保活时间用于在没有消息交互时,客户端定期发送PINGREQ以维持连接,若Broker在1.5倍保活时间内未收到任何报文,将断开连接。
### PUBLISH与PUBACK
- **PUBLISH**:发布消息,包含主题名、报文ID(QoS>0时需要)、有效载荷和QoS等级等字段。
- **PUBACK**:对QoS 1发布消息的确认。Broker收到QoS 1的PUBLISH后存储消息并向订阅者转发,同时回复发送者PUBACK。对QoS 2的流程更复杂,但由PUBREC/PUBREL/PUBCOMP完成,详见协议规范。
### SUBSCRIBE与SUBACK
- **SUBSCRIBE**:客户端发送订阅请求,可一次订阅多个主题,并为每个主题指定要求的QoS。报文ID必须存在。
- **SUBACK**:Broker返回订阅结果,为每个订阅主题单独返回一个授予的QoS(可能低于请求的QoS)。
订阅者指定的QoS是期望Broker在向自己转发消息时使用的最大QoS级别。实际授予的QoS由Broker根据主题自身限制决定。
### PINGREQ与PINGRESP
- **PINGREQ**:客户端在无数据交互时发送心跳请求,维持连接活性。
- **PINGRESP**:Broker响应PINGREQ,表明连接正常。
### DISCONNECT
- **DISCONNECT**:客户端在正常关闭连接前发送,告知Broker自己将断开。若设置了遗嘱消息,则此时不会发布遗嘱,因为这是正常断开。
## MQTT 5.0 新特性概览
MQTT 5.0在保持轻量核心的基础上引入了大量现代功能,显著提升了协议的可扩展性和适用场景:
- **会话与消息过期**:可以为会话和单条消息设置过期时间,超时后将自动清除,避免长期占用存储。
- **原因码与用户属性**:所有确认报文均能携带原因码字符串和用户自定义键值对,便于错误诊断和元数据传递。
- **共享订阅**:允许多个订阅者组共享同一订阅,消息将在组内负载均衡分发,用于构建消费者组。
- **请求/响应模式**:通过响应主题(Response Topic)和关联数据(Correlation Data)原生支持请求-响应,无需额外协议。
- **更强的认证与授权**:支持增强认证方法(如SCRAM),在连接阶段可执行多步安全挑战。
- **Topic Alias**:将主题名映射为整数别名,减少重复传输长主题名的开销。
- **Flow Control**:收发双方可限制未确认PUBLISH报文的数量,实现流量控制。
对于新项目,建议直接采用MQTT 5.0;如果项目需要与大量旧有设备兼容,MQTT 3.1.1仍是可靠选择。
## 动手实践:搭建你的第一个MQTT通信
### 使用公共代理进行测试
在开始编写代码前,你可以使用公开免费的MQTT代理来快速体验。例如:
- **Broker地址**:`broker.emqx.io`
- **TCP端口**:1883(非加密)
- **WebSocket端口**:8083
你可以使用图形化工具[MQTTX](https://mqttx.app/)或命令行工具`mosquitto_pub`/`mosquitto_sub`来发布和订阅消息。
**简单命令行示例(需安装mosquitto客户端):**
```bash
# 终端1:订阅主题 tutorial/test,打印接收到的消息
mosquitto_sub -h broker.emqx.io -t "tutorial/test" -q 1
# 终端2:发布一条消息到同一主题
mosquitto_pub -h broker.emqx.io -t "tutorial/test" -m "Hello MQTT" -q 1
你会看到终端1立即打印出“Hello MQTT”。
Python代码示例
使用paho-mqtt库,可以轻松实现发布和订阅功能。
订阅端 client_sub.py
import paho.mqtt.client as mqtt
def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))
client.subscribe("tutorial/test", qos=1)
def on_message(client, userdata, msg):
print(f"Received '{msg.payload.decode()}' on topic '{msg.topic}'")
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect("broker.emqx.io", 1883, 60)
client.loop_forever()
发布端 client_pub.py
import paho.mqtt.client as mqtt
import time
client = mqtt.Client()
client.connect("broker.emqx.io", 1883, 60)
# 发布消息,QoS 1
client.publish("tutorial/test", payload="Hello from Python", qos=1)
time.sleep(1) # 等待网络发送完成
client.disconnect()