天天看點

通俗易懂了解 WebSocket及其應用

應用場景:

用戶端與浏覽器間進行通信,正常操作,我們在用戶端發送一個http請求,服務端收到我們的http請求後,傳回一個請求結果。這種方式,我們隻能主動的從服務端去擷取資料,假若想服務端資料有更新第一時間回報到用戶端,我們再利用http請求通信就行不通了。接下來我們來探讨一下WebSocket如何去實作上述情景中所提應用需求。

WebSocket簡介

首先了解一下,Socket又稱"套接字",應用程式通常通過"套接字"向網絡送出請求或者應答網絡請求。Socket的英文原義是“孔”或“插座”,作為UNIX的程序通信機制。Socket可以實作應用程式間網絡通信。

WebSocket是HTML5新增加的(協定),也就是說HTTP協定沒有變化,或者說和HTTP沒關系,但HTTP是不支援持久連接配接的。 Websocket 其實是一個新協定,跟HTTP協定基本沒有關系,隻是為了相容現有浏覽器的握手規範而已,也就是說它是HTTP協定上的一種補充。它們有交集,但不等于。

通俗易懂了解 WebSocket及其應用

簡而言之:WebSocket 是 HTML5 開始提供的一種在單個 TCP 連接配接上進行全雙工通訊的協定。

為什麼需要 WebSocket ?

了解計算機網絡協定的人,應該都知道:HTTP 協定是一種無狀态的、無連接配接的、單向的應用層協定。它采用了請求/響應模型。通信請求隻能由用戶端發起,服務端對請求做出應答處理。

這種通信模型有一個弊端:HTTP 協定無法實作伺服器主動向用戶端發起消息。

這種單向請求的特點,注定了如果伺服器有連續的狀态變化,用戶端要獲知就非常麻煩。大多數 Web 應用程式将通過頻繁的異步JavaScript和XML(AJAX)請求實作長輪詢。輪詢的效率低,非常浪費資源(因為必須不停連接配接,或者 HTTP 連接配接始終打開)。

WebSocket 連接配接允許用戶端和伺服器之間進行全雙工通信,以便任一方都可以通過建立的連接配接将資料推送到另一端。WebSocket 隻需要建立一次連接配接,就可以一直保持連接配接狀态。這相比于輪詢方式的不停建立連接配接顯然效率要大大提高。

了解完WebSocket是什麼,以及為什麼需要WebSocket,我們更需要知道怎麼去使用它,作為前端開發的角色在前端上我們該如何使用呢。

WebSocket使用

使用方法:

var ws = new WebSocket("wss://echo.websocket.org");

ws.onopen = function(evt) {
  console.log("Connection open ...");
  ws.send("Hello WebSockets!");
};

ws.onmessage = function(evt) {
  console.log( "Received Message: " + evt.data);
  ws.close();
};

ws.onclose = function(evt) {
  console.log("Connection closed.");
};   
           

WebSocket API

可參考 https://developer.mozilla.org/en-US/docs/Web/API/WebSocket

1) WebSocket 構造函數

WebSocket 對象作為一個構造函數,用于建立 WebSocket 執行個體。

var ws = new WebSocket('ws://localhost:8080');
           

執行上面語句之後,用戶端就會與伺服器進行連接配接。

2)webSocket.readyState

readyState屬性傳回執行個體對象的目前狀态,共有四種。

CONNECTING:值為0,表示正在連接配接。
OPEN:值為1,表示連接配接成功,可以通信了。
CLOSING:值為2,表示連接配接正在關閉。
CLOSED:值為3,表示連接配接已經關閉,或者打開連接配接失敗。
           

下面是一個示例。

switch (ws.readyState) {
  case WebSocket.CONNECTING:
    // do something
    break;
  case WebSocket.OPEN:
    // do something
    break;
  case WebSocket.CLOSING:
    // do something
    break;
  case WebSocket.CLOSED:
    // do something
    break;
  default:
    // this never happens
    break;
}
           
3)webSocket.onopen

執行個體對象的onopen屬性,用于指定連接配接成功後的回調函數。

ws.onopen = function () {
  ws.send('Hello Server!');
}
           

如果要指定多個回調函數,可以使用addEventListener方法。

ws.addEventListener('open', function (event) {
  ws.send('Hello Server!');
});
           
4)webSocket.onclose

執行個體對象的onclose屬性,用于指定連接配接關閉後的回調函數。

ws.onclose = function(event) {
  var code = event.code;
  var reason = event.reason;
  var wasClean = event.wasClean;
  // handle close event
};



ws.addEventListener("close", function(event) {
  var code = event.code;
  var reason = event.reason;
  var wasClean = event.wasClean;
  // handle close event
});
           
5)webSocket.onmessage

執行個體對象的onmessage屬性,用于指定收到伺服器資料後的回調函數。

ws.onmessage = function(event) {
  var data = event.data;
  // 處理資料
};


ws.addEventListener("message", function(event) {
  var data = event.data;
  // 處理資料
});
           

注意,伺服器資料可能是文本,也可能是二進制資料(blob對象或Arraybuffer對象)。

ws.onmessage = function(event){
  if(typeof event.data === String) {
    console.log("Received data string");
  }

  if(event.data instanceof ArrayBuffer){
    var buffer = event.data;
    console.log("Received arraybuffer");
  }

}
           

除了動态判斷收到的資料類型,也可以使用binaryType屬性,顯式指定收到的二進制資料類型。

// 收到的是 blob 資料

ws.binaryType = "blob";
ws.onmessage = function(e) {
  console.log(e.data.size);
};


// 收到的是 ArrayBuffer 資料
ws.binaryType = "arraybuffer";
ws.onmessage = function(e) {
  console.log(e.data.byteLength);
};
           
6)webSocket.send()

執行個體對象的send()方法用于向伺服器發送資料。

發送文本的例子。

ws.send('your message');
           

發送 Blob 對象的例子。

var file = document
  .querySelector('input[type="file"]')
  .files[0];

ws.send(file);
           

發送 ArrayBuffer 對象的例子。

// Sending canvas ImageData as ArrayBuffer
var img = canvas_context.getImageData(0, 0, 400, 320);
var binary = new Uint8Array(img.data.length);
for (var i = 0; i < img.data.length; i++) {
  binary[i] = img.data[i];
}

ws.send(binary.buffer);
           
7)webSocket.bufferedAmount

執行個體對象的bufferedAmount屬性,表示還有多少位元組的二進制資料沒有發送出去。它可以用來判斷發送是否結束。

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

if (socket.bufferedAmount === 0) {
  // 發送完畢

} else {
  // 發送還沒結束

}
           
8)webSocket.onerror

執行個體對象的onerror屬性,用于指定報錯時的回調函數。

socket.onerror = function(event) {
  // handle error event

};

socket.addEventListener("error", function(event) {
  // handle error event

});
           

前後端配合,即可完成資訊的實時推送。

繼續閱讀