WebSocket协议允许客户端和服务器之间建立持久的全双工连接,相比传统的HTTP轮询,它能大幅减少通信开销,非常适合实时聊天、数据推送等场景。在Golang生态中,gorilla_websocket是最常用的WebSocket库,功能完善且社区活跃,下面我们将基于这个库讲解完整的实现过程。

环境准备
首先需要安装gorilla_websocket库,执行以下命令即可完成安装:
go get github.com/gorilla/websocket
核心实现步骤
1. 升级HTTP连接到WebSocket
WebSocket连接由HTTP连接升级而来,我们需要先配置升级器参数,处理客户端的升级请求。升级器可以设置读取缓冲区大小、写入缓冲区大小、检查请求来源等参数。
package main
import (
"log"
"net/http"
"github.com/gorilla/websocket"
)
// 定义升级器,配置相关参数
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
// 检查请求来源,这里简单允许所有来源,生产环境需要自定义校验逻辑
CheckOrigin: func(r *http.Request) bool {
return true
},
}
2. 处理WebSocket连接
升级成功后,我们就得到了WebSocket连接对象,接下来可以在这个连接上进行消息的读取和发送。下面的代码实现了处理单个WebSocket连接的逻辑,包括读取客户端消息并回传。
// 处理WebSocket连接的函数
func handleWebSocket(w http.ResponseWriter, r *http.Request) {
// 升级HTTP连接为WebSocket连接
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Printf("升级连接失败: %v", err)
return
}
// 函数退出时关闭连接
defer conn.Close()
// 循环读取客户端消息
for {
// 读取消息类型和消息内容
messageType, message, err := conn.ReadMessage()
if err != nil {
log.Printf("读取消息失败: %v", err)
break
}
log.Printf("收到客户端消息: %s", message)
// 将收到的消息回传给客户端
err = conn.WriteMessage(messageType, message)
if err != nil {
log.Printf("发送消息失败: %v", err)
break
}
}
}
3. 注册路由并启动服务
我们需要将处理WebSocket的函数注册到对应的路由,然后启动HTTP服务,这样客户端就可以通过对应路径发起WebSocket连接了。
func main() {
// 注册WebSocket处理路由
http.HandleFunc("/ws", handleWebSocket)
// 启动HTTP服务,监听8080端口
log.Println("服务启动,监听端口8080")
err := http.ListenAndServe(":8080", nil)
if err != nil {
log.Fatalf("启动服务失败: %v", err)
}
}
连接管理与并发处理
实际场景中往往需要管理多个WebSocket连接,比如实现群发消息、向指定用户推送消息等功能。我们可以维护一个连接池,用互斥锁保证并发安全。
package main
import (
"log"
"net/http"
"sync"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool {
return true
},
}
// 连接管理结构体
type ConnectionManager struct {
connections map[*websocket.Conn]bool
mu sync.RWMutex
}
// 初始化连接管理器
func NewConnectionManager() *ConnectionManager {
return &ConnectionManager{
connections: make(map[*websocket.Conn]bool),
}
}
// 添加连接
func (cm *ConnectionManager) Add(conn *websocket.Conn) {
cm.mu.Lock()
defer cm.mu.Unlock()
cm.connections[conn] = true
}
// 移除连接
func (cm *ConnectionManager) Remove(conn *websocket.Conn) {
cm.mu.Lock()
defer cm.mu.Unlock()
delete(cm.connections, conn)
}
// 向所有连接广播消息
func (cm *ConnectionManager) Broadcast(message []byte) {
cm.mu.RLock()
defer cm.mu.RUnlock()
for conn := range cm.connections {
err := conn.WriteMessage(websocket.TextMessage, message)
if err != nil {
log.Printf("广播消息失败: %v", err)
}
}
}
// 全局连接管理器实例
var connManager = NewConnectionManager()
func handleWebSocket(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Printf("升级连接失败: %v", err)
return
}
defer conn.Close()
// 将新连接加入管理器
connManager.Add(conn)
defer connManager.Remove(conn)
for {
messageType, message, err := conn.ReadMessage()
if err != nil {
log.Printf("读取消息失败: %v", err)
break
}
log.Printf("收到消息: %s", message)
// 广播收到的消息给所有连接
connManager.Broadcast(message)
}
}
func main() {
http.HandleFunc("/ws", handleWebSocket)
log.Println("服务启动,监听端口8080")
err := http.ListenAndServe(":8080", nil)
if err != nil {
log.Fatalf("启动服务失败: %v", err)
}
}
注意事项
- 生产环境中一定要自定义
CheckOrigin函数的逻辑,避免非法来源的连接请求。 - 读取和发送消息时要做好错误处理,比如客户端异常断开连接时需要及时清理连接资源。
- 并发场景下操作连接池、发送消息时要使用互斥锁保证线程安全,避免出现数据竞争问题。
- 可以根据业务需求设置连接的读取超时和写入超时,避免连接长时间占用资源。
GolangWebSocketgorilla_websocket实时通信并发处理修改时间:2026-06-13 07:06:18