client.connect()后必须调用token.waittimeout()并检查错误,否则publish/subscribe会panic或静默失败;subscribe handler不可为nil;qos=0收不到消息需排查broker配置;disconnect()不应defer,应监听信号显式调用。

client.Connect() 返回 token 后必须显式等待连接就绪,否则 publish/subscribe 会静默失败或 panic。
一款AI音频处理工具,主要用于通过向 `toingg/make_campaign` API 发送 POST 请求,提交用户提供的 JSON 数据,创建并启动 Toingg 语音呼叫活动,适用于 Codex 将活动简报……,适合需要提升相关任务效率的用户。
token.Wait() 必须调用,但不能裸等主线程
-
client.Connect()是异步操作,返回的token只表示“连接请求已发出”,不代表 TCP 握手完成、MQTT 协议层 CONNECT 报文已确认 - 不调
token.Wait()就直接client.Publish(),大概率触发panic: client is not connected,或更糟:静默丢包(无错误、无日志、消息根本没发出去) - 生产环境禁用无限阻塞的
token.Wait();改用token.WaitTimeout(5 * time.Second),并检查两个条件:token.Error() != nil-
token.WaitTimeout(...)返回true(超时返回false,此时连接未就绪)
- 建议搭配
opts.SetAutoReconnect(true)和opts.OnConnectionLost回调,应对网络抖动
订阅时 handler 传 nil 就等于没订阅
-
client.Subscribe("sensor/temp", 1, nil)看似合法,但 MQTT 库不会注册任何回调——收到消息后直接丢弃,连日志都不会打 - handler 必须是非
nil函数,哪怕只是打印:func(client mqtt.Client, msg mqtt.Message) { fmt.Println("recv:", string(msg.Payload())) } - handler 内部严禁做耗时操作(如 HTTP 请求、DB 写入),否则阻塞整个 MQTT 事件循环;应把
msg推入chan mqtt.Message,由独立 goroutine 处理 - 循环订阅多个 topic 时,避免闭包捕获循环变量:
for _, t := range topics { topic := t // ← 关键:创建局部副本 client.Subscribe(topic, 0, func(c mqtt.Client, m mqtt.Message) { fmt.Printf("from %s: %s\n", topic, string(m.Payload())) }) }
qos=0 发出去却收不到?先查 broker 配置
-
qos=0本身不保证送达,但“完全收不到”往往不是协议问题,而是 broker 行为导致:-
clean session=true+qos=0→ 消息不存、不投递、不重试,断连即清空所有待投递状态 - broker 禁用了匿名访问(
allow_anonymous=false)但客户端没传用户名/密码 - 主题权限未配置(EMQX 的 ACL 规则拒绝了该 client ID 对该 topic 的 publish/subscribe)
-
- 调试阶段优先用公共 broker:
tcp://broker.hivemq.com:1883,排除本地环境干扰 - 生产必须用自建或托管 broker(如 EMQX),并确认:
-
max_connections足够支撑并发设备数 - TLS 配置与客户端匹配(mqtts 端口、证书链完整、
InsecureSkipVerify不在生产启用)
-
client.Disconnect() 别放 defer
-
defer client.Disconnect(250)在main()函数里基本无效:Go runtime 在main返回后快速回收资源,Disconnect()可能根本没发完 MQTT DISCONNECT 报文就被 OS 强制 kill 连接 - 正确做法是监听系统信号,显式控制退出流程:
c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, syscall.SIGTERM)
- 如果是长期运行的服务(如 daemon),还要考虑优雅关闭:停止接收新消息、等待正在处理的 handler 完成、再断连
MQTT 的坑不在协议本身,而在连接生命周期、broker 状态、QoS 语义和 Go 并发模型三者的交界处。最容易被忽略的是:token.WaitTimeout() 返回 true 才代表连接真正可用,仅检查 Error() 不够。










