跳转到内容

Broker 与客户端角色

本节详细介绍 MQTT 中 Broker 和客户端的角色、功能和工作方式。学习完成后,您将能够:

  • 理解 MQTT Broker 的核心功能和职责
  • 区分不同客户端类型及其作用
  • 掌握 Broker 的连接管理和会话维护机制
  • 评估不同场景下的 Broker 选型

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

  • 理解发布-订阅架构
  • Mosquitto Broker 已安装运行
  • 已安装 MQTT 命令行工具或 MQTT Explorer

MQTT Broker 是消息系统的核心枢纽,负责以下关键功能:

┌───────────────────────────────────────────────────────┐
│ MQTT Broker │
├───────────────────────────────────────────────────────┤
│ │
│ 1. 消息接收与路由 │
│ ┌────────┐ ┌──────────┐ ┌────────┐ │
│ │ Publisher│───→│ Topic 路由 │───→│Subscriber│ │
│ └────────┘ └──────────┘ └────────┘ │
│ │
│ 2. 连接管理 │
│ ┌──────────────────────────────────────────────┐ │
│ │ 客户端认证 → 会话创建 → 连接保持 → 断线检测 │ │
│ └──────────────────────────────────────────────┘ │
│ │
│ 3. 消息质量管理 │
│ QoS 0: 直接转发 │
│ QoS 1: 等待 PUBACK │
│ QoS 2: 双段握手 (PUBREC → PUBREL → PUBCOMP) │
│ │
│ 4. 状态管理 │
│ - 保留消息 (Retained Messages) │
│ - 遗嘱消息 (Last Will) │
│ - 离线消息缓存 (Pending Messages) │
│ │
└───────────────────────────────────────────────────────┘

Broker 根据 Topic 进行消息路由的核心机制:

发布消息: factory/zone1/temperature
┌─────────────────┐
│ Topic 匹配引擎 │
└─────────────────┘
┌──────────┼──────────┐
↓ ↓ ↓
[Subscribers] [Subscribers] [Subscribers]
factory/# factory/+/temperature factory/zone1/temperature

匹配规则

  • 完全匹配:Topic 完全相同时直接转发
  • 通配符订阅:+ 匹配单级,# 匹配多级
  • 系统 Topic:以 $SYS/ 开头的内部管理 Topic

1. Publisher(发布者)

  • 功能:向特定 Topic 发送消息
  • 特点:不需要订阅任何 Topic
  • 典型设备:传感器节点、数据采集器

2. Subscriber(订阅者)

  • 功能:接收订阅 Topic 的消息
  • 特点:不需要发布任何消息
  • 典型设备:仪表板、数据存储、手机 App

3. Publisher + Subscriber

  • 功能:同时发布和订阅
  • 特点:双向通信能力
  • 典型设备:智能插座(上报状态 + 接收控制命令)

MQTT 客户端连接状态管理:

状态转换图:
DISCONNECTED
│ CONNECT (发送 CONNECT 报文)
CONNECTING
│ CONNACK (接收连接确认)
CONNECTED ←──────────────────┐
│ │
│ Publish/Subscribe │ PING (心跳保活)
↓ │
ACTIVE ──────────────────────┘
│ DISCONNECT / 连接中断
DISCONNECTED → 触发 Last Will (遗嘱消息)

每个 MQTT 客户端连接时必须使用唯一的 Client ID:

Client ID 命名规范:
✅ 推荐格式:
esp32_factory_001 # 设备类型_位置_编号
sensor_temp_zone1 # 传感器类型_区域
dashboard_main # 应用类型_名称
❌ 避免格式:
esp32 # 太通用,容易冲突
client_1 # 毫无信息量
test # 仅用于测试

Client ID 管理

// ESP32 中自动生成唯一 Client ID
#include <WiFi.h>
String generateClientID() {
// 使用 MAC 地址生成唯一 ID
uint64_t chipid = ESP.getEfuseMac();
String clientID = "esp32_" + String((uint16_t)(chipid >> 32), HEX)
+ String((uint32_t)chipid, HEX);
return clientID;
}

MQTT 连接建立过程:

