Go标准库不支持WebSocket,需用gorilla/websocket;服务端用Upgrader升级连接后读写消息,客户端需手动拨号并处理重连与超时。
Go标准库不支持WebSocket,必须用第三方包
Go语言原生
包只提供HTTP协议支持,没有内置WebSocket实现。直接调用
的
方法或试图升级连接会失败,因为缺少WebSocket握手、帧解析和心跳等关键逻辑。
主流选择是
——它稳定、文档清晰、被大量生产项目验证。别用已归档的
,也不建议从零手写WebSocket帧处理。
服务端:用
建立连接并读写消息
核心是
升级HTTP请求,再用
收发数据。注意升级过程必须在HTTP handler中完成,且不能有任何前置
或
修改(否则触发
错误)。
默认拒绝
跨域
请求,开发时可临时设为
,生产环境应校验
头
读取消息用
,返回
,第一个值是消息类型(
或
)
发送消息用
,第二个参数必须是
;若传字符串,需先转
连接应显式关闭:
,否则可能泄漏goroutine和文件描述符
客户端:用
连接并处理断线重连
浏览器
端用
即可,但Go客户端需主动拨号。常见陷阱是忽略TLS配置(
需传
仅限测试)、未设置读写超时导致goroutine卡死。
立即学习
“
go语言免费学习笔记(深入)
”;
默认无超时,务必设置
和
(如需代理)
读写操作可能阻塞,建议用
和
控制超时
断线后不能复用旧
,必须重新
;重连逻辑需自己实现(例如指数退避)
发送JSON数据时,先
再
;接收时先
再
消息粘包与并发安全:每个连接应独占一个goroutine
本身不是并发安全的——多个goroutine同时调用
会panic(
)。但
可以并发调用,只要写操作被串行化。
典型模式:一个goroutine循环
,另一个goroutine负责
,通过
通信
不要在HTTP handler里直接处理业务逻辑,应把
交给worker goroutine,并用
确保清理
大消息(>1MB)可能触发
,需调大
和
真正难的是状态同步和连接生命周期管理,比如用户登录态如何绑定到Conn、如何广播消息给房间内所有人——这些不在WebSocket协议层,得自己设计。
net/httphttp.ResponseWriterWritegorilla/websocketgolang.org/x/net/websocketgorilla/websocketwebsocket.Upgrader*websocket.ConnWriteHeaderhttp: multiple response.WriteHeader callsUpgrader.CheckOriginfunc(r *http.Request) bool { return true }Originconn.ReadMessage()(int, []byte, error)websocket.TextMessagewebsocket.BinaryMessageconn.WriteMessage()[]byte[]byte("hello")conn.Close()package main
import (
"log"
"net/http"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool { return true },
}
func wsHandler(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println("Upgrade error:", err)
return
}
defer conn.Close()
for {
_, msg, err := conn.ReadMessage()
if err != nil {
log.Println("Read error:", err)
break
}
if err := conn.WriteMessage(websocket.TextMessage, msg); err != nil {
log.Println("Write error:", err)
break
}
}
}
func main() {
http.HandleFunc("/ws", wsHandler)
log.Fatal(http.ListenAndServe(":8080", nil))
}websocket.Dialnew WebSocket("ws://localhost:8080/ws")wss://&tls.Config{InsecureSkipVerify: true}websocket.DefaultDialerTLSClientConfigProxyconn.SetReadDeadline()conn.SetWriteDeadline()*websocket.ConnDialjson.MarshalWriteMessageReadMessagejson.Unmarshalwebsocket.ConnWriteMessageconcurrent write to websocket connectionReadMessageReadMessageWriteMessagechan []byteconndefer conn.Close()websocket: close sentUpgrader.ReadBufferSizeWriteBufferSize