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

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

如何優雅地重新連接websocket?

如何優雅地重新連接websocket?

Go
慕姐4208626 2023-08-07 10:33:08
我正在使用 HTTP 和 Websockets 構建一個單頁面應用程序。用戶提交表單,我將響應流式傳輸給客戶端。下面是一個片段客戶端。var html = `<!DOCTYPE html><meta charset="utf-8"><head></head><body><script>var ws = new WebSocket("ws://localhost:8000/ws")ws.onmessage = function(e) {  document.getElementById("output").innerHTML += e.data + "<br>"}function submitFunction() {  document.getElementById("output").innerHTML += ""  return false}</script><formenctype="multipart/x-www-form-urlencoded"action="http://localhost:8000/"method="post">`這是服務器。如果請求不是 POST,我會編寫/渲染 html (parseAndExecute),以建立新的 websocket 連接。如果請求是 POST(來自表單),那么我開始處理并最終寫入 websocket。func (c *Config) ServeHtml(w http.ResponseWriter, r *http.Request) {    if r.Method == http.MethodPost {        //process        channel <- data    }    c.parseAndExecute(w)}func (sh *SocketHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {    ws, err := upgrader.Upgrade(w, r, nil)    if err != nil {        w.Write([]byte(fmt.Sprintf("", err)))        return    }    //defer ws.Close()    // discard received messages    go func(c *websocket.Conn) {        for {            if _, _, err := c.NextReader(); err != nil {                c.Close()                break            }        }    }(ws)    data <- channel僅當我不刷新頁面時,一切都會按我的預期進行。如果我不刷新,我可以繼續提交表單并看到不同的輸出逐行出現。澄清一下,它實際上只有在頁面已經啟動時才有效,因此parseAndExecute永遠不會被調用。該函數解析并執行 html/template 創建一個新的 websocket 客戶端。任何頁面刷新或最初瀏覽 localhost:8000 都會websocket: close sent在服務器上引起。我不知道如何解決這個問題。服務器是否需要優雅地處理斷開連接并允許重新連接?或者客戶需要做些什么?似乎服務器應該升級任何連接,/ws因此創建多少個新的 websocket 客戶端并不重要,但顯然我的理解是錯誤的。我不會關閉服務器上的 websocket 連接,因為只要程序運行,它就應該保持連接狀態。當用戶停止該程序時,我認為它會自動關閉。
查看完整描述

1 回答

?
慕后森

TA貢獻1802條經驗 獲得超5個贊

Websocket 服務器應用程序必須通過關閉連接并釋放與該連接關聯的資源來處理連接上的錯誤。


當包含的頁面刷新時,瀏覽器會關閉 websocket 連接。瀏覽器關閉連接后,服務器最終會收到讀取或寫入錯誤。


連接關閉是服務器可能遇到的幾種錯誤之一。服務器應用程序應以相同的方式處理連接上的所有錯誤:關閉連接并釋放與該連接關聯的資源。


典型的應用程序設計是讓客戶端在頁面加載時進行連接,并在發生錯誤后重新連接(使用退避)。服務器假設客戶端會隨著時間的推移而連接和斷開連接。


可以通過添加一個通過退避重新連接的 onerror 處理程序來改進 JS 代碼。根據應用程序的不同,您可能還希望顯示指示連接狀態的 UI。


Go代碼并不會在所有場景下關閉連接。正在運行的命令是與連接關聯的資源。應用程序不會在連接錯誤時終止該程序。以下是一些修復:


defer ws.Close()升級成功后添加。ws.Close()刪除對from的其他直接調用SocketHandler.ServeHTTP。這確保了ws.Close()在所有場景中都被調用。


從讀寫泵退出時終止該命令。命令啟動后將讀取泵移至。回來就殺掉。


go func(c *websocket.Conn, cmd *exec.Command) {

? ? defer c.Close()

? ? defer cmd.Process.Kill()

? ? for {

? ? ? ? if _, _, err := c.NextReader(); err != nil {

? ? ? ? ? ? break

? ? ? ? }

? ? }

}(ws, cmd)

從寫泵退出時終止命令:


s := bufio.NewScanner(io.MultiReader(stdout, stderr))

for s.Scan() {

? ? err := ws.WriteMessage(1, s.Bytes())

? ? if err != nil {

? ? ? ? break

? ? }

}

cmd.Process.Kill()

我還沒有運行或測試過這段代碼。有些細節可能是錯誤的,但這概述了關閉連接和釋放資源的一般方法。


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

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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