用gorilla websocket 搞一個聊天室

這個demo實現了:

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

通過命令行來進行聊天

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

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

單個鏈接會在 aliveList 中註冊, ConnList 就是所有活躍的鏈接

// 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
}

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

// 啓動監聽
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地址
我的博客

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章