MQTT 协议模型:客户端、 broker 与主题详解(三)
核心角色(客户端、 broker)的定义与功能,主题(Topic)的层级结构与通配符规则,消息(Message)的组成( payload、QoS、Retain),会话与连接的概念。
五、MQTT 主题
5.1 主题定义与结构
MQTT 主题是 MQTT 协议中消息路由的关键元素,本质上是一个 UTF - 8 编码的字符串 。它采用层级结构,类似于文件系统的路径或 URL 路径,使用斜杠(“/”)作为层级分隔符 。例如,“home/bedroom/temperature” 就是一个典型的 MQTT 主题,其中 “home” 是顶级层级,“bedroom” 是二级层级,“temperature” 是三级层级,这种层级结构使得主题具有很强的逻辑性和可读性,方便对消息进行分类和管理 。
在实际应用中,主题不需要预先创建 。当客户端首次向某个主题发布消息,或者订阅某个主题时,MQTT broker 会自动创建该主题 。例如在智能家居系统中,当智能温度传感器首次向 “home/kitchen/temperature” 主题发布温度数据时,broker 会自动创建这个主题 。同时,MQTT 主题区分大小写,“home/room/temperature” 和 “Home/Room/Temperature” 被视为不同的主题 。为了避免歧义且易于理解,通常不建议主题以 “/” 开头或结尾 ,如 “/home” 或 “home/” 这样的主题命名方式是不推荐的 。
5.2 主题通配符
MQTT 主题通配符为客户端订阅主题提供了更灵活的方式,允许客户端一次订阅多个相关主题 。通配符主要分为单层通配符(+)和多层通配符(#) 。
5.2.1 单层通配符(+)
单层通配符 “+” 用于匹配单个主题层级 。在使用时,它必须占据整个层级 。例如,“home/+/temperature” 这个主题过滤器中,“+” 可以匹配 “home” 下任意一个单层的主题,如 “home/livingroom/temperature”“home/studyroom/temperature” 等 。但它不会匹配 “home/livingroom/area1/temperature”,因为 “+” 只能匹配一个层级,而这里 “livingroom” 和 “area1” 是两个层级 。
单层通配符在实际应用中非常实用 。在一个智能办公大楼中,每层都有多个会议室,每个会议室都有温湿度传感器,传感器将数据发布到以 “office/building1/floor [X]/conferenceRoom [X]/temperature” 和 “office/building1/floor [X]/conferenceRoom [X]/humidity” 这样格式的主题上([X] 表示楼层号和会议室号) 。如果监控系统想要订阅所有会议室的温度数据,就可以使用 “office/building1/+/conferenceRoom+/temperature” 这个主题过滤器,通过单层通配符 “+”,可以方便地匹配到所有楼层和所有会议室的温度主题,而不需要为每个具体的会议室温度主题单独订阅 。
5.2.2 多层通配符(#)
多层通配符 “#” 用于匹配主题中任意层级的剩余部分 。它必须占据整个层级,并且必须是主题过滤器的最后一个字符 。例如,“home/#” 表示匹配 “home” 下的所有主题,包括 “home/bedroom/temperature”“home/kitchen/lighting/status”“home/garden/soil/moisture” 等,无论主题后面还有多少层级,都能被匹配 。而 “home/#/temperature” 是无效的,因为 “#” 必须是主题的最后一个字符 。
多层通配符适用于需要订阅某个顶级主题下所有子主题消息的场景 。在一个大型的工业自动化工厂中,所有设备的数据都发布在以 “factory/device” 为前缀的主题下,设备类型、设备 ID、数据类型等构成了后续的层级 。如果数据分析中心想要获取所有设备的所有数据,就可以订阅 “factory/device/#” 主题,这样无论工厂后续添加了新的设备类型,还是新的数据监测点,只要主题是以 “factory/device” 开头,都能被匹配到,大大提高了订阅的灵活性和扩展性 。但需要注意的是,由于多层通配符匹配范围广,使用时要谨慎,避免订阅过多不必要的消息,增加系统负载 。
5.3 系统主题
以 “\(SYS/”开头的主题被定义为系统主题 。系统主题主要用于获取MQTT服务器自身的运行状态、消息统计、客户端上下线事件等数据 。虽然目前MQTT协议暂未对“\)SYS/” 主题标准进行明确规定,但大多数 MQTT 服务器都遵循这一约定 。
以 EMQX 服务器为例,通过系统主题可以获取丰富的系统信息 。例如,“\(SYS/brokers”用于获取EMQX集群节点列表;“\)SYS/brokers/emqx@127.0.0.1/version” 可以获取指定节点的 EMQX 版本;“\(SYS/brokers/emqx@127.0.0.1/uptime”用于获取节点的运行时间;“\)SYS/brokers/emqx@127.0.0.1/datetime” 可获取节点的系统时间 。此外,还可以通过系统主题监听客户端上下线事件,如 “\(SYS/brokers/emqx@172.17.0.4/clients/+/connected”用于订阅客户端上线的主题,“\)SYS/brokers/emqx@172.17.0.4/clients/+/disconnected” 用于订阅客户端下线的主题 。
不过,监听系统主题通常需要在 broker 端开通对应的访问权限 。系统主题为系统管理员和开发者提供了深入了解 MQTT 服务器运行状况的途径,有助于进行系统监控、性能优化和故障排查等工作 。
5.4 主题别名(MQTT 5.0 新特性)
主题别名是 MQTT 5.0 引入的一项重要新特性 ,它允许客户端和服务器在互相通信时使用简短的整数值来代替完整的主题路径,从而减少传输的负载,提升传输效率和降低带宽消耗 。
在传统的 MQTT 通信中,每次消息传输都需要携带完整的主题字符串 。对于一些主题路径较长且固定的场景,如 “home/groundfloor/livingroom/temperature” 这样的主题,频繁传输完整主题会占用较多的带宽和资源 。而使用主题别名后,可以为这个主题分配一个别名,如 “1” 。在后续的消息传输中,只需要使用 “1” 来代替完整的主题路径,大大减少了数据传输量 。例如,第一个 PUBLISH 报文可能是:Topic Name: home/groundfloor/livingroom/temperature,Topic Alias: 1,Payload: 22°C ;之后的 PUBLISH 报文就可以简化为:Topic Alias: 1,Payload: 23°C 。
使用主题别名也有一些限制 。单个连接中,服务端最多支持 30 个 Topic 别名 ,如果客户端发送给服务端的消息中,topic 别名个数超过 30 个则关闭连接,并报 Topic 名字错误 。客户端向服务端声明自己支持的 Topic 别名个数最多设置为 30 个,超过 30 个,服务端推送消息时将不会设置 Topic 别名 。主题别名不能重复,Topic 和别名在一个连接中一一对应 ,且主题别名映射只对当前连接有效,重新连接不保证相同 Topic 的别名一样 。另外,Topic Alias 值不能是 0 ,客户端发送的 PUBLISH 的 Topic Alias 不能大于服务端 CONNACK 回复的 Topic Alias Maximum ,客户端必须接受所有大于 0 小于等于 Topic Alias Maximum 的 Topic Alias(其在 CONNECT 报文中设置的) ,且 Topic Alias 映射对于客户端和服务端不是相等的,例如客户端 PUBLISH 和服务端 PUBLISH 中的 Topic 别名都是 1,但是它们可能指向不同的 Topic 。
主题别名适用于多种场景 。在带宽受限的环境中,如一些通过低带宽网络连接的物联网设备,使用主题别名可以显著减少发送每条消息所需的数据量,降低带宽消耗 。对于高频率消息发布的场景,如股市行情跟踪系统,每秒都会发送大量的消息,使用主题别名可以极大地减少冗余信息的发送 。对于以电池供电的设备,减少数据传输量还可以延长设备的续航时间,例如远程监控站点或移动设备 。在资源受限的设备,如一些嵌入式设备和 IoT 设备,较短的主题别名可以使这些设备处理消息的速度更快并且占用更少的内存 。
六、三者关系与协同工作
6.1 客户端与 Broker 交互
客户端与 Broker 之间的交互是 MQTT 通信的基础,它们通过一系列的消息交换来实现连接建立、消息发布与订阅等功能 。
在连接阶段,客户端向 Broker 发送 CONNECT 报文,报文中包含客户端 ID、用户名、密码、遗嘱消息、心跳时间间隔以及清理会话标志等信息 。Broker 接收到 CONNECT 报文后,会进行身份验证、会话管理等操作,并返回 CONNACK 报文,告知客户端连接结果 。例如在一个智能安防系统中,摄像头客户端连接到 MQTT Broker 时,会在 CONNECT 报文中提供自身唯一的设备 ID 作为客户端 ID,以及预设的用户名和密码进行身份验证 。如果认证通过,Broker 返回的 CONNACK 报文的连接结果码为 0x00,表示连接成功 。
连接建立后,客户端可以进行消息发布和订阅操作 。当客户端要发布消息时,会向 Broker 发送 PUBLISH 报文,包含目标主题、消息内容、QoS 等级和保留标志等 。Broker 接收 PUBLISH 报文后,根据消息的主题和 QoS 等级,将消息分发给订阅了该主题的客户端 。例如在智能家居系统中,智能门锁客户端向 “home/security/doorlock” 主题发布门锁状态消息 “unlocked”,QoS 等级为 1 。Broker 收到消息后,会将其转发给订阅了该主题的手机 APP 客户端,确保用户能及时知晓门锁状态 。
当客户端需要订阅感兴趣的主题时,会向 Broker 发送 SUBSCRIBE 报文,包含要订阅的主题过滤器和期望的 QoS 等级 。Broker 验证订阅请求的合法性后,将订阅信息记录到订阅关系表中,并返回 SUBACK 报文确认订阅 。例如在一个城市交通监测系统中,交通数据分析平台客户端订阅 “city/traffic/congestion” 主题,QoS 等级为 1 。Broker 确认订阅成功后,返回的 SUBACK 报文中对应主题的返回码为 0x01,表示订阅成功且最大 QoS 为 1 。之后,当有交通传感器客户端向该主题发布交通拥堵信息时,Broker 会将消息转发给数据分析平台客户端 。
6.2 主题在交互中的作用
主题在 MQTT 客户端与 Broker 的交互中扮演着消息分类和路由的关键角色,是实现发布者和订阅者解耦的核心要素 。
对于发布者来说,主题是消息的目标地址 。发布者在发送消息时,必须指定消息所属的主题 。例如在一个气象监测网络中,各个气象站作为发布者,将采集到的温度、湿度、气压等数据分别发布到 “weather/station1/temperature”“weather/station1/humidity”“weather/station1/pressure” 等不同主题下 。通过明确的主题定义,发布者能够准确地将消息归类,方便后续的管理和处理 。
对于订阅者而言,主题是获取感兴趣消息的过滤器 。订阅者通过订阅特定主题或包含通配符的主题过滤器,来接收相关消息 。例如在一个农业物联网系统中,农场主的管理终端作为订阅者,可能订阅 “agriculture/field1/#” 主题过滤器,这样就能接收 “agriculture/field1/soil/moisture”“agriculture/field1/crop/growth” 等该农场一号田相关的所有主题消息,及时了解农田的各种信息 。
在 Broker 端,主题是消息路由的依据 。Broker 维护着一张主题订阅关系表,当收到发布者发送的消息时,会根据消息的主题,在订阅关系表中查找订阅了该主题的客户端列表,然后将消息转发给这些客户端 。例如在一个智能工厂中,设备状态监测系统作为 Broker,当收到某个生产设备客户端发布到 “factory/device1/status” 主题的设备故障消息时,会根据订阅关系,将消息发送给订阅了该主题的设备维护人员的手机 APP 客户端和工厂监控中心的服务器客户端,以便及时进行故障处理 。通过主题的这种分类和路由作用,MQTT 实现了发布者和订阅者之间的解耦,发布者无需关心哪些订阅者会接收消息,订阅者也无需知道消息的来源,提高了系统的灵活性和可扩展性 。
6.3 实际案例分析
以智能家居场景为例,深入剖析客户端、Broker 和主题如何协同工作 。
在这个智能家居系统中,存在多个智能设备作为客户端,如智能灯泡、智能窗帘、智能空调等 ,它们通过 Wi-Fi 连接到家庭中的 MQTT Broker,该 Broker 可以是运行在家庭网关设备上的 Mosquitto 服务 。同时,用户的手机 APP 也是一个客户端,用于远程控制和监测这些智能设备 。
假设用户想要通过手机 APP 打开客厅的智能灯泡 。手机 APP 客户端首先与 MQTT Broker 建立连接,在连接过程中,设置客户端 ID 为手机的唯一标识,进行身份验证(如用户名和密码验证),并设置心跳时间间隔以保持连接活性 。连接成功后,手机 APP 客户端向 Broker 发送 SUBSCRIBE 报文,订阅 “home/livingroom/bulb/status” 主题,以便接收灯泡的状态反馈,QoS 等级设置为 1,确保消息至少被接收一次 。
当用户在手机 APP 上点击 “打开灯泡” 按钮时,APP 客户端会向 Broker 发送 PUBLISH 报文,消息的主题为 “home/livingroom/bulb/control”,消息内容为 “ON”,QoS 等级同样设置为 1 。Broker 接收到该 PUBLISH 报文后,根据主题 “home/livingroom/bulb/control”,在其订阅关系表中查找订阅了该主题的客户端 。由于智能灯泡客户端订阅了该主题,Broker 将消息转发给智能灯泡客户端 。
智能灯泡客户端接收到 “ON” 的控制消息后,执行打开灯泡的操作,并向 Broker 发送 PUBLISH 报文,将灯泡的状态(“ON”)发布到 “home/livingroom/bulb/status” 主题,QoS 等级为 1 。Broker 收到灯泡状态消息后,根据订阅关系,将其转发给订阅了该主题的手机 APP 客户端 。手机 APP 客户端接收到灯泡状态消息后,更新界面显示,告知用户灯泡已成功打开 。
再比如,智能空调客户端会定时向 “home/livingroom/airconditioner/temperature” 主题发布室内温度数据,QoS 等级为 0(因为温度数据偶尔丢失一次对用户影响不大) 。用户的手机 APP 客户端可以订阅该主题,实时获取室内温度信息 。如果用户想要调节空调温度,在 APP 上设置温度后,APP 客户端会向 “home/livingroom/airconditioner/temperature/set” 主题发布新的温度设置值,智能空调客户端订阅了该主题,接收到设置值后进行相应的温度调节操作 。
在这个智能家居场景中,通过客户端、Broker 和主题的协同工作,实现了设备之间的高效通信和远程控制,展示了 MQTT 协议在实际应用中的强大功能和灵活性 。
更多推荐
所有评论(0)