文档
MQTT 协议进阶:QoS 深度解析与安全通信(TLS)
目标
深入理解 MQTT QoS 机制的消息流程,配置 TLS/SSL 加密通信,使用 MQTT 5.0 新特性。
一、QoS 深度解析
QoS 0 — 至多一次 (Fire and Forget)
发布者 → PUBLISH → Broker → PUBLISH → 订阅者
(不等待确认) (不重试)
client.publish("sensor/temp", "25.5", qos=0)
# 优点:最快、开销最小
# 适用:高频传感器数据,容忍丢帧(如每秒 100 次的加速度采样)
QoS 1 — 至少一次 (Acknowledged)
发布者 → PUBLISH (Packet ID=1234)
← PUBACK (Packet ID=1234)
Broker → PUBLISH (Packet ID=5678)
← PUBACK (Packet ID=5678) 订阅者
# 未收到 PUBACK 则重发
def on_publish(client, userdata, mid):
print(f"QoS 1 消息 {mid} 已确认")
client.on_publish = on_publish
client.publish("alert/fire", "HIGH", qos=1)
# 优点:可靠投递
# 缺点:可能重复(订阅者需幂等处理)
QoS 2 — 恰好一次 (Four-Way Handshake)
发布者 → PUBLISH (ID=1)
← PUBREC (ID=1)
发布者 → PUBREL (ID=1)
← PUBCOMP (ID=1)
# 四步握手保证「恰好一次」
client.publish("payment/confirmed", json.dumps(order), qos=2)
# 优点:不丢不重
# 缺点:最慢,适合金融/控制指令
# 注意:MQTT 5.0 优化了 QoS 2 握手流程
QoS 选择建议
| 场景 | 推荐 QoS | 原因 |
|---|---|---|
| 温度传感器(1Hz) | QoS 1 | 偶尔重复可接受 |
| 加速度计(100Hz) | QoS 0 | 速度优先 |
| 支付确认 | QoS 2 | 零容忍重复 |
| 设备控制命令 | QoS 2 | 必须恰好执行一次 |
| 状态更新 (Retained) | QoS 1 | 新订阅者需最新状态 |
二、TLS/SSL 安全通信
生成自签名证书
# CA 私钥
openssl genrsa -out ca.key 2048
# CA 证书
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt \
-subj "/C=CN/ST=Guangdong/O=IoT Company/CN=My IoT CA"
# Broker 私钥
openssl genrsa -out broker.key 2048
# Broker 证书请求
openssl req -new -key broker.key -out broker.csr \
-subj "/CN=mqtt.local"
# 签发 Broker 证书
openssl x509 -req -in broker.csr -CA ca.crt -CAkey ca.key \
-CAcreateserial -out broker.crt -days 365
Mosquitto TLS 配置
# /etc/mosquitto/conf.d/tls.conf
listener 8883
cafile /etc/mosquitto/certs/ca.crt
certfile /etc/mosquitto/certs/broker.crt
keyfile /etc/mosquitto/certs/broker.key
require_certificate true # 要求客户端证书
tls_version tlsv1.2
# 同时保留内部非 TLS 端口
listener 1883 localhost # 仅本地可用
Python 客户端 TLS
import ssl
import paho.mqtt.client as mqtt
client = mqtt.Client(client_id="secure_sensor")
# 单向 TLS(验证 Broker)
client.tls_set(
ca_certs="ca.crt", # CA 证书
certfile=None, # 无客户端证书
keyfile=None,
cert_reqs=ssl.CERT_REQUIRED,
tls_version=ssl.PROTOCOL_TLSv1_2
)
# 双向 TLS(客户端也出示证书)
# client.tls_set(
# ca_certs="ca.crt",
# certfile="client.crt",
# keyfile="client.key",
# cert_reqs=ssl.CERT_REQUIRED
# )
client.connect("mqtt.local", 8883)
三、MQTT 5.0 新特性实战
# MQTT 5.0 特性示例
import paho.mqtt.client as mqtt
from paho.mqtt.properties import Properties
from paho.mqtt.packettypes import PacketTypes
client = mqtt.Client(protocol=mqtt.MQTTv5)
# ── 会话过期 ──
props = Properties(PacketTypes.CONNECT)
props.SessionExpiryInterval = 3600 # 断线后保留会话 1 小时
client.connect("localhost", properties=props)
# ── 消息过期 ──
pub_props = Properties(PacketTypes.PUBLISH)
pub_props.MessageExpiryInterval = 60 # 消息 60 秒后自动丢弃
client.publish("temp/urgent", "42°C", qos=1, properties=pub_props)
# ── 请求/响应模式 ──
# 发布者
response_props = Properties(PacketTypes.PUBLISH)
response_props.ResponseTopic = "cmd/response/xyz"
response_props.CorrelationData = b"req-001"
client.publish("cmd/restart", properties=response_props)
# ── 用户属性(自定义元数据) ──
meta_props = Properties(PacketTypes.PUBLISH)
meta_props.UserProperty = [
("sensor_type", "temperature"),
("firmware_version", "2.4.1"),
("priority", "high")
]
client.publish("data", "25.0", properties=meta_props)
四、关键点
- QoS 降级:发布者 QoS 2 → Broker 可为订阅者降为 QoS 1 或 0(取决于订阅 QoS)
- TLS 开销:ESP32 上 TLS 握手约 1-2 秒,需考虑电池功耗
- MQTT 5.0 vs 3.1.1:5.0 新增 30+ 特性但 Broker 兼容成本高,嵌入式首选 3.1.1
- 会话保持:
clean_start=false+SessionExpiryInterval确保断线后消息不丢失