WebSocket #

一、WebSocket概述 #

1.1 什么是WebSocket #

WebSocket是一种在单个TCP连接上进行全双工通信的协议,适合实时应用。

1.2 应用场景 #

  • 实时聊天
  • 在线游戏
  • 实时数据推送
  • 协作编辑

二、基本使用 #

2.1 安装依赖 #

bash
go get github.com/gofiber/fiber/v2
go get github.com/gofiber/contrib/websocket

2.2 基本WebSocket #

go
package main

import (
    "log"
    
    "github.com/gofiber/fiber/v2"
    "github.com/gofiber/contrib/websocket"
)

func main() {
    app := fiber.New()
    
    app.Get("/ws", websocket.New(func(c *websocket.Conn) {
        var msg string
        
        for {
            // 读取消息
            mt, message, err := c.ReadMessage()
            if err != nil {
                break
            }
            
            log.Printf("Received: %s", message)
            
            // 发送消息
            err = c.WriteMessage(mt, message)
            if err != nil {
                break
            }
        }
    }))
    
    app.Listen(":3000")
}

三、连接管理 #

3.1 连接池 #

go
type Client struct {
    ID   string
    Conn *websocket.Conn
}

type Hub struct {
    Clients    map[string]*Client
    Register   chan *Client
    Unregister chan *Client
    Broadcast  chan []byte
}

func NewHub() *Hub {
    return &Hub{
        Clients:    make(map[string]*Client),
        Register:   make(chan *Client),
        Unregister: make(chan *Client),
        Broadcast:  make(chan []byte),
    }
}

func (h *Hub) Run() {
    for {
        select {
        case client := <-h.Register:
            h.Clients[client.ID] = client
            
        case client := <-h.Unregister:
            if _, ok := h.Clients[client.ID]; ok {
                delete(h.Clients, client.ID)
                client.Conn.Close()
            }
            
        case message := <-h.Broadcast:
            for _, client := range h.Clients {
                client.Conn.WriteMessage(websocket.TextMessage, message)
            }
        }
    }
}

3.2 使用Hub #

go
var hub = NewHub()

func main() {
    go hub.Run()
    
    app := fiber.New()
    
    app.Get("/ws/:id", websocket.New(func(c *websocket.Conn) {
        id := c.Params("id")
        
        client := &Client{
            ID:   id,
            Conn: c,
        }
        
        hub.Register <- client
        
        defer func() {
            hub.Unregister <- client
        }()
        
        for {
            mt, message, err := c.ReadMessage()
            if err != nil {
                break
            }
            
            hub.Broadcast <- message
        }
    }))
    
    app.Listen(":3000")
}

四、消息处理 #

4.1 JSON消息 #

go
type Message struct {
    Type    string      `json:"type"`
    Content interface{} `json:"content"`
}

app.Get("/ws", websocket.New(func(c *websocket.Conn) {
    for {
        mt, message, err := c.ReadMessage()
        if err != nil {
            break
        }
        
        var msg Message
        json.Unmarshal(message, &msg)
        
        switch msg.Type {
        case "chat":
            // 处理聊天消息
            hub.Broadcast <- message
            
        case "ping":
            // 心跳响应
            c.WriteMessage(mt, []byte(`{"type":"pong"}`))
        }
    }
}))

4.2 广播消息 #

go
func BroadcastMessage(hub *Hub, message []byte) {
    hub.Broadcast <- message
}

func BroadcastJSON(hub *Hub, msg interface{}) {
    data, _ := json.Marshal(msg)
    hub.Broadcast <- data
}

五、聊天室示例 #

go
package main

import (
    "encoding/json"
    "log"
    
    "github.com/gofiber/fiber/v2"
    "github.com/gofiber/contrib/websocket"
)

type Client struct {
    ID   string
    Name string
    Conn *websocket.Conn
    Hub  *Hub
}

type Hub struct {
    Clients    map[string]*Client
    Register   chan *Client
    Unregister chan *Client
    Broadcast  chan []byte
}

type Message struct {
    Type    string `json:"type"`
    Sender  string `json:"sender"`
    Content string `json:"content"`
}

func NewHub() *Hub {
    return &Hub{
        Clients:    make(map[string]*Client),
        Register:   make(chan *Client),
        Unregister: make(chan *Client),
        Broadcast:  make(chan []byte),
    }
}

func (h *Hub) Run() {
    for {
        select {
        case client := <-h.Register:
            h.Clients[client.ID] = client
            h.Broadcast <- []byte(`{"type":"join","sender":"` + client.Name + `"}`)
            
        case client := <-h.Unregister:
            if _, ok := h.Clients[client.ID]; ok {
                delete(h.Clients, client.ID)
                client.Conn.Close()
                h.Broadcast <- []byte(`{"type":"leave","sender":"` + client.Name + `"}`)
            }
            
        case message := <-h.Broadcast:
            for _, client := range h.Clients {
                client.Conn.WriteMessage(websocket.TextMessage, message)
            }
        }
    }
}

var hub = NewHub()

func main() {
    go hub.Run()
    
    app := fiber.New()
    
    app.Get("/ws/:id/:name", websocket.New(func(c *websocket.Conn) {
        id := c.Params("id")
        name := c.Params("name")
        
        client := &Client{
            ID:   id,
            Name: name,
            Conn: c,
            Hub:  hub,
        }
        
        hub.Register <- client
        
        defer func() {
            hub.Unregister <- client
        }()
        
        for {
            _, message, err := c.ReadMessage()
            if err != nil {
                break
            }
            
            var msg Message
            json.Unmarshal(message, &msg)
            msg.Sender = name
            
            data, _ := json.Marshal(msg)
            hub.Broadcast <- data
        }
    }))
    
    log.Fatal(app.Listen(":3000"))
}

六、总结 #

6.1 WebSocket要点 #

要点 说明
连接管理 维护客户端连接
消息处理 解析和处理消息
广播 向所有客户端发送消息
错误处理 处理断开连接

6.2 下一步 #

现在你已经掌握了WebSocket,接下来让我们学习 限流控制,了解如何保护API!

最后更新:2026-03-28