<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          WebSocket 從入門到入土

          共 15635字,需瀏覽 32分鐘

           ·

          2024-04-10 21:05


          作者:耀耀切克鬧灬

          https://juejin.cn/post/7309687967063818292

          前言

          因新部門需求有一個后臺管理需要一個右上角的實時的消息提醒功能,第一時間想到的就是使用WebSocket建立實時通信了,之前沒整過,于是只能學習了。和原部門相比現(xiàn)在太忙了,快樂的日子一去不復返了。經典的加量不加薪啊!!!

          一.WebSocket 基本概念

          1.WebSocket是什么?

          WebSocket 是基于 TCP 的一種新的應用層網絡協(xié)議。它提供了一個全雙工的通道,允許服務器和客戶端之間實時雙向通信。因此,在 WebSocket 中,瀏覽器和服務器只需要完成一次握手,兩者之間就直接可以創(chuàng)建持久性的連接,并進行雙向數(shù)據傳輸,客戶端和服務器之間的數(shù)據交換變得更加簡單。WebSocket

          2.與 HTTP 協(xié)議的區(qū)別

          與 HTTP 協(xié)議相比,WebSocket 具有以下優(yōu)點:

          1. 更高的實時性能:WebSocket 允許服務器和客戶端之間實時雙向通信,從而提高了實時通信場景中的性能。
          2. 更少的網絡開銷:HTTP 請求和響應之間需要額外的數(shù)據傳輸,而 WebSocket 通過在同一個連接上雙向通信,減少了網絡開銷。
          3. 更靈活的通信方式:HTTP 請求和響應通常是一一對應的,而 WebSocket 允許服務器和客戶端之間以多種方式進行通信,例如消息 Push、事件推送等。
          4. 更簡潔的 API:WebSocket 提供了簡潔的 API,使得客戶端開發(fā)人員可以更輕松地進行實時通信。

          當然肯定有缺點的:

          1. 不支持無連接: WebSocket 是一種持久化的協(xié)議,這意味著連接不會在一次請求之后立即斷開。這是有利的,因為它消除了建立連接的開銷,但是也可能導致一些資源泄漏的問題。
          2. 不支持廣泛: WebSocket 是 HTML5 中的一種標準協(xié)議,雖然現(xiàn)代瀏覽器都支持,但是一些舊的瀏覽器可能不支持 WebSocket。
          3. 需要特殊的服務器支持: WebSocket 需要服務端支持,只有特定的服務器才能夠實現(xiàn) WebSocket 協(xié)議。這可能會增加系統(tǒng)的復雜性和部署的難度。
          4. 數(shù)據流不兼容: WebSocket 的數(shù)據流格式與 HTTP 不同,這意味著在不同的網絡環(huán)境下,WebSocket 的表現(xiàn)可能會有所不同。

          3.WebSocket工作原理

          1.  握手階段

          WebSocket在建立連接時需要進行握手階段。握手階段包括以下幾個步驟:

          • 客戶端向服務端發(fā)送請求,請求建立WebSocket連接。請求中包含一個Sec-WebSocket-Key參數(shù),用于生成WebSocket的隨機密鑰。
          • 服務端接收到請求后,生成一個隨機密鑰,并使用隨機密鑰生成一個新的Sec-WebSocket-Accept參數(shù)。
          • 客戶端接收到服務端發(fā)送的新的Sec-WebSocket-Accept參數(shù)后,使用原來的隨機密鑰和新的Sec-WebSocket-Accept參數(shù)共同生成一個新的Sec-WebSocket-Key參數(shù),用于加密數(shù)據傳輸。
          • 客戶端將新的Sec-WebSocket-Key參數(shù)發(fā)送給服務端,服務端接收到后,使用該參數(shù)加密數(shù)據傳輸。

          2.  數(shù)據傳輸階段

          建立連接后,客戶端和服務端就可以通過WebSocket進行實時雙向通信。數(shù)據傳輸階段包括以下幾個步驟:

          • 客戶端向服務端發(fā)送數(shù)據,服務端收到數(shù)據后將其轉發(fā)給其他客戶端。
          • 服務端向客戶端發(fā)送數(shù)據,客戶端收到數(shù)據后進行處理。

          雙方如何進行相互傳輸數(shù)據的 具體的數(shù)據格式是怎么樣的呢?WebSocket 的每條消息可能會被切分成多個數(shù)據幀(最小單位)。發(fā)送端會將消息切割成多個幀發(fā)送給接收端,接收端接收消息幀,并將關聯(lián)的幀重新組裝成完整的消息。

          發(fā)送方 -> 接收方:ping。

          接收方 -> 發(fā)送方:pong。

          ping 、pong 的操作,對應的是 WebSocket 的兩個控制幀

          3.  關閉階段

          當不再需要WebSocket連接時,需要進行關閉階段。關閉階段包括以下幾個步驟:

          • 客戶端向服務端發(fā)送關閉請求,請求中包含一個WebSocket的隨機密鑰。
          • 服務端接收到關閉請求后,向客戶端發(fā)送關閉響應,關閉響應中包含服務端生成的隨機密鑰。
          • 客戶端收到關閉響應后,關閉WebSocket連接。

          總的來說,WebSocket通過握手階段、數(shù)據傳輸階段和關閉階段實現(xiàn)了服務器和客戶端之間的實時雙向通信。

          二.WebSocket 數(shù)據幀結構和控制幀結構。

          1.  數(shù)據幀結構

          WebSocket 數(shù)據幀主要包括兩個部分:幀頭和有效載荷。以下是 WebSocket 數(shù)據幀結構的簡要介紹:

          • 幀頭:幀頭包括四個部分:fin、rsv1、rsv2、rsv3、opcode、masked 和 payload_length。其中,fin 表示數(shù)據幀的結束標志,rsv1、rsv2、rsv3 表示保留字段,opcode 表示數(shù)據幀的類型,masked 表示是否進行掩碼處理,payload_length 表示有效載荷的長度。
          • 有效載荷:有效載荷是數(shù)據幀中實際的數(shù)據部分,它由客戶端和服務端進行數(shù)據傳輸。

          2.  控制幀結構

          除了數(shù)據幀之外,WebSocket 協(xié)議還包括一些控制幀,主要包括 Ping、Pong 和 Close 幀。以下是 WebSocket 控制幀結構的簡要介紹:

          • Ping 幀:Ping 幀用于測試客戶端和服務端之間的連接狀態(tài),客戶端向服務端發(fā)送 Ping 幀,服務端收到后需要向客戶端發(fā)送 Pong 幀進行響應。
          • Pong 幀:Pong 幀用于響應客戶端的 Ping 幀,它用于測試客戶端和服務端之間的連接狀態(tài)。
          • Close 幀:Close 幀用于關閉客戶端和服務端之間的連接,它包括四個部分:fin、rsv1、rsv2、rsv3、opcode、masked 和 payload_length。其中,opcode 的值為 8,表示 Close 幀。

          三. JavaScript 中 WebSocket 對象的屬性和方法,以及如何創(chuàng)建和連接 WebSocket。

          WebSocket 對象的屬性和方法:

          1. WebSocket 對象:WebSocket 對象表示一個新的 WebSocket 連接。
          2. WebSocket.onopen 事件處理程序:當 WebSocket 連接打開時觸發(fā)。
          3. WebSocket.onmessage 事件處理程序:當接收到來自 WebSocket 的消息時觸發(fā)。
          4. WebSocket.onerror 事件處理程序:當 WebSocket 發(fā)生錯誤時觸發(fā)。
          5. WebSocket.onclose 事件處理程序:當 WebSocket 連接關閉時觸發(fā)。
          6. WebSocket.send 方法:向 WebSocket 發(fā)送數(shù)據。
          7. WebSocket.close 方法:關閉 WebSocket 連接。

          創(chuàng)建和連接 WebSocket:

          1. 創(chuàng)建 WebSocket 對象:
                        
                        var socket = new WebSocket('ws://example.com');

          其中,ws://example.com 是 WebSocket 的 URL,表示要連接的服務器。

          1. 連接 WebSocket:

          使用 WebSocket.onopen 事件處理程序檢查 WebSocket 是否成功連接。

                        
                        socket.onopen = function() {
              console.log('WebSocket connected');
          };
          1. 接收來自 WebSocket 的消息:

          使用 WebSocket.onmessage 事件處理程序接收來自 WebSocket 的消息。

                        
                        socket.onmessage = function(event{
              console.log('WebSocket message:', event.data);
          };
          1. 向 WebSocket 發(fā)送消息:

          使用 WebSocket.send 方法向 WebSocket 發(fā)送消息。

                        
                        socket.send('Hello, WebSocket!');
          1. 關閉 WebSocket:

          當需要關閉 WebSocket 時,使用 WebSocket.close 方法。

                        
                        socket.close();

          注意:在 WebSocket 連接成功打開和關閉時,會分別觸發(fā) WebSocket.onopen 和 WebSocket.onclose 事件。在接收到來自 WebSocket 的消息時,會觸發(fā) WebSocket.onmessage 事件。當 WebSocket 發(fā)生錯誤時,會觸發(fā) WebSocket.onerror 事件。

          四.webSocket簡單示例

          以下是一個簡單的 WebSocket 編程示例,通過 WebSocket 向服務器發(fā)送數(shù)據,并接收服務器返回的數(shù)據:

          1. 首先,創(chuàng)建一個 HTML 文件,添加一個按鈕和一個用于顯示消息的文本框:
                        
                        <!DOCTYPE html>
          <html>
          <head>
             <meta charset="UTF-8">
             <title>WebSocket 示例</title>
          </head>
          <body>
             <button id="sendBtn">發(fā)送消息</button>
             <textarea id="messageBox" readonly></textarea>
             <script src="main.js"></script>
          </body>
          </html>
          2. 接下來,創(chuàng)建一個 JavaScript 文件(例如 main.js),并在其中編寫以下代碼:
                        
                        // 獲取按鈕和文本框元素
          const sendBtn = document.getElementById('sendBtn');
          const messageBox = document.getElementById('messageBox');

          // 創(chuàng)建 WebSocket 對象
          const socket = new WebSocket('ws://echo.websocket.org'); // 使用一個 WebSocket 服務器進行測試

          // 設置 WebSocket 連接打開時的回調函數(shù)
          socket.onopen = function() {
             console.log('WebSocket 連接已打開');
          };

          // 設置 WebSocket 接收到消息時的回調函數(shù)
          socket.onmessage = function(event{
             console.log('WebSocket 接收到消息:', event.data);
             messageBox.value += event.data + '\n';
          };

          // 設置 WebSocket 發(fā)生錯誤時的回調函數(shù)
          socket.onerror = function() {
             console.log('WebSocket 發(fā)生錯誤');
          };

          // 設置 WebSocket 連接關閉時的回調函數(shù)
          socket.onclose = function() {
             console.log('WebSocket 連接已關閉');
          };

          // 點擊按鈕時發(fā)送消息
          sendBtn.onclick = function() {
             const message = 'Hello, WebSocket!';
             socket.send(message);
             messageBox.value += '發(fā)送消息: ' + message + '\n';
          };

          五.webSocket應用場景

          1. 實時通信:WebSocket 非常適合實時通信場景,例如聊天室、在線游戲、實時數(shù)據傳輸?shù)取Mㄟ^ WebSocket,客戶端和服務器之間可以實時通信,無需依賴輪詢,從而提高通信效率和減少網絡延遲。
          2. 監(jiān)控數(shù)據傳輸:WebSocket 可以在監(jiān)控系統(tǒng)中實現(xiàn)實時數(shù)據傳輸,例如通過 WebSocket,客戶端可以實時接收和處理監(jiān)控數(shù)據,而無需等待輪詢數(shù)據。
          3. 自動化控制:WebSocket 可以在自動化系統(tǒng)中實現(xiàn)遠程控制,例如通過 WebSocket,客戶端可以遠程控制設備或系統(tǒng),而無需直接操作。
          4. 數(shù)據分析:WebSocket 可以在數(shù)據分析場景中實現(xiàn)實時數(shù)據傳輸和處理,例如通過 WebSocket,客戶端可以實時接收和處理數(shù)據,而無需等待數(shù)據存儲和分析。
          5. 人工智能:WebSocket 可以在人工智能場景中實現(xiàn)實時數(shù)據傳輸和處理,例如通過 WebSocket,客戶端可以實時接收和處理數(shù)據,而無需等待數(shù)據處理和分析。

          六.WebSocket 錯誤處理

          WebSocket 的錯誤處理

          1. WebSocket is not supported:當瀏覽器不支持 WebSocket 時,會出現(xiàn)此錯誤。解決方法是在瀏覽器兼容性列表中檢查是否支持 WebSocket。
          2. WebSocket connection closed:當 WebSocket 連接被關閉時,會出現(xiàn)此錯誤。解決方法是在 WebSocket.onclose 事件處理程序中進行錯誤處理。
          3. WebSocket error:當 WebSocket 發(fā)生錯誤時,會出現(xiàn)此錯誤。解決方法是在 WebSocket.onerror 事件處理程序中進行錯誤處理。
          4. WebSocket timeout:當 WebSocket 連接超時時,會出現(xiàn)此錯誤。解決方法是在 WebSocket.ontimeout 事件處理程序中進行錯誤處理。
          5. WebSocket handshake error:當 WebSocket 握手失敗時,會出現(xiàn)此錯誤。解決方法是在 WebSocket.onerror 事件處理程序中進行錯誤處理。
          6. WebSocket closed by server:當 WebSocket 連接被服務器關閉時,會出現(xiàn)此錯誤。解決方法是在 WebSocket.onclose 事件處理程序中進行錯誤處理。
          7. WebSocket closed by protocol:當 WebSocket 連接被協(xié)議錯誤關閉時,會出現(xiàn)此錯誤。解決方法是在 WebSocket.onclose 事件處理程序中進行錯誤處理。
          8. WebSocket closed by network:當 WebSocket 連接被網絡錯誤關閉時,會出現(xiàn)此錯誤。解決方法是在 WebSocket.onclose 事件處理程序中進行錯誤處理。
          9. WebSocket closed by server:當 WebSocket 連接被服務器錯誤關閉時,會出現(xiàn)此錯誤。解決方法是在 WebSocket.onclose 事件處理程序中進行錯誤處理。

          通過為 WebSocket 對象的 oncloseonerror 和 ontimeout 事件添加處理程序,可以及時捕獲和處理 WebSocket 錯誤,從而確保程序的穩(wěn)定性和可靠性。

          七.利用單例模式創(chuàng)建完整的wesocket連接

                        
                        class webSocketClass {
              constructor(thatVue) {
                this.lockReconnect = false;
                this.localUrl = process.env.NODE_ENV === 'production' ? 你的websocket生產地址' : '測試地址';
                this.globalCallback = null;
                this.userClose = false;
                this.createWebSocket();
                this.webSocketState = false
                this.thatVue = thatVue
              }
            
              createWebSocket() {
                let that = this;
                // console.log('
          開始創(chuàng)建websocket新的實例', new Date().toLocaleString())
                if( typeof(WebSocket) != "function" ) {
                  alert("您的瀏覽器不支持Websocket通信協(xié)議,請更換瀏覽器為Chrome或者Firefox再次使用!")
                }
                try {
                  that.ws = new WebSocket(that.localUrl);
                  that.initEventHandle();
                  that.startHeartBeat()
                } catch (e) {
                  that.reconnect();
                }
              }

              //初始化
              initEventHandle() {
                let that = this;
                // //連接成功建立后響應
                that.ws.onopen = function() {
                  console.log("連接成功");
                }; 
                //連接關閉后響應
                that.ws.onclose = function() {
                  // console.log('
          websocket連接斷開', new Date().toLocaleString())
                  if (!that.userClose) {
                    that.reconnect(); //重連
                  }
                };
                that.ws.onerror = function() {
                  // console.log('
          websocket連接發(fā)生錯誤', new Date().toLocaleString())
                  if (!that.userClose) {
                    that.reconnect(); //重連
                  }
                };
                that.ws.onmessage = function(event) {
                  that.getWebSocketMsg(that.globalCallback);
                  // console.log('
          socket server return '+ event.data);
                };
              }
              startHeartBeat () {
                // console.log('
          心跳開始建立', new Date().toLocaleString())
                setTimeout(() => {
                    let params = {
                      request: '
          ping',
                    }
                    this.webSocketSendMsg(JSON.stringify(params))
                    this.waitingServer()
                }, 30000)
              }
              //延時等待服務端響應,通過webSocketState判斷是否連線成功
              waitingServer () {
                this.webSocketState = false//在線狀態(tài)
                setTimeout(() => {
                    if(this.webSocketState) {
                        this.startHeartBeat()
                        return
                    }
                    // console.log('
          心跳無響應,已斷線', new Date().toLocaleString())
                    try {
                      this.closeSocket()
                    } catch(e) {
                      console.log('
          連接已關閉,無需關閉', new Date().toLocaleString())
                    }
                    this.reconnect()
                    //重連操作
                }, 5000)
              }
              reconnect() {
                let that = this;
                if (that.lockReconnect) return;
                that.lockReconnect = true; //沒連接上會一直重連,設置延遲避免請求過多
                setTimeout(function() {
                  that.createWebSocket();
                  that.thatVue.openSuccess(that) //重連之后做一些事情
                  that.thatVue.getSocketMsg(that)
                  that.lockReconnect = false;
                }, 15000);
              }
            
              webSocketSendMsg(msg) {
                this.ws.send(msg);
              }
            
              getWebSocketMsg(callback) {
                this.ws.onmessage = ev => {
                  callback && callback(ev);
                };
              }
              onopenSuccess(callback) {
                this.ws.onopen = () => {
                  // console.log("連接成功", new Date().toLocaleString())
                  callback && callback()
                }
              }
              closeSocket() {
                let that = this;
                if (that.ws) {
                  that.userClose = true;
                  that.ws.close();
                }
              }
            }
            export default webSocketClass;
          推薦閱讀  點擊標題可跳轉

          1、Websocket 被玩出了多種花樣!

          2、看尤雨溪說:為什么Vue3 中應該使用 Ref 而不是 Reactive?

          3、堪稱 React 版本的 Pinia,這才是你該選的 React 狀態(tài)管理庫!

          瀏覽 41
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  黄片操逼视频 | 成人在线看网站 | 插穴无码 | 国产高清视频在线播放 | 免费麻豆国产一区二区三区四区 |