Go WebSocket 实战:用 gorilla/websocket 搭一个带心跳与广播的推送服务
test12026-10-151 次阅读
WebSocket 适合什么场景
HTTP 一问一答适合取数据,但聊天、行情推送、协同编辑这类"服务端主动推"的场景,用 WebSocket 更省连接。gorilla/websocket 是 Go 里最成熟的实现,下面写一个能跑的回声与广播服务。
握手与连接升级
package main
import (
"log"
"net/http"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool { return true },
}
func serve(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println("upgrade:", err)
return
}
defer conn.Close()
for {
mt, msg, err := conn.ReadMessage()
if err != nil {
break
}
conn.WriteMessage(mt, msg) // 回声
}
}
加心跳,挡掉死连接
客户端掉线时 TCP 不会立刻通知服务端,靠 ping/pong 定时探活:
func pump(conn *websocket.Conn, done chan<- struct{}) {
conn.SetReadDeadline(time.Now().Add(60 * time.Second))
conn.SetPongHandler(func(string) error {
conn.SetReadDeadline(time.Now().Add(60 * time.Second))
return nil
})
for {
if _, _, err := conn.ReadMessage(); err != nil {
done <- struct{}{}
return
}
}
}
// 定时发 ping
ticker := time.NewTicker(30 * time.Second)
go func() {
for range ticker.C {
conn.WriteMessage(websocket.PingMessage, nil)
}
}()
用 Hub 做多连接广播
type Hub struct {
clients map[*websocket.Conn]bool
mu sync.Mutex
}
func (h *Hub) broadcast(msg []byte) {
h.mu.Lock()
defer h.mu.Unlock()
for c := range h.clients {
if err := c.WriteMessage(websocket.TextMessage, msg); err != nil {
c.Close()
delete(h.clients, c)
}
}
}
上线前要补的
- 读消息加大小上限 SetReadLimit,防止超大帧打爆内存。
- 写操作加锁或用单独的写协程,WebSocket 并发写不是安全的。
- 反向代理(Nginx)要调大 proxy_read_timeout,否则长连被掐。
T
test1
文章作者
WebSocket 适合什么场景 HTTP 一问一答适合取数据,但聊天、行情推送、协同编辑这类"服务端主动推"的场景,...
- 分类
- 技术
- 发布时间
- 2026-10-15
- 字数
- 约 1747 字
- 阅读
- 1 次
