在使用Golang的gorilla/websocket庫構(gòu)建WebSocket應(yīng)用時,可能會遇到一些挑戰(zhàn)。本文將分析一個常見問題:使用chrome瀏覽器打開多個標(biāo)簽頁連接同一個WebSocket地址(例如localhost或IP地址),只有一個標(biāo)簽頁能正常工作,其他標(biāo)簽頁刷新后才能恢復(fù)連接。
問題根源在于WebSocket連接的管理方式。一些開發(fā)者錯誤地使用全局變量來存儲websocket.Conn對象:
var ws *websocket.Conn
每次有新的連接時,都會更新ws的值,覆蓋之前的連接。這意味著服務(wù)器端只能維持一個活躍連接。當(dāng)多個標(biāo)簽頁連接時,后連接的標(biāo)簽頁會斷開之前的連接。
立即學(xué)習(xí)“go語言免費(fèi)學(xué)習(xí)筆記(深入)”;
解決方案:為每個連接創(chuàng)建獨(dú)立的websocket.Conn對象
為了解決這個問題,必須為每個WebSocket連接創(chuàng)建獨(dú)立的websocket.Conn對象,避免使用全局變量。正確的做法是在處理函數(shù)內(nèi)部,針對每個連接創(chuàng)建新的websocket.Conn對象,并綁定到該連接。 一個參考自gitHub聊天案例的改進(jìn)代碼如下:
func Ws(c *gin.Context) { ws, err := upgrader.Upgrade(c.Writer, c.Request, nil) if err != nil { return } defer ws.Close() // 關(guān)閉連接非常重要 go func(conn *websocket.Conn) { // 處理每個連接的讀寫操作 for { mt, message, err := conn.ReadMessage() if err != nil { log.Println("read:", err) // 添加錯誤日志 break } log.Printf("Received: %s", message) // 添加日志方便調(diào)試 err = conn.WriteMessage(mt, message) if err != nil { log.Println("write:", err) // 添加錯誤日志 break } } }(ws) }
通過goroutine為每個連接創(chuàng)建一個獨(dú)立的處理函數(shù),并使用函數(shù)內(nèi)部的conn變量,避免了全局變量帶來的沖突,確保每個WebSocket連接獨(dú)立運(yùn)行,互不干擾。 這才是正確處理多個并發(fā)WebSocket連接的最佳實(shí)踐。 此外,添加了錯誤日志和接收消息日志,方便調(diào)試和排錯。
通過以上改進(jìn),可以有效解決多個瀏覽器標(biāo)簽頁連接同一個WebSocket地址時,只有一個標(biāo)簽頁能正常工作的問題。 記住,妥善管理連接,避免使用全局變量是關(guān)鍵。