connection refused 十有八九是端口或协议不匹配:mqtt 默认用 tcp://host:1883,websocket 客户端须连 ws://host:9001(需 broker 显式启用 websocket listener),且 nginx 代理需透传 upgrade 头。

MQTT 客户端连接不上 broker,connection refused 是不是端口错了?
十有八九是端口或协议没对上。MQTT broker(比如 Mosquitto)默认监听 1883(TCP),但 Web 浏览器里的 WebSocket 客户端必须走 ws:// 或 wss://,对应 broker 要额外启用 WebSocket listener,常见配错是只开了 1883 却让前端连 ws://localhost:1883 —— 这个端口不支持 WebSocket 协议。
- 检查 broker 配置是否启用了 WebSocket:Mosquitto 需在配置里加
listener 9001+protocol websockets - Go 后端用
github.com/eclipse/paho.mqtt.golang连 broker 时,URL 必须是tcp://host:1883,不能写成ws:// - 前端 JS 的
MQTT.js连接地址得是ws://your-server:9001,和 Go 后端连的不是同一个端口 - 如果用 Nginx 做反向代理 WebSocket,要显式透传 Upgrade 头:
proxy_set_header Upgrade $http_upgrade;和proxy_set_header Connection "upgrade";
Go 用 gorilla/websocket 接收前端 MQTT 消息,怎么转发给真实 MQTT broker?
别直接把 WebSocket 收到的原始字节当 MQTT 报文发出去——MQTT 协议有固定头、长度编码、QoS 控制字段,浏览器发来的只是 JSON 或字符串格式的“业务消息”,不是二进制 MQTT packet。
- 前端通常发的是类似
{"topic":"/device/001/temp","payload":"23.5","qos":1}这样的 JSON,Go 后端要先json.Unmarshal解析,再调用 MQTT client 的client.Publish -
client.Publish的payload参数类型是[]byte,别直接传字符串,用[]byte(s)转换 - 注意
qos字段:前端传0就用client.Publish(topic, 0, false, payload);传1或2时确保 broker 支持且 client 已设置SetAutoReconnect(true),否则 QoS > 0 的消息可能丢 - 别在 WebSocket
ReadMessage循环里直接 Publish——阻塞会导致连接假死,建议丢进 channel 由 goroutine 异步处理
设备上线/下线状态怎么实时推给前端?MQTT 的 $SYS 主题能直接用吗?
不能直接依赖 $SYS/broker/clients/+/connected 这类主题,它只反映 TCP 连接状态,而物联网设备常通过遗嘱(will)机制上报离线,且 $SYS 主题需 broker 显式开启,不同 broker 行为不一致(比如 EMQX 默认关闭,Mosquitto 需编译时加 flag)。
IoTSharp开源物联网是一个 基于.Net Core 开源的物联网基础平台, 支持 HTTP、MQTT 、CoAp 协议, 属性数据和遥测数据协议简单类型丰富,简单设置即可将数据存储在PostgreSql、MySql、Oracle、SQLServer、Sqlite,是一个用于数据收集、处理、可视化与设备管理的 IoT 平台。
- 更稳的做法是设备主动发布
/device/{id}/status,值为"online"或"offline",后端订阅该主题,收到后通过 WebSocket 广播给对应前端页面 - Go 订阅时用
client.Subscribe("/device/+/status", 1, handler),注意+是单层通配,#才是递归,别写成/device/#/status - 前端收到状态更新后,别直接改 DOM,先比对时间戳或版本号,避免网络延迟导致旧状态覆盖新状态
- 如果设备不支持主动上报,才考虑解析遗嘱消息:订阅时设
WillTopic和WillPayload,但要注意遗嘱触发有延迟(TCP 断连后 broker 检测超时才发),不适合秒级感知场景
并发量上来了,WebSocket 连接数暴涨,Go 后端 CPU 打满怎么办?
问题常出在 MQTT client 复用不当和 JSON 序列化/反序列化热点上。每个 WebSocket 连接都 new 一个 paho.Client 实例,会创建大量 TCP 连接和 goroutine,broker 端也扛不住。
立即学习“go语言免费学习笔记(深入)”;
- 全局复用一个 MQTT client 实例(或按 topic 分组复用),用
sync.Pool管理bytes.Buffer和json.Decoder,避免高频 GC - 别用
json.Marshal拼接大消息体,设备列表推送这种场景,提前生成好 JSON byte slice 缓存起来,用atomic.Value存最新快照 - WebSocket
WriteMessage是阻塞调用,高并发下容易卡住,加writeDeadline并捕获net.ErrWriteTimeout,超时直接 close 连接,别重试 - MQTT broker 的连接数上限(如 Mosquitto 的
max_connections)和 Go 的GOMAXPROCS要对齐,别让 Go 调度器空转等 I/O
真正难调的不是连接数,是设备频繁上下线引发的状态同步风暴——一个设备掉线,可能触发几十个前端页面重拉数据,这时候得加限流和合并更新,而不是堆机器。









