必须显式等待 token 完成连接,订阅需传非 nil handler,QoS 0 不保证送达,Broker 地址和 TLS 配置须严格匹配,容错需结合自动重连与连接丢失回调。

直接用 eclipse/paho.mqtt.golang 就能跑通,但跳过 token.WaitTimeout()、传 nil handler、忽略 QoS 语义,90% 的“收不到”“发不出”问题都会出现。
connect() 后必须显式等 token 完成
MQTT 连接是异步的。client.Connect() 立即返回一个 token,不代表已连上 Broker。不等就发消息或订阅,轻则静默失败,重则 panic:panic: client is not connected。
-
token.Wait()是阻塞等待,适合脚本;生产环境务必用token.WaitTimeout(5 * time.Second)防卡死 - 检查不能只看
token.Error() != nil,还要确认token.WaitTimeout()返回true,否则可能是超时而非失败 - 配合
opts.SetAutoReconnect(true)和opts.OnConnectionLost才算完整容错
Subscribe 必须传非 nil 的 MessageHandler
client.Subscribe("sensor/temp", 1, nil) 看似合法,实际等于“订了但不看消息”——库收到消息后直接丢弃,不报错也不 log。
- handler 函数签名必须是
func(client MQTT.Client, msg MQTT.Message),哪怕只做fmt.Println(string(msg.Payload())) - handler 内部别做耗时操作(如 DB 写入、HTTP 调用),否则阻塞整个 MQTT 事件循环;应把
msg推进一个chan MQTT.Message,由独立 goroutine 消费 - 循环订阅多个 topic 时,避免闭包捕获循环变量:
for _, t := range topics { client.Subscribe(t, 1, func() {}) }中的t会被所有 handler 共享;应写成topic := t; client.Subscribe(topic, 1, handler)
QoS 0 不等于“不可靠”,但行为高度依赖 Broker 配置
client.Publish("cmd/led", 0, false, []byte("on")) 发出去没回音?不是 Go 代码问题,而是 QoS 0 本身不保证送达,且受 Broker clean session 和 retain 设置影响。
立即学习“go语言免费学习笔记(深入)”;
- 若订阅者晚于发布者上线,且 Broker 启用了
clean_session=true(默认),QoS 0 消息就真的消失了——它不存、不转发、不重试 - 测试阶段先用公共 Broker(如
tcp://broker.hivemq.com:1883)排除本地配置干扰 - 生产环境必须确认 EMQX/Mosquitto 的
allow_anonymous、max_connections、max_qos参数允许你用的 QoS 等级 - 业务关键消息别硬扛 QoS 0:要么升到 QoS 1(Broker 必须支持 PUBACK),要么在应用层加 ACK 机制
Broker 地址和 TLS 配置最容易被忽略
常见错误现象:连接后立即断开、token.Wait() 卡住、订阅无响应。多数是因为地址格式或 TLS 配置不对。
-
AddBroker("tcp://localhost:1883")中协议前缀必须明确,不能只写"localhost:1883" - 若 Broker 启用了 TLS(如 EMQX 默认开启 8883),得用
"ssl://"并配置opts.SetTLSConfig() - WebSocket 场景下要用
"ws://"或"wss://",不能混用tcp://和wss:// - 使用
ssl://时,SetTLSConfig()里必须设置InsecureSkipVerify: true(开发调试)或提供正确 CA 证书(生产)
真正难的不是连上,而是让连接在 K8s Pod 驱逐、防火墙中断、Broker 重启这些真实场景中自动恢复;OnConnectionLost 回调里清缓存、暂停采集、重置状态,比任何重连逻辑都关键。


















