
本文详解如何使用 go 语言和 websocket 实现一个支持**指定用户私聊**(而非仅广播)的轻量级实时聊天系统,涵盖服务端消息路由、客户端连接管理及会话隔离等核心机制。
要构建一个支持“发送消息给选定用户”(即私聊)的 Go WebSocket 聊天服务,关键在于打破全广播模型,转而实现基于用户标识(如用户名或唯一 ID)的精准消息投递。官方推荐的经典示例——Gary Burd 的 go-websocket-chat(虽已归档,但源码仍广泛可用)——默认采用广播模式;我们需要在此基础上扩展用户注册、会话绑定与定向转发能力。
核心改造思路
- 为每个连接分配唯一用户标识:客户端在建立 WebSocket 连接后,需立即发送 {"type":"register","username":"alice"} 类型的认证消息;
- 服务端维护用户-连接映射表:使用 map[string]*Client(string 为 username,*Client 为封装了 *websocket.Conn 和 send channel 的结构体);
- 消息协议升级:支持 {"type":"private","to":"bob","body":"Hello!"},服务端解析后仅向 bob 的连接写入消息;
- 并发安全处理:所有映射读写需加 sync.RWMutex 保护。
精简服务端关键逻辑(Go)
type Client struct {
username string
conn *websocket.Conn
send chan []byte
}
var (
clients = make(map[string]*Client)
mu sync.RWMutex
)
func handleWS(w http.ResponseWriter, r *http.Request) {
conn, _ := upgrader.Upgrade(w, r, nil)
client := &Client{conn: conn, send: make(chan []byte, 256)}
// 首次接收注册消息
_, msg, _ := conn.ReadMessage()
var reg struct{ Type, Username string }
json.Unmarshal(msg, ®)
if reg.Type == "register" && reg.Username != "" {
mu.Lock()
clients[reg.Username] = client
client.username = reg.Username
mu.Unlock()
}
// 启动读/写协程
go client.writePump()
client.readPump()
}
func (c *Client) readPump() {
defer func() { c.conn.Close() }()
for {
_, msg, err := c.conn.ReadMessage()
if err != nil { break }
var m struct{ Type, To, Body string }
json.Unmarshal(msg, &m)
if m.Type == "private" && m.To != "" {
mu.RLock()
target, ok := clients[m.To]
mu.RUnlock()
if ok {
target.send <- []byte(fmt.Sprintf(`{"from":"%s","body":"%s"}`, c.username, m.Body))
}
}
}
}
func (c *Client) writePump() {
defer func() { c.conn.Close() }()
for msg := range c.send {
c.conn.WriteMessage(websocket.TextMessage, msg)
}
}注意事项与最佳实践
- ✅ 永远校验用户名唯一性:注册前检查 clients 中是否已存在同名用户,避免覆盖;
- ✅ 添加连接超时与心跳:使用 conn.SetReadDeadline() 防止僵尸连接占用资源;
- ✅ 敏感操作需鉴权:生产环境应集成 JWT 或 Session 验证,防止伪造用户名;
- ⚠️ 避免直接暴露 username 作为 key:建议改用 UUID + 用户名映射,提升安全性;
- ? 客户端需维护在线用户列表(通过服务端推送 user_online/user_offline 事件同步)。
通过以上设计,你将获得一个可扩展、易调试的私聊 WebSocket 聊天骨架。它不依赖第三方框架,完全基于 Go 标准库 net/http 和 gorilla/websocket,适合学习底层通信原理或快速搭建 MVP。










