2. MQTT协议基础概念:Broker、Client、Topic、Payload、Session、Will Message等核心术语详解

好,咱们正式开始聊MQTT的核心概念。说实话,很多初学者一上来就被这些术语搞懵了。什么Broker、Client、Topic……听着像是一堆专业黑话。其实没那么复杂,你把它想象成一个「消息快递系统」,一下子就通了。

我个人习惯把MQTT比作一个「邮局」。Client就是寄信人和收信人,Broker就是邮局本身,Topic就是地址,Payload就是信的内容。嗯,咱们一个一个拆开讲。

2.1 Broker——消息的中枢神经

Broker,说白了就是MQTT服务器。所有消息都得经过它。它不生产消息,它只是消息的搬运工。

我在项目中遇到过一种情况:团队里有人把Broker和Client搞混了,结果调试了一整天,发现消息根本没发出去。为什么?因为Client之间不直接通信,所有数据都得走Broker中转。

Broker的核心职责:

  • 接收Client发来的消息
  • 根据Topic将消息转发给订阅者
  • 管理Client的会话状态
  • 处理遗嘱消息(Will Message)

常见的Broker实现有Mosquitto、EMQX、VerneMQ。我个人偏爱Mosquitto,轻量、稳定,适合嵌入式场景。

2.2 Client——消息的发送者与接收者

任何连接到Broker的设备,都叫Client。它可以是一个传感器、一部手机、一台服务器,甚至是一个微服务。

Client有两种角色:

  • Publisher(发布者):发送消息的一方
  • Subscriber(订阅者):接收消息的一方

你想想看,同一个Client可以同时扮演两种角色。比如一个温度传感器,它既发布温度数据,又订阅控制指令。这在IoT场景里太常见了。

我的经验:设计Client时,一定要考虑断线重连机制。我曾经见过一个设备,网络一抖就再也连不回来了,最后只能派人去现场重启。嗯,这种坑踩过一次就够了。

2.3 Topic——消息的地址标签

Topic就是消息的「地址」。它用斜杠分隔层级,比如:

sensor/temperature/room1
sensor/humidity/room2
device/light/status

Topic支持通配符:

  • +:匹配单层。比如 sensor/+/room1 匹配 sensor/temperature/room1sensor/humidity/room1
  • #:匹配多层。比如 sensor/# 匹配所有以 sensor/ 开头的Topic

我记得有一次,团队里有人把Topic设计成 data/2024/01/15/temperature,结果订阅时用了 data/#,一下子把所有历史数据都拉下来了。嗯,Topic设计要谨慎,层级别太深,也别太浅。

避坑指南:Topic不要以斜杠开头或结尾。比如 /sensor/tempsensor/temp/ 都是不规范的做法。我曾经因为这个导致订阅匹配失败,排查了半天才发现是斜杠的问题。

2.4 Payload——消息的实体内容

Payload就是消息里真正要传输的数据。它可以是任何格式:JSON、XML、二进制、纯文本……MQTT本身不限制。

我个人建议用JSON,可读性好,解析方便。比如:

{
  "device_id": "sensor_01",
  "temperature": 25.6,
  "humidity": 60.2,
  "timestamp": 1700000000
}

但要注意,Payload大小有限制。默认情况下,MQTT最大支持256MB的Payload。不过在实际项目中,我建议控制在1KB以内。为什么?因为大消息会占用带宽,增加延迟,还容易导致内存溢出。

我的习惯:Payload里只放必要字段。别把整个设备状态都塞进去。我曾经见过一个Payload,里面包含了设备型号、固件版本、WiFi信号强度……其实订阅者只需要温度数据。浪费带宽不说,还增加了解析负担。

2.5 Session——Client与Broker的「记忆」

Session就是Client和Broker之间的「会话」。它记录了订阅关系、未送达的消息等状态。

Session有两种模式:

模式 说明 适用场景
Clean Session = true 每次连接都是全新会话,断开后Broker不保留任何状态 临时设备、测试环境
Clean Session = false Broker保留会话状态,断线重连后恢复 生产环境、需要持久订阅的设备

你想想看,如果一个传感器每5秒发一次数据,断线后重连,你希望它丢失这5秒的数据吗?当然不希望。所以生产环境中,我一般建议用持久会话。

关键点:持久会话会占用Broker的内存。如果设备数量很大(比如10万+),要评估Broker的承载能力。我曾经遇到过Broker内存爆掉的情况,就是因为持久会话太多,没及时清理。

2.6 Will Message——设备的「遗言」

Will Message,中文叫遗嘱消息。它是Client在连接时预先设定的一条消息。当Client意外断开时,Broker会替它把这条消息发出去。

举个例子:

// Client连接时设置遗嘱消息
client.connect({
  will: {
    topic: 'device/status',
    payload: JSON.stringify({ device_id: 'sensor_01', status: 'offline' }),
    qos: 1,
    retain: true
  }
});

当这个传感器突然掉线,Broker就会向 device/status 这个Topic发送一条消息,内容是 {"device_id": "sensor_01", "status": "offline"}。其他订阅了这个Topic的Client就能立刻知道:哦,那个传感器挂了。

避坑指南:遗嘱消息只在「意外断开」时触发。如果Client主动发送DISCONNECT报文正常断开,遗嘱消息不会发送。我曾经踩过这个坑:调试时手动断开连接,发现遗嘱没发,还以为是Broker的bug,结果是自己没搞清楚触发条件。

另外,遗嘱消息的QoS和Retain标志也要注意。我建议QoS至少设为1,确保消息能送达。Retain设为true的话,新订阅者一上来就能收到这个离线状态,非常实用。

2.7 小结

好了,核心术语咱们过了一遍。Broker是中枢,Client是端点,Topic是地址,Payload是内容,Session是记忆,Will Message是遗言。这六个概念,是理解MQTT的基石。

你想想看,掌握了这些,再看MQTT的报文交互,是不是清晰多了?下一章咱们就深入报文结构,看看这些概念在网络上是怎么传输的。

嗯,今天就到这儿。有问题随时交流。