亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

關閉在服務器端發送但客戶端仍然連接

關閉在服務器端發送但客戶端仍然連接

Go
繁星coding 2023-05-08 18:13:21
我有一個通過 API 和 websocket 進行通信的應用程序。websocket 用于將更新的用戶數據發布到客戶端,如果它在數據庫中發生更改 - 這非常有效,除了在某些情況下 websocket 不接收任何數據的情況。幾秒鐘后,websocket 再次開始工作。服務器日志(首先,websocket 不工作并重新開始工作)msg="無法將數據寫入 Websocket: websocket: close sent"msg="正在向客戶端發送 Ping 消息"msg="無法將 ping 消息寫入 Websocket:websocket:關閉發送"msg="正在向客戶端發送 Ping 消息"msg="正在向客戶端發送 Ping 消息"msg="正在向客戶端發送 Ping 消息"msg="正在向客戶端發送 Ping 消息"客戶端代碼:<html><body><p id="data"></p></body><script>var ws = new WebSocket("wss://example.com/ws");function unloadPage() {    toggleLoader();    ws.onclose = function () {};    ws.close();}ws.onopen = function () {    ws.send('Ping');};ws.onerror = function (error) {    console.log('WebSocket Error ' + error);    var d = document.getElementById("data");    d.innerHTML += "<tr><td>Failed to connect to Server.</td></tr>"};ws.onmessage = function (e) {    console.log(e);    var data = e.data;    var d = document.getElementById("data");    var parsedjson = JSON.parse(data);    d.innerHTML = "";    for (var i = 0; i < parsedjson.length; i++) {        d.innerHTML += parsedjson;    }};ws.onclose = function () {    console.log("Websocket has been closed");};window.addEventListener("beforeunload", unloadPage);</script></html>基本上,我們將當前數據發布到新的 Websocket 連接,當它更新時——這總是有效的。之后,如果數據庫發生變化,它會將更新后的用戶列表發布到頻道中——然后 websocket 應將其發布到更新列表的客戶端。我們還發送 ping 消息 - 失?。ㄈ缟厦娴娜罩舅荆?。客戶端本身不會記錄任何錯誤或關閉 websocket。
查看完整描述

1 回答

?
尚方寶劍之說

TA貢獻1788條經驗 獲得超4個贊

該websocket: close sent錯誤表明服務器向客戶端發送了關閉消息。因為應用程序服務器代碼不發送消息,所以連接必須發送消息以響應來自客戶端的關閉消息。


關閉消息作為錯誤從 websocket 讀取方法返回。因為沒有記錄任何消息,所以客戶端一定發送了“離開”關閉消息(唯一沒有記錄的錯誤)。


當websocket連接返回錯誤時,讀寫goroutine關閉連接返回。連接未保持打開狀態。


讀取和寫入 goroutine 不會檢測到另一個已關閉連接,直到從連接上的方法調用返回錯誤。讀取 goroutine 會快速檢測到關閉的連接,因為它始終在讀取,但寫入 goroutine 可能會有延遲。這可能是應用程序的問題


要讓寫入 goroutine 快速退出,請使用通道向寫入 goroutine 發出信號。有可能dataChan可用于此目的,但我不確定,因為該問題不包含有關如何管理頻道的信息。假設通道可以使用,讀取 goroutine 應該關閉dataChan。writer 應該檢測到關閉的通道并退出 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不能使用,為此引入一個新的通道。在處理程序中創建通道并將通道傳遞給讀寫 goroutines:


?done := make(chan struct{})

?go allUserWebsocketWriter(ws, stop, datachan)

?go PingResponse(ws, stop)

從讀取 goroutine 返回時關閉通道:


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)

? ? ? ? ...

這導致寫 goroutine 在讀 goroutine 退出后快速退出。


這兩種方法都降低了在連接上寫入返回錯誤的可能性websocket: close sent,但它們并沒有消除這種可能性。該錯誤是預期的,因為讀取 goroutine 可以在寫入 goroutine 寫入消息之前關閉連接。


無論如何,證據是客戶端正在關閉連接。未關閉的連接不是問題所在。


查看完整回答
反對 回復 2023-05-08
  • 1 回答
  • 0 關注
  • 346 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號