3. 使用通配符订阅多个主题

使用通配符订阅多个主题 学习卡片

任务目标

在MQTT中,通配符用于一次订阅多个匹配的主题,避免逐条订阅。本案例使用+(单层通配符)和#(多层通配符)订阅一组主题,并通过发布消息验证匹配规则。

环境准备

需要安装 paho-mqtt 客户端库,并准备一个可用的MQTT Broker(如公共Broker broker.emqx.io:1883)。

pip install paho-mqtt

完整实现代码

import paho.mqtt.client as mqtt
import time

BROKER = "broker.emqx.io"
PORT = 1883
TOPIC_BASE = "demo/wildcard"

# 订阅回调:打印收到的主题和消息
def on_message(client, userdata, msg):
    print(f"收到消息: topic={msg.topic}, payload={msg.payload.decode()}")

# 连接回调
def on_connect(client, userdata, flags, rc):
    print(f"连接结果: {rc}")
    # 使用通配符订阅:
    # '+' 匹配 demo/wildcard/ 下的任意一层
    # '#' 匹配 demo/wildcard/ 下的所有后续层级
    client.subscribe([(f"{TOPIC_BASE}/+/temp", 0), (f"{TOPIC_BASE}/#", 0)])

client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message

client.connect(BROKER, PORT, 60)
client.loop_start()

# 等待连接建立
time.sleep(1)

# 发布测试消息,验证匹配规则
test_cases = [
    (f"{TOPIC_BASE}/room1/temp", "25.5"),   # 应被 + 和 # 匹配
    (f"{TOPIC_BASE}/room2/temp", "26.0"),   # 应被 + 和 # 匹配
    (f"{TOPIC_BASE}/room1/humidity", "60%"), # 仅被 # 匹配(+ 只匹配一层)
    (f"{TOPIC_BASE}/floor1/room1/temp", "24.8"), # 仅被 # 匹配(+ 不匹配多层)
]

for topic, payload in test_cases:
    client.publish(topic, payload)
    time.sleep(0.5)

# 等待消息回调完成
time.sleep(2)
client.loop_stop()
client.disconnect()

运行与验证

直接运行上述Python脚本。观察控制台输出,验证匹配规则:

  • demo/wildcard/room1/temp 和 demo/wildcard/room2/temp 会被打印两次(分别由+/temp和#两个订阅匹配)。
  • demo/wildcard/room1/humidity 和 demo/wildcard/floor1/room1/temp 只会被打印一次(仅由#匹配)。

通过条件:输出结果与上述预期完全一致,即每条消息至少被打印一次,且前两条消息各出现两次,后两条各出现一次,说明+只匹配单层、#匹配剩余所有层级。

匹配规则说明

  • +:匹配一个层级。例如 demo/wildcard/+/temp 可匹配 demo/wildcard/任意名/temp,但不能匹配 demo/wildcard/a/b/temp。
  • #:匹配多个层级(含零个)。例如 demo/wildcard/# 可匹配 demo/wildcard/ 下的任意深度主题。
  • 通配符只能位于主题末尾(#)或单独占一层(+),不能出现在主题中间(如 demo/+/temp 合法,但 demo/#/temp 非法)。