初識WebSocket

HTTP 協議特色

  • 單向請求
  • 無狀態
  • 半雙工

通訊只能由客戶端主動發起請求來獲取服務端數據javascript

WebSocket是什麼

WebSocket是一種能夠建立和服務器間進行 雙向會話 的高級技術,經過WebSocket能夠向服務器發送消息並接受基於事件驅動的響應。這樣就不用向服務器輪詢獲取數據。html

雙向會話:客戶端和服務端都可以經過WebSocket來進行數據相互傳遞,即服務端能夠給客戶端推送數據,客戶端也能夠經過WebSocket向服務端傳遞數據。java

爲何要使用WebSocket?

在不使用WebSocket時,咱們須要創建長鏈接時。創建長鏈接的幾種主要方法:web

  • 輪詢
  • 長輪詢
  • SSE(Server Send Event)

輪詢

輪詢是最先在客戶端用來模擬長鏈接的一種方式。他經過客戶端定時向服務端發送HTTP請求來模擬客戶端向服務端發送數據,而服務端的數據則是在客戶端發送HTTP請求後跟隨返回
缺點: 服務端的數據須要在客戶端的請求回來後才能帶回。若是HTTP請求的間隔過短,則會致使大量的網絡開銷;若是間隔太長,這將致使數據傳遞的不及時api

長輪詢

長輪詢是在輪詢的基礎上改進的一種方式。在客戶端發送HTTP請求且服務端收到請求時,服務端會先維持這個請求不返回。在特定的時間內(通常爲30秒,由於一般HTTP判斷超時時間爲30秒),若是服務端沒有數據,則迴應這個請求;服務端有數據須要發送時,則當即經過HTTP請求的響應將數據傳遞給客戶端。客戶端收到響應後,當即發起下一次的HTTP請求。
優缺點:可以解決輪詢中帶來的服務端數據不能及時傳遞的問題,可是帶來的網絡花銷大的問題仍然沒法解決服務器

SSE(Server Send Event)

SSE一種新的協議,用於服務端向客戶端推送數據,經過SSE實現數據的單向推送功能。
缺點: 單向推送,只能從服務端向客戶端推送數據、websocket

WebSocket可以解決的問題

WebSocket可以有效的解決上述問題,還包括如下問題:網絡

  1. 帶寬問題:WebSocket相對HTTP協議頭更小,按需傳遞數據
  2. 數據實時性問題:WebSocket相對輪詢和長輪詢來講可以實時傳遞數據,延遲更少
  3. 狀態問題:相對無狀態的HTTP,WebSocket在創建鏈接後會維持特定的狀態

WebSocket協議

WebSocket協議是由HTTP協議升級而來的,只要在HTTP協議的基礎上增長兩次握手(若是是須要經過SSL加密,則還須要進行SSL握手過程),便可創建WebSocket鏈接。如下Header相關字段socket

請求Header

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13性能

其中:

  • Host: server.example.com:表示將要鏈接的WebSocket地址。
  • Connection: Upgrade:表示HTTP鏈接須要升級
  • Upgrade: websocket:表示將HTTP鏈接升級爲WebSocket鏈接
  • Sec-WebSocket-Key:dGhlIHNhbXBsZSBub25jZQ==:客戶端生成的WebSocket密鑰
  • Sec-WebSocket-Protocol: chat, superchat:指定客戶端那些WebSocket協議是能夠接受的
  • Sec-WebSocket-Version: 13:指定WebSocket版本

響應Header

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat

其中:

  • Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo:服務端根據客戶端生成的鏈接密鑰生成服務端密鑰
  • Connection: Upgrade:確認升級HTTP鏈接
  • Upgrade: websocket:確認將HTTP鏈接升級爲WebSocket鏈接
  • Sec-WebSocket-Protocol: chat:服務端選擇的WebSocket協議

WebSocket API

WebSocket的API比較簡單,按使用順序包括:

  • 創建鏈接
  • 接收消息
  • 發送消息
  • 關閉鏈接

創建鏈接

WebSocket 經過實例化來建立鏈接,經過實例的open事件的回調來確認鏈接建立成功,如:

const websocket = new WebSocket('ws://server.example.com');
websocket.addEventListener('open', e => {
    // 創建鏈接成功...
});

ps:在WebSocket創建ws鏈接時,url能夠是域名或者IP地址;可是當創建的鏈接是wss(加密WebSocket)時,url必須是域名,由於須要配置相應的證書,而證書是針對域名的。

接收消息

WebSocket 經過message事件來監聽消息接收,如:

websocket .addEventListener('message', e => {
    // 消息接收成功
});

WebSocket能夠傳遞StringArrayBufferBlob三種數據類型,所以在收到消息時多是其中的任意一種。其中,StringArrayBuffer使用的最多。

發送消息

WebSocket 的發送消息是經過實例的send方法來實現的。

websocket.send(data);

關閉鏈接

被動關閉

當服務端被動關閉WebSocket鏈接時,會經過WebSocket向客戶端發送一個close數據包,會觸發實例的WebSocket close事件如:

websocket.addEventListener('close', e => {
    // WebSocket鏈接關閉
});

注:當網絡斷開時,WebSocket鏈接並不會被動關閉,由於沒有收到關閉的數據包

主動關閉

客戶端能夠經過WebSocket提供的close方法來主動關閉長鏈接

websocket.close();

注:主動關閉不會觸發close事件

其餘客戶端API

websocket.readyState
readyState屬性返回實例對象的當前狀態,共有四種

  • CONNECTING 值爲0 表示正在鏈接
  • OPEN 值爲1 表示已經鏈接,能夠通訊
  • CLOSING 值爲2 表示鏈接正在關閉
  • CLOSED 值爲3 表示鏈接已經關閉

websocket.bufferedAmount
實例對象的bufferedAmount屬性,表示還有多少字節的二進制數據沒有發送出去,能夠經過該屬性來判斷數據發送是否結束。

var data = new ArrayBuffer(10000000);
    socket.send(data);

    if (socket.bufferedAmount === 0) {
      // 發送完畢
    } else {
      // 發送還沒結束
    }

websocket.binaryType
binaryType屬性,顯式指定收到的二進制數據類型

// 收到的是 blob 數據
websocket.binaryType = "blob";
websocket.onmessage = function(e) {
  console.log(e.data.size);
};

// 收到的是 ArrayBuffer 數據
websocket.binaryType = "arraybuffer";
websocket.onmessage = function(e) {
  console.log(e.data.byteLength);
};

總結

經過WebSocket的長鏈接,客戶端和服務端能夠進行大量的數據傳輸而不會帶來相關的性能問題,這給Web端帶來了極大的功能加強。目前Web端可使用WebSocket來進行IM相關功能開發,或者實時協做等須要與服務端進行大量數據交互的功能,而且不須要像以前同樣使用長輪詢的Hack方式來實現。

參考連接

WebSocket 教程

相關文章
相關標籤/搜索