WebSocket的理解與使用

  1. 什麼是WebSocket?php

    WebSocket是HTML5開始提供的一種在TCP鏈接上進行全雙工通信的協議,是一種服務器推送技術html

  2. WebSocket出現以前客戶端如何獲取服務端的實時數據?html5

    Comet:是一種服務器向頁面推送數據的技術。有如下實現方式:node

    (1) ajax輪詢:瀏覽器定時向服務器發送請求,詢問服務器是否有新信息。web

    (2) 長輪詢:客戶端發送請求後,服務器會保持鏈接,直到有新數據返回給客戶端或請求超時。客戶端收到數據並處理完,或者請求超時後,再向服務端發送新請求。ajax

    (3) HTTP流:瀏覽器向服務器發送一個請求,服務器保持鏈接打開,而後週期性地向瀏覽器發送數據。瀏覽器經過偵聽readystatechange事件及檢測readyState的值是否爲3,是則比較此前接收到的數據,決定從收到的數據中的什麼位置開始取得最新的數據。小程序

    (4) SSE:服務器發送事件,是圍繞只讀Comet交互推出的API。使用SSE API建立到服務器的單向鏈接,服務器能夠經過這個鏈接發送任意數量的數據。SSE支持ajax輪詢、長輪詢和HTTP流,能在斷開鏈接時自動肯定什麼時候從新鏈接。微信小程序

  3. 爲何須要WebSocket?瀏覽器

    (1) HTTP協議的侷限緩存

    • HTTP協議是一種單向的網絡協議,通訊只能由客戶端發起,服務器沒法主動向客戶端推送信息。
    • HTTP協議是無狀態的,客戶端向服務器發送請求時,每次都要重讀發送鑑別信息。

    (2) 輪詢、HTTP流、SSE方式存在侷限性:

    • ajax輪詢:服務器在某個時間段沒有數據更新時,會返回相同的數據,浪費帶寬,下降CPU的利用率
    • 長輪詢:服務端數據更新較快時,需等待客戶端發送請求才可返回數據,存在客戶端處理數據、請求創建鏈接和網絡延時等時差問題
    • HTTP流:管理鏈接比較容易出錯。
    • SSE:只適用於服務器到客戶端的單向推送,如比賽成績。

    WebSocket是一種與服務器進行全雙工、雙向通訊的信道,專門爲快速傳輸小數據設計。適用於聊天室等須要雙向通訊的場景。

  4. WebSocket的特色

    (1) 雙向通訊,服務器能夠主動向客戶端推送信息,客戶端也能夠主動向服務器發送信息

    (2) 創建在TCP協議之上

    (3) 與HTTP協議有着良好的兼容性

    (4) 數據格式比較輕量,性能開銷小,通訊高效

    (5) 能夠發送文本,也能夠發送二進制數據

    (6) 沒有同源限制,是否與某個域中的頁面通訊,徹底取決於服務器(經過握手信息能夠知道請求來自何方)

    (7) 協議標識符爲wswss,服務器網址就是URL

  5. WebSocket協議與HTTP協議的聯繫和區別

    (1) 聯繫

    • 二者都創建在TCP協議之上,經過TCP傳遞數據。
    • 爲了兼容現有瀏覽器的握手規範,WebSocket須要借用HTTP協議完成握手階段。

    (2)區別

    WebSocket HTTP
    是HTML5新增的一種通訊協議 與HTML無直接關係
    雙向通訊 單向通訊
    持久鏈接,整個通信過程創建在一次鏈接中 非持久鏈接,每次請求要從新創建鏈接
  6. 創建WebSocket鏈接的過程

    客戶端向服務器發送一個升級協議的HTTP請求,這個請求頭部包含ConnectionUpgrade字段,表示客戶端須要使用WebSocket協議。服務器將HTTP協議升級成WebSocket協議後返回客戶端響應數據,即完成了握手階段,創建了WebSocket鏈接,這個鏈接會持續存在,直到客戶端或服務器主動關閉鏈接。

  7. WebSocket的使用

    (1) 使用WebSocket構造函數建立WebSocket對象

    var ws = new WebSocket('wss://wx.douyucdn.cn')
    複製代碼

    (2) 添加事件處理程序

    ws.onopen = function() {
      // 調用send()方法發送數據
      ws.send('發送數據');
    }
    ws.onmessage = function(event) {
      // 處理接收到的數據
      var receive_msg = event.data;
    }
    ws.onerror = function() {
      // 出錯處理
      ws.close();
    }
    ws.onclose = function() {
      // 關閉WebSocket
    }
    複製代碼
  8. WebSocket的應用

    雙向通訊,如聊天室。

    (1) 微信小程序對WebSocket進行了封裝,wx.connectSocket()能夠理解爲建立了一個WebSocket實例SocketTask

    (2) socket.io支持WebSocket、輪詢、HTTP流等方式。

  9. WebSocket的降級方案

    WebSocket協議不一樣於HTTP,須要創建和維護WebSocket服務器。若是現有服務器不能用於WebSocket通訊,能夠組合使用XHRSSE實現雙向通訊。【WebSocket至關於在SSE的基礎上增長了send()方法】


