天天看點

Web前端之WebSocket

什麼是WebSocket?

  • WebSocket 是 HTML5 開始提供的一種在單個 TCP 連接配接上進行全雙工通訊的協定。
  • 在 WebSocket API中,浏覽器和伺服器隻需要完成一次握手,兩者就直接可以建立持久性的連接配接,并進行雙向資料傳輸。
  • websocket彌補了HTTP不支援長連接配接的特點。

了解雙向通信

在WebSocket協定之前有三種實作雙向通信的方式:輪詢(polling)、長輪詢(long-polling)和 iframe流(streaming)。

  • 輪詢:是用戶端和伺服器之間會一直進行連接配接,每隔一段時間就詢問一次。而且每次發送請求都會有Http的Header,會很耗流量,也會消耗CPU的使用率。
  • 長輪詢:是對輪詢的改進版,用戶端發送HTTP給伺服器之後,看有沒有新消息,如果沒有新消息,就一直等待。當有新消息的時候,才會傳回給用戶端。- 優點:比 Polling 做了優化,有較好的時效性;
  • iframe流:方式是在頁面中插入一個隐藏的iframe,利用其src屬性在伺服器和用戶端之間建立一條長連接配接,伺服器向iframe傳輸資料(通常是HTML,内有負責插入資訊的javascript),來實時更新頁面。

雙向通信的優缺點

通信方式 優點 缺點
輪詢

實作簡單,

無需做過多的更改

輪詢的間隔過長,會導緻使用者不能及時接收到更新的資料; 輪詢的間隔過短,會導緻查詢請求過多,增加伺服器端的負擔
長輪詢 比輪詢做了優化,有較好的時效性 保持連接配接會消耗資源;伺服器沒有傳回有效資料,程式逾時
iframe流 消息能夠實時到達;浏覽器相容好 伺服器維護一個長連接配接會增加開銷;IE、chrome、Firefox會顯示加載沒有完成,圖示會不停旋轉

了解HTTP的局限性

iHTTP是半雙工協定,也就是說,在同一時刻資料隻能單向流動,用戶端向伺服器發送請求(單向的),然後伺服器響應請求(單向的)。
  • 伺服器不能主動推送資料給浏覽器。這就會導緻一些進階功能難以實作,諸如聊天室場景就沒法實作。

WebSocket 的特點

  • 支援雙向通信,實時性更強。
  • 建立在 TCP 協定之上,伺服器端的實作比較容易。
  • 與 HTTP 協定有着良好的相容性。預設端口也是80和443,并且握手階段采用 HTTP 協定,是以握手時不容易屏蔽,能通過各種 HTTP 代理伺服器。
  • 可以發送文本,也可以發送二進制資料。
  • 沒有同源限制,用戶端可以與任意伺服器通信。
  • 協定辨別符是ws(如果加密,則為wss),伺服器網址就是 URL。
  • 減少通信量:隻要建立起WebSocket連接配接,就希望一直保持連接配接狀态。

WebSocket 的使用

建立 WebSocket 對象

以上代碼中的第一個參數 url, 指定連接配接的 URL。第二個參數 protocol 是可選的,指定了可接受的子協定。

WebSocket 的屬性

屬性 描述
Socket.readyState 隻讀屬性 readyState 表示連接配接狀态:0 - 表示連接配接尚未建立。1 - 表示連接配接已建立,可以進行通信。2 - 表示連接配接正在進行關閉。3 - 表示連接配接已經關閉或者連接配接不能打開。
Socket.bufferedAmount 隻讀屬性 bufferedAmount 已被 send() 放入正在隊列中等待傳輸,但是還沒有發出的 UTF-8 文本位元組數

WebSocket的事件

事件 事件處理程式 描述
open Socket.onopen 連接配接建立時觸發
message Socket.onmessage 用戶端接收服務端資料時觸發
error Socket.onerror 通信發生錯誤時觸發
close Socket.onclose 連接配接關閉時觸發

WebSocket 方法

方法 描述
Socket.send() 使用連接配接發送資料
Socket.close() 關閉連接配接

代碼示例

// 打開一個 web socket
               var ws = new WebSocket("ws://localhost:9998/echo");
                
               ws.onopen = function()
               {
                  // Web Socket 已連接配接上,使用 send() 方法發送資料
                  ws.send("發送資料");
                  alert("資料發送中...");
               };
                
               ws.onmessage = function (evt) 
               { 
                  var received_msg = evt.data;
                  alert("資料已接收...");
               };
                
               ws.onclose = function()
               { 
                  // 關閉 websocket
                  alert("連接配接已關閉..."); 
               };
            }