Go-WebSocket实时通信从聊天室到消息推送系统实战
文章导语
WebSocket是实现实时双向通信的利器。在Go中,goroutine-per-connection模型与WebSocket天然契合。本文基于gorilla/websocket库,实现从基础聊天室到生产级消息推送系统。
一、WebSocket基础服务
import "github.com/gorilla/websocket"
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool {
return true // 生产环境需要校验Origin
},
}
func handleWebSocket(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Print("升级失败:", err)
return
}
defer conn.Close()
for {
messageType, msg, err := conn.ReadMessage()
if err != nil {
break
}
// Echo回复
conn.WriteMessage(messageType, msg)
}
}
二、聊天室Hub模式
type Hub struct {
clients map[*Client]bool
broadcast chan []byte
register chan *Client
unregister chan *Client
mu sync.RWMutex
}
func (h *Hub) Run() {
for {
select {
case client := <-h.register:
h.mu.Lock()
h.clients[client] = true
h.mu.Unlock()
case client := <-h.unregister:
h.mu.Lock()
if _, ok := h.clients[client]; ok {
delete(h.clients, client)
close(client.send)
}
h.mu.Unlock()
case message := <-h.broadcast:
h.mu.RLock()
for client := range h.clients {
select {
case client.send <- message:
default:
close(client.send)
delete(h.clients, client)
}
}
h.mu.RUnlock()
}
}
}
三、心跳保活
func (c *Client) ReadPump(hub *Hub) {
defer func() {
hub.unregister <- c
c.conn.Close()
}()
c.conn.SetReadDeadline(time.Now().Add(pongWait))
c.conn.SetPongHandler(func(string) error {
c.conn.SetReadDeadline(time.Now().Add(pongWait))
return nil
})
for {
_, msg, err := c.conn.ReadMessage()
if err != nil {
break
}
hub.broadcast <- msg
}
}
func (c *Client) WritePump() {
ticker := time.NewTicker(pingPeriod)
defer func() {
ticker.Stop()
c.conn.Close()
}()
for {
select {
case msg, ok := <-c.send:
if !ok { return }
c.conn.WriteMessage(websocket.TextMessage, msg)
case <-ticker.C:
c.conn.WriteMessage(websocket.PingMessage, nil)
}
}
}
四、全文总结
- Hub模式管理所有连接,实现广播推送
- Ping/Pong心跳保持长连接活跃
- 读写分离通过两个goroutine实现全双工
- 连接数限制通过channel信号量控制
参考文献
- gorilla/websocket: https://github.com/gorilla/websocket
- WebSocket RFC 6455
- Go Blog - Advanced Go Concurrency Patterns

343

被折叠的 条评论
为什么被折叠?



