跳转到内容

多级通配符

本节介绍 MQTT 多级通配符 # 的使用方法、限制和实际应用场景。学习完成后,您将能够:

  • 理解多级通配符的工作原理和使用限制
  • 区分单级和多级通配符的适用场景
  • 在实际项目中选择正确的通配符类型
  • 避免通配符使用中的常见错误

在开始本节之前,请确保:

  • 理解单级通配符 +
  • 理解 Topic 层级结构
  • Mosquitto Broker 已运行

# 通配符匹配 Topic 中剩余的所有层级(包含 0 个层级):

Topic: home/#
匹配:
✅ home (# 匹配 0 层级)
✅ home/livingroom
✅ home/livingroom/temperature
✅ home/livingroom/temperature/value
✅ home/ground/kitchen/humidity
不匹配:
❌ apartment/livingroom/temperature (第一层不匹配 home)
  1. 必须是 Topic 的最后一个字符# 只能出现在 Topic 末尾
  2. 前面必须有斜杠:通常写作 /#,但单独 # 也有效
  3. 匹配所有剩余层级:包括 0 个或多个层级
  4. 只能用于订阅:发布者不能使用 #
Topic 结构:
factory/{zone}/{sensor_type}/{sub_parameter}
订阅: factory/#
匹配:
✅ factory (只有域)
✅ factory/zone1 (域+区域)
✅ factory/zone1/temperature (域+区域+类型)
✅ factory/zone1/temperature/avg (域+区域+类型+子参数)
Terminal window
# CLI 验证
# 向不同层级发布
mosquitto_pub -h localhost -t "factory" -m "system_online"
mosquitto_pub -h localhost -t "factory/zone1" -m "zone1_ready"
mosquitto_pub -h localhost -t "factory/zone1/temperature" -m "26.5"
mosquitto_pub -h localhost -t "factory/zone2/humidity" -m "62"
# 使用多级通配符订阅
mosquitto_sub -h localhost -t "factory/#" -v
# 预期: 所有 factory 开头的 Topic 消息
Topic 结构:
devices/{device_id}/{category}/{parameter}
订阅特定设备的所有信息:
订阅: devices/esp32_001/#
匹配:
✅ devices/esp32_001
✅ devices/esp32_001/status
✅ devices/esp32_001/temperature/current
✅ devices/esp32_001/temperature/history/last_hour
✅ devices/esp32_001/humidity/current
// Node-RED 中使用多级通配符监控全局
// 订阅所有消息(危险做法 - 可能收到大量消息)
msg.topic = "#"; // 订阅 Broker 上的所有 Topic
// 更合理的做法:订阅特定域的全局
msg.topic = "factory/#"; // 只关注工厂数据
发布 Topic订阅 home/+订阅 home/#
home❌ (+ 必须匹配一个层级)✅ (# 匹配0层级)
home/livingroom
home/livingroom/temperature❌ (层级数不同)
home/livingroom/temperature/value
你需要订阅:
├── 某个层级下的所有数据(不限深度)
│ └── 使用 #
│ 例: factory/#
├── 某个特定层级的所有值(限定深度)
│ └── 使用 +
│ 例: factory/zone1/+
├── 组合需求
│ └── 多个 + 或 + 与 # 组合
│ 例: factory/+/temperature/# (所有区域温度下的所有子数据)
└── 全局所有消息
└── 单独 #
例: # (慎用,可能收到大量消息)

+# 可以在同一个订阅中组合使用:

订阅: factory/+/temperature/#
匹配:
✅ factory/zone1/temperature (区域1温度)
✅ factory/zone1/temperature/current (区域1当前温度)
✅ factory/zone2/temperature (区域2温度)
✅ factory/zone2/temperature/avg (区域2平均温度)
✅ factory/zone2/temperature/history (区域2历史温度)
不匹配:
❌ factory/zone1/humidity (传感器类型不匹配)
❌ office/zone1/temperature (域不匹配)
Terminal window
# 组合通配符 CLI 验证
# 发布数据
mosquitto_pub -h localhost -t "factory/zone1/temperature" -m "26.5"
mosquitto_pub -h localhost -t "factory/zone1/temperature/current" -m "26.5"
mosquitto_pub -h localhost -t "factory/zone2/temperature" -m "28.0"
mosquitto_pub -h localhost -t "factory/zone1/humidity" -m "62" # 不会被接收
# 订阅
mosquitto_sub -h localhost -t "factory/+/temperature/#" -v
// 监控特定工厂区域的所有数据
// 在 Node-RED 中使用
[
{
"topic": "factory/zone1/#",
"description": "订阅 Zone1 的所有数据"
},
{
"topic": "factory/zone2/alarm/#",
"description": "订阅 Zone2 的所有告警"
}
]
// 调试工具:查看特定设备的所有 Topic
function subscribeToDevice(deviceId) {
const topic = `devices/${deviceId}/#`;
mqttClient.subscribe(topic);
console.log(`Monitoring all topics for device: ${deviceId}`);
}
❌ 错误订阅: home/#/temperature
原因: # 必须是 Topic 最后一个字符
✅ 正确订阅: home/#
✅ 正确订阅: #
✅ 正确: factory/#
意义: factory 下的所有子层级
✅ 正确: #
意义: 全局所有 Topic
注意: 单独 `#` 是有效的全局通配符
❌ 错误: mosquitto_pub -t "home/#" -m "data"
Error: Wildcard not allowed in publish
✅ 正确: mosquitto_pub -t "home/livingroom/temperature" -m "26.5"

使用 # 通配符,尤其是在系统级使用,需要注意性能影响:

风险:
- 订阅 # 会收到 Broker 上的所有消息
- 如果系统中有大量 Topic,可能导致消息泛滥
- 设备消息和系统消息都收到(如 $SYS 消息)
建议:
✅ 限定域范围: factory/# 优于 #
✅ 结合 + 精确控制: factory/zone1/# 优于 factory/#
✅ 使用排除规则: 通过 ACL 过滤不需要的 Topic
Terminal window
# 完整测试
# 1. 订阅多级通配符
mosquitto_sub -h localhost -t "factory/#" -v &
# 2. 发布不同层级的消息
mosquitto_pub -h localhost -t "factory" -m "init"
mosquitto_pub -h localhost -t "factory/zone1" -m "active"
mosquitto_pub -h localhost -t "factory/zone1/temperature" -m "26.5"
mosquitto_pub -h localhost -t "factory/zone1/temperature/avg" -m "26.3"
mosquitto_pub -h localhost -t "factory/zone2/humidity" -m "62"
# 预期: 收到所有 5 条消息

本节要点总结:

  1. # 通配符:匹配 Topic 中剩余的所有层级(含 0 层)
  2. 使用限制:必须是 Topic 末尾,只能用于订阅
  3. + vs #+ 匹配一个层级,# 匹配多个层级
  4. 组合使用+# 可以在一个订阅中组合
  5. 性能注意# 订阅范围广,应限定域范围避免消息泛滥