MQTT 主题的写法(强烈不推荐以/开头,会形成空层级)
好的,我们来详细讲解 MQTT 主题的写法、规则以及通配符的使用。这是 MQTT 协议中非常核心和灵活的部分。
1. 主题 (Topic) 是什么?
- 作用: MQTT 主题是一个UTF-8编码的字符串,是消息的地址标签或路由路径。发布者将消息发送到特定的主题,订阅者通过订阅感兴趣的主题来接收相关的消息。Broker 负责根据主题将消息从发布者路由到正确的订阅者。
- 结构: 主题由一个或多个主题层级组成,层级之间用正斜杠
/分隔。层级顺序通常从一般到具体(类似于文件路径或 URL)。- 例如:
home/livingroom/temperature,factory/building1/machine5/rpm,sensors/+/status,$SYS/broker/clients/connected
- 例如:
2. 主题规则与最佳实践
- 区分大小写: 主题名称是区分大小写的。
home/temp和Home/Temp是两个不同的主题。 - 长度限制: MQTT 协议本身没有硬性规定主题的最大长度,但实际实现(Broker 和 Client 库)通常有限制(例如 65535 字节)。设计时应考虑合理长度。
- 允许字符: 主题层级可以使用任何 UTF-8 字符(包括中文、日文等),但以下字符有特殊含义或限制,强烈建议避免在普通主题层级中使用:
/: 层级分隔符。+: 单层通配符 (不能单独作为主题发布)。#: 多层通配符 (不能单独作为主题发布)。$: 系统主题前缀。以$SYS/开头的主题通常由 Broker 内部使用,用于发布 Broker 自身的状态信息(如客户端连接数、消息统计等)。客户端通常可以订阅这些主题来监控 Broker,但发布消息时避免使用$开头的主题,以免与系统主题冲突。不同 Broker 的$SYS主题结构可能不同。
- 空层级: 连续的
/(如home//temperature)或开头/结尾的/(如/home/temp或home/temp/)会形成空层级。虽然语法上允许,但强烈不推荐,因为它可能导致混淆和通配符匹配问题。尽量使用明确的层级(如home/temp)。 - 最佳实践:
- 设计有意义的层级结构: 按照业务逻辑或设备属性组织主题(如
区域/位置/设备类型/设备ID/数据项)。 - 避免主题泛滥: 不要为每个可能的数据点创建独立的主题,合理使用通配符订阅。
- 保持简洁: 在保证清晰的前提下,主题层级不宜过深过长。
- 避免敏感信息: 不要在主题中包含密码等敏感信息(主题内容可能被未订阅的客户端嗅探到)。
- 明确命名: 使用清晰、一致的命名规范。
- 设计有意义的层级结构: 按照业务逻辑或设备属性组织主题(如
3. 通配符 (Wildcards)
通配符允许订阅者订阅一组符合特定模式的主题,是 MQTT 订阅功能强大的关键。有两种通配符:
-
单层通配符
+(Plus):- 含义: 匹配该层级的任意一个字符串。只能匹配一层。
- 位置: 可以出现在主题订阅的任何层级。
- 示例:
- 订阅
home/+/temperature:- 匹配:
home/livingroom/temperature(+=livingroom) - 匹配:
home/kitchen/temperature(+=kitchen) - 不匹配:
home/livingroom/thermostat/temperature(+只匹配一层,这里是livingroom,后面还有thermostat这一层) - 不匹配:
home/temperature(+需要匹配一层,但home和temperature之间没有层级了)
- 匹配:
- 订阅
+/status:- 匹配:
sensor1/status(+=sensor1) - 匹配:
machineA/status(+=machineA) - 不匹配:
building1/floor2/machineA/status(+只匹配了building1,后面还有多层)
- 匹配:
- 订阅
sensors/+/+/battery:- 匹配:
sensors/floor1/room101/battery(第一个+=floor1, 第二个+=room101) - 匹配:
sensors/outside/gate/battery(第一个+=outside, 第二个+=gate) - 不匹配:
sensors/device123/battery(需要两个层级,这里只有device123一层) - 不匹配:
sensors/buildingA/floor3/room305/battery(只有两个+,这里有三层buildingA/floor3/room305)
- 匹配:
- 订阅
-
多层通配符
#(Hash/Number Sign/Pound):- 含义: 匹配零个或多个层级。它必须是订阅主题字符串中的最后一个字符,且前面必须有
/(除非它是整个订阅字符串)。 - 位置: 只能出现在订阅主题的末尾。
- 示例:
- 订阅
home/#:- 匹配:
home/livingroom/temperature(#匹配了/livingroom/temperature) - 匹配:
home/kitchen/humidity(#匹配了/kitchen/humidity) - 匹配:
home(#匹配了零个层级 - 注意:home和home/是不同的主题!home/#会匹配home/...但不直接匹配home,除非 Broker 特殊处理或主题是home/。更安全的做法是如果需要匹配home本身,单独订阅home或使用home和home/#两个订阅。) - 不匹配:
house/garage/temperature(主题必须以home开头)
- 匹配:
- 订阅
sensors/#:- 匹配:
sensors/temperature(#匹配了零个层级?不,sensors/temperature是sensors下的一个层级,#匹配了/temperature) - 匹配:
sensors/building1/floor2/room301/humidity(#匹配了/building1/floor2/room301/humidity) - 匹配:
sensors(同上home的情况,sensors/#通常不直接匹配sensors,除非是sensors/)
- 匹配:
- 订阅
#: (非常危险!谨慎使用!)- 匹配:Broker 上所有主题的消息(包括系统主题
$SYS/...)。 - 后果: 客户端将收到海量可能无关的消息,消耗大量网络带宽、CPU 和内存资源。也可能收到敏感信息。仅在调试或绝对必要时使用,生产环境强烈避免。
- 匹配:Broker 上所有主题的消息(包括系统主题
- 订阅
- 含义: 匹配零个或多个层级。它必须是订阅主题字符串中的最后一个字符,且前面必须有
4. 重要注意事项
- 通配符仅用于订阅: 客户端只能在
SUBSCRIBE数据包的主题过滤器中使用+和#。在PUBLISH数据包的主题名中不能使用通配符!发布主题必须是明确的、不含通配符的字符串。 $SYS主题与通配符:- 订阅
#或$SYS/#会收到$SYS/...主题的消息。 - 订阅
+/monitor不会匹配$SYS/broker/monitor,因为$是一个普通字符,+匹配了$SYS,但下一层broker没有被匹配到模式+/monitor(broker/monitor是两层)。 - 要订阅所有
$SYS下的主题,用$SYS/#。
- 订阅
- 匹配是逐层进行的: Broker 在匹配主题时,是严格按照层级和通配符规则逐层比较的。
- 性能影响: 大量使用通配符(尤其是
#)订阅会增加 Broker 路由消息的计算开销。设计主题结构时应考虑平衡灵活性和效率。 - 安全性: 通配符订阅可能让客户端意外订阅到包含敏感信息的主题(如果主题设计不当或存在恶意发布者)。使用 MQTT 的认证和授权机制(用户名/密码、客户端证书、ACL)来严格控制客户端对主题的发布和订阅权限至关重要。
总结:
- 主题是地址标签,用
/分隔层级。 +匹配一层中的任意字符串。#匹配零层或多层,必须放在订阅主题末尾。- 通配符只能用于订阅,不能用于发布。
- 设计清晰、有层次的主题结构,谨慎使用通配符(特别是
#)。 - 始终考虑安全性和性能。
理解并熟练运用主题和通配符是构建高效、灵活 MQTT 应用的基础。务必根据你的具体业务场景仔细设计主题命名空间。

浙公网安备 33010602011771号