用gorilla websocket 搞一個聊天室

這個demo實現了:git

  1. 消息廣播
  2. 心跳檢測

經過命令行來進行聊天github

具體邏輯都在 websocket.go 這個文件裏web

這裏的核心就是 aliveList 這個全局變量, 負責把消息分發給各客戶端, 事件用channel來傳遞, 減小阻塞json

單個連接會在 aliveList 中註冊, ConnList 就是全部活躍的連接websocket

// AliveList 當前在線列表
type AliveList struct {
    ConnList  map[string]*Client
    register  chan *Client
    destroy   chan *Client
    broadcast chan Message
    cancel    chan int
    Len       int
}

// Client socket客戶端
type Client struct {
    ID     string
    conn   *websocket.Conn
    cancel chan int
}

服務啓動後會執行事件監聽循環socket

// 啓動監聽
func (al *AliveList) run() {
    log.Println("開始監聽註冊事件")
    for {
        select {
        case client := <-al.register:
            log.Println("註冊事件:", client.ID)
            al.ConnList[client.ID] = client
            al.Len++
            al.SysBroadcast(ConnectedMessage, Message{
                ID:      client.ID,
                Content: "connected",
                SentAt:  time.Now().Unix(),
            })

        case client := <-al.destroy:
            log.Println("銷燬事件:", client.ID)
            err := client.conn.Close()
            if err != nil {
                log.Printf("destroy Error: %v \n", err)
            }
            delete(al.ConnList, client.ID)
            al.Len--

        case message := <-al.broadcast:
            log.Printf("廣播事件: %s %s %d \n", message.ID, message.Content, message.Type)
            for id := range al.ConnList {
                if id != message.ID {

                    err := al.sendMessage(id, message)
                    if err != nil {
                        log.Println("broadcastError: ", err)
                    }
                }
            }

        case sign := <-al.cancel:
            log.Println("終止事件: ", sign)
            os.Exit(0)
        }
    }
}

由於消息的類型比較多, 單純字符串沒法知足需求, 就選用了比較經常使用的json格式去傳遞, 消息目前分:優化

const (
    // SystemMessage 系統消息
    SystemMessage = iota
    // BroadcastMessage 廣播消息(正常的消息)
    BroadcastMessage
    // HeartBeatMessage 心跳消息
    HeartBeatMessage
    // ConnectedMessage 上線通知
    ConnectedMessage
    // DisconnectedMessage 下線通知
    DisconnectedMessage
)



// Message 消息體結構
type Message struct {
    ID      string
    Content string
    SentAt  int64
    Type    int     // <- SystemMessage 等類型就是這裏了
}

若是有空閒時間就再搞搞多聊天室的實現, 以及優化一下目前的事件循環邏輯
若是還有更多的餘力, 就搞一個好看點的客戶端?命令行

demo地址
個人博客code

相關文章
相關標籤/搜索