Client Broker
│ │
│─── CONNECT ──────────────────────→│
│ Protocol Level: 4 (v3.1.1) │
│ Client ID: esp32_001 │
│ Clean Session: true │
│ Keep Alive: 60 seconds │
│ Username: (optional) │
│ Password: (optional) │
│ Last Will Topic: (optional) │
│ Last Will Message: (optional) │
│ │
│←── CONNACK ───────────────────────│
│ Session Present: false │
│ Return Code: 0 (Accepted) │
│ │
│======== Connection Established ====│

CONNACK 返回码说明

返回码含义处理方式
0连接接受正常通信
1不接受的协议版本检查 MQTT 版本
2标识符被拒更换 Client ID
3服务器不可用稍后重试
4用户名或密码错误检查认证信息
5未授权检查权限配置

心跳机制维护客户端连接状态:

keepAlive 间隔 (客户端声明,如 60 秒)
├── 客户端应当在 1.5×keepAlive 内发送 PINGREQ
├── Broker 如果超过 1.5×keepAlive 未收到消息
│ 或 PINGREQ,则判定客户端离线
└── 离线后 Broker 发送 Last Will 消息
# mosquitto.conf 核心配置
# 监听端口
listener 1883 # 非加密 MQTT
listener 9001 # WebSocket(浏览器用)
# 认证配置
allow_anonymous false # 禁止匿名连接
password_file /mosquitto/config/passwd # 密码文件
# 持久化配置
persistence true
persistence_location /mosquitto/data/
# 日志配置
log_dest file /mosquitto/log/mosquitto.log
log_type all
connection_messages true
# 客户端限制
max_connections -1 # 无限制
max_inflight_messages 20 # 最大并发消息数
max_queued_messages 100 # 最大队列消息数
# 大小限制
message_size_limit 0 # 无限制
Terminal window
# 创建用户密码
docker exec -it mosquitto mosquitto_passwd -c /mosquitto/config/passwd esp32_user
# 输入密码并确认
# 查看已创建的用户
cat mosquitto/config/passwd
特性MosquittoEMQX
开发语言CErlang
许可证Eclipse Public LicenseApache 2.0 (开源版)
单节点连接数~10,000~1,000,000
集群支持有限(桥接)原生支持
消息路由单线程多线程高并发
Web Dashboard无(需第三方)内置
规则引擎内置
适合场景中小型部署大规模/高可用部署
部署复杂度低(单一二进制)中(依赖 Erlang)
资源占用低(~10MB 内存)中(~100MB+ 内存)
场景推荐 Broker理由
个人项目/学习Mosquitto简单、轻量
小型企业 (< 100 设备)Mosquitto够用、配置简单
中型部署 (100-1000 设备)Mosquitto 或 EMQX视复杂度决定
大规模部署 (1000+)EMQX集群能力
需要高可用EMQX 集群原生支持
IoT 云平台EMQX 企业版规则引擎+数据桥接
Terminal window
# 检查 Broker 状态
docker ps | grep mosquitto
# 查看日志
docker logs mosquitto --tail 20
# 测试连接
mosquitto_sub -h localhost -t "test" -v &
mosquitto_pub -h localhost -t "test" -m "hello"
# 预期:订阅端收到 "hello"

症状:客户端无法连接 Broker

可能原因

  • Broker 未运行
  • 端口被防火墙阻止
  • 认证失败

解决方案

Terminal window
# 检查 Broker 是否运行
docker ps | grep mosquitto
# 检查端口
netstat -an | grep 1883
# 临时允许匿名连接测试
# 修改 mosquitto.conf:
# allow_anonymous true

症状:一个客户端频繁掉线重连

可能原因:多个客户端使用相同的 Client ID

解决方案

  1. 确保每个设备使用唯一的 Client ID
  2. ESP32 使用 MAC 地址生成 Client ID
  3. 使用 UUID 作为 Client ID

本节要点总结:

  1. Broker 核心功能:消息路由、连接管理、QoS 支持、状态管理
  2. 客户端类型:Publisher、Subscriber 或两者兼具
  3. 连接管理:CONNECT/CONNACK 握手机制,Keep Alive 心跳保活
  4. 身份标识:Client ID 必须唯一,建议使用设备特征生成
  5. Broker 选型:Mosquitto 适合中小规模,EMQX 适合大规模高可用