ReadMessage返回websocket.CloseAbnormalClosure(1006)时必须立即停止读循环、确认错误类型、清理资源并退出goroutine,不可忽略、log后继续循环或defer关闭,否则将引发panic或goroutine泄漏。

ReadMessage 返回 websocket.CloseAbnormalClosure(1006)不是 bug,是 TCP 层断连的协议兜底;你得立刻停读、清理资源、别再写,否则大概率 panic。
ReadMessage 返回 1006 时为什么不能直接 return 或 log 后继续循环
这个错误意味着底层 net.Conn 已不可用——浏览器关页、Nginx 超时、手机切后台、网络中断都会触发。此时再调 conn.WriteMessage 会 panic(use of closed network connection),conn.RemoteAddr() 可能 panic,defer conn.Close() 也大概率失效。
- 必须在
err != nil后第一件事调websocket.IsCloseError(err, websocket.CloseAbnormalClosure)确认类型,别用strings.Contains(err.Error(), "1006")这种脆弱判断 - 确认后立即 break 读循环,不要试图重试或 sleep 后再读
- 检查
conn != nil且未 panic 前,才做清理:从sync.Map删除连接、close()通知 channel、cancel()关联 context
主动关闭连接时如何让对端收到 1000 而不是 1006
直接调 conn.Close() 只会断 TCP,不发 WebSocket 关闭帧,对端收不到 1000。真正起作用的是先写 CloseMessage 帧。
- 正确顺序:
conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "bye")) -
websocket.FormatCloseMessage第二个参数是原因字符串,长度不能超 123 字节,否则会被截断或返回 error - 写完建议
time.Sleep(10 * time.Millisecond)再调conn.Close(),给对端时间响应;但如果WriteMessage已失败(比如网络已断),就跳过 sleep,直接conn.Close()
收到客户端 CloseMessage 帧时怎么回应才不 panic
客户端调 ws.close(1000),服务端 ReadMessage 不会返回消息,而是直接返回一个 error,且 websocket.IsCloseError(err, websocket.CloseNormalClosure) 为 true。
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
立即学习“go语言免费学习笔记(深入)”;
- 必须在本次函数调用内响应:立即
conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) - 写完立刻
return,不要继续ReadMessage或WriteMessage,否则下一次操作大概率触发use of closed network connection - 不要把响应逻辑放在
defer里——那时连接可能已关,WriteMessage会 panic
为什么 conn.Close() 后还收到 read: connection closed
这不是竞态 bug,是 Go WebSocket 库的必然行为:你调了 conn.Close(),但另一 goroutine 还卡在系统调用里(比如阻塞在 ReadMessage),下次调用就会立刻返回该错误。
- 安全做法是用
context.Context协同退出:每次ReadMessage前检查ctx.Err() != nil -
SetReadDeadline和SetPingPeriod必须配对使用——ping 间隔设 30s,deadline 至少设 45s,否则 pong 没回来就读超时,误判断连 - 别依赖
net.Conn.SetKeepAlive,它对 WebSocket 无效;心跳必须走协议层PingMessage/PongMessage
最易被忽略的一点:1006 错误本身无法预防,只能响应;而“响应是否及时、资源是否干净、goroutine 是否退出”才是决定服务稳定性的关键。任何延迟处理、二次读写、defer 收尾,都可能让一个 1006 演变成 goroutine 泄漏或 panic 雪崩。

















