1 回答

TA貢獻(xiàn)1788條經(jīng)驗(yàn) 獲得超4個(gè)贊
該websocket: close sent錯(cuò)誤表明服務(wù)器向客戶端發(fā)送了關(guān)閉消息。因?yàn)閼?yīng)用程序服務(wù)器代碼不發(fā)送消息,所以連接必須發(fā)送消息以響應(yīng)來自客戶端的關(guān)閉消息。
關(guān)閉消息作為錯(cuò)誤從 websocket 讀取方法返回。因?yàn)闆]有記錄任何消息,所以客戶端一定發(fā)送了“離開”關(guān)閉消息(唯一沒有記錄的錯(cuò)誤)。
當(dāng)websocket連接返回錯(cuò)誤時(shí),讀寫goroutine關(guān)閉連接返回。連接未保持打開狀態(tài)。
讀取和寫入 goroutine 不會(huì)檢測(cè)到另一個(gè)已關(guān)閉連接,直到從連接上的方法調(diào)用返回錯(cuò)誤。讀取 goroutine 會(huì)快速檢測(cè)到關(guān)閉的連接,因?yàn)樗冀K在讀取,但寫入 goroutine 可能會(huì)有延遲。這可能是應(yīng)用程序的問題
要讓寫入 goroutine 快速退出,請(qǐng)使用通道向?qū)懭?goroutine 發(fā)出信號(hào)。有可能dataChan可用于此目的,但我不確定,因?yàn)樵搯栴}不包含有關(guān)如何管理頻道的信息。假設(shè)通道可以使用,讀取 goroutine 應(yīng)該關(guān)閉dataChan。writer 應(yīng)該檢測(cè)到關(guān)閉的通道并退出 goroutine:
...
for {
? ? select {
? ? case data, ok := <-datachan:
? ? ? ? if !ok {
? ? ? ? ? ?// Done writing, return
? ? ? ? ? ?return
? ? ? ? }
? ? ? ? ws.SetWriteDeadline(time.Now().Add(writeWait))
? ? ? ? err := ws.WriteJSON(&data)
? ? ? ? if err != nil {
? ? ? ? ? ? conf.Log.Debugf("Failed to write data to Websocket: %v", err)
? ? ? ? ? ? return
? ? ? ? }
? ? ? ? ...
這是Gorilla Chat Example使用的方法。
如果dataChan不能使用,為此引入一個(gè)新的通道。在處理程序中創(chuàng)建通道并將通道傳遞給讀寫 goroutines:
?done := make(chan struct{})
?go allUserWebsocketWriter(ws, stop, datachan)
?go PingResponse(ws, stop)
從讀取 goroutine 返回時(shí)關(guān)閉通道:
func PingResponse(ws *websocket.Conn, done chan struct{}) {
? ? defer close(done)
? ? conf := storage.GetConfig()
? ? ...
在寫gorountine的通道上選擇:
...
for {
? ? select {
? ? case <-done:
? ? ? ? return
? ? case data := <-datachan:
? ? ? ? ws.SetWriteDeadline(time.Now().Add(writeWait))
? ? ? ? err := ws.WriteJSON(&data)
? ? ? ? ...
這導(dǎo)致寫 goroutine 在讀 goroutine 退出后快速退出。
這兩種方法都降低了在連接上寫入返回錯(cuò)誤的可能性websocket: close sent,但它們并沒有消除這種可能性。該錯(cuò)誤是預(yù)期的,因?yàn)樽x取 goroutine 可以在寫入 goroutine 寫入消息之前關(guān)閉連接。
無論如何,證據(jù)是客戶端正在關(guān)閉連接。未關(guān)閉的連接不是問題所在。
- 1 回答
- 0 關(guān)注
- 332 瀏覽
添加回答
舉報(bào)