詳解:

  1. HTTP流的實現:

    • 服務端

      <?php
          $i = 0;
          while(true) {
              // 輸出一些數據,而後當即刷新輸出緩存
              echo "Number is $i";
              flush();
              
              // 等待幾秒鐘
              sleep(10);
              
              $i++;
          }
      ?>
      複製代碼
    • 瀏覽器

      function createStreamingClient(url, progress, finished){
        var xhr = new XMLHttpRequest(),
          received = 0;
        
        xhr.open("get", url, true);
        xhr.onreadystatechange = function(){
          var result;
          if (xhr.readyState == 3){
            //只取得最新數據並調整計數器
            result = xhr.responseText.substring(received);
            received += result.length;
            //調用 progress 回調函數
            progress(result);
          } else if (xhr.readyState == 4){
            finished(xhr.responseText);
          }
        };
        xhr.send(null);
        return xhr;
      }
      
      var client = createStreamingClient("streaming.php", function(data){
          alert("Received: " + data);
        }, function(data){
          alert("Done!");
        });
      複製代碼
  2. SSE API

    (1) 建立一個EventSource對象

    var source = new EventSource('myevents.php');
    複製代碼

    (2) 添加事件處理程序

    source.onopen = function() {}
    source.onmessage = function(event) {
      // 處理數據
      var data = event.data;
    }
    source.onerror = function() {
      // 出錯處理
      source.close();
    }
    複製代碼

    (3) 屬性

    • readyState屬性:鏈接的狀態
      • 0:表示正在鏈接
      • 1:打開了鏈接
      • 2:關閉了鏈接

    (4) 方法

    • close():強制當即斷開鏈接而且再也不從新鏈接。默認狀況下,EventSource對象會保持與服務器的活動鏈接,若是鏈接斷開,還會從新鏈接。

    注:SSE方式服務器返回的數據是流信息,響應的MIME類型必須是text/event-stream,即設置響應頭部:

    Content-Type: text/event-stream
    複製代碼
  3. HTTP與WebSocket的生命週期

    image

  4. WebSocket握手的請求頭和響應頭

    請求中的header:

    • Connection: Upgrade:指示這是一個升級請求
    • Upgrade: websocket:表示升級爲websocket協議
    • Sec-WebSocket-Key:向服務器提供所需的信息,確認客戶端有權請求升級到WebSocket,防止濫用。此頭部由客戶端自動生成,沒法經過XMLHttpRequest.setRequestHeader()方法添加。
    • Sec-WebSocket-Protocol:以優先順序指定客戶端要使用的一個或多個協議
    • Sec-WebSocket-Version:指定客戶端但願使用的WebSocket協議版本
    • Sec-WebSocket-Extensions:指定要求服務器使用的一個或多個WebSocket擴展

    服務端響應中的header:

    • Connection: Upgrade
    • Upgrade: websocket:和Connection一塊兒表示服務器已成功切換協議
    • Sec-WebSocket-Accept:返回根據請求頭中Sec-WebSocket-Key字段值生成的值
    • Sec-WebSocket-Protocol:返回客戶端指定使用的全部協議中支持的第一個協議
    • Sec-WebSocket-Version:服務器若是支持客戶端要求的協議版本,則響應頭中不包含這個字段。不然,服務端將返回一個錯誤,並在響應頭中以此字段返回服務器支持的協議列表
    • Sec-WebSocket-Extensions:MDN文檔中沒有明確指明,私覺得與Sec-WebSocket-Version類似
  5. WebSocket API

    (1) 使用構造函數建立WebSocket對象

    var socket = new WebSocket(url, [protocol]);  // protocol指定了可接收的子協議
    複製代碼

    (2) 屬性

    • WebSocket.readyState:返回實例對象的當前狀態
      • 0:對應WebSocket.CONNECTING,正在鏈接
      • 1:對應WebSocket.OPEN,鏈接成功
      • 2:對應WebSocket.CLOSING,正在關閉鏈接
      • 3:對應WebSocket.CLOSED,鏈接關閉,或打開鏈接失敗
    • WebSocket.bufferedAmount:表示隊列中等待傳輸的UTF-8字節數
    • WebSocket.onopen
    • WebSocket.onmessage
    • WebSocket.onerror
    • WebSocket.onclose
    • WebSocket.binaryType
    • WebSocket.protocol
    • WebSocket.url

    (3) 事件

    事件 事件處理程序 描述
    open Socket.onopen 鏈接創建時觸發
    message Socket.onmessage 客戶端接收服務端數據時觸發
    error Socket.onerror 通訊發生錯誤時觸發
    close Socket.onclose 鏈接關閉時觸發

    (4) 方法

    • WebSocket.send(data):發送數據

    • WebSocket.close:關閉鏈接

  6. WebSocket在項目中的應用:

    • 微信鬥魚小程序tcp/TcpClient.js使用wx.connectSocket返回WebSocket實例SocketTask
    • 主站代碼@shark/net/lib/tcp/webSocket.js直接調用WebSocket構造函數建立WebSocket實例

參考:

【阮一峯】WebSocket教程:www.ruanyifeng.com/blog/2017/0…

【知乎】WebSocket是什麼原理?爲何能夠實現持久鏈接?www.zhihu.com/question/20…

【掘金】WebSocket介紹以及node+socket-io實現聊天室功能:juejin.im/entry/5ab37…

【MDN】協議升級機制:developer.mozilla.org/zh-CN/docs/…

【MDN】WebSocket:developer.mozilla.org/en-US/docs/…

【菜鳥教程】HTML5 WebSocket:www.runoob.com/html/html5-…

【HTML5】全雙工通訊的WebSocket:halfrost.com/websocket/

【socket.io】socket.io:socket.io/get-started…

【JavaScript高級程序設計】第21章21.5節

相關文章
相關標籤/搜索