近年來,隨着HTML5的誕生,WebSocket協議被提出,它實現了瀏覽器與服務器的全雙工通訊,擴展了瀏覽器與服務端的通訊功能,使服務端也能主動向客戶端發送數據。
咱們知道,傳統的HTTP協議是無狀態的,每次請求(request)都要由客戶端(如 瀏覽器)主動發起,服務端進行處理後返回response結果,而服務端很難主動向客戶端發送數據;這種客戶端是主動方,服務端是被動方的傳統Web模式 對於信息變化不頻繁的Web應用來講形成的麻煩較小,而對於涉及實時信息的Web應用卻帶來了很大的不便,如帶有即時通訊、實時數據、訂閱推送等功能的應用。在WebSocket規範提出以前,開發人員若要實現這些實時性較強的功能,常常會使用折衷的解決方法:輪詢。
輪詢是最原始的實現實時Web應用的解決方案。輪詢技術要求客戶端以設定的時間間隔週期性地向服務端發送請求,頻繁地查詢是否有新的數據改動。明顯地,這種方法會致使過多沒必要要的請求,浪費流量和服務器資源。
輪詢都是基於請求-應答模式,都不算是真正意義上的實時技術;它們的每一次請求、應答,都浪費了必定流量在相同的頭部信息上,而且開發複雜度也較大。
伴隨着HTML5推出的WebSocket,真正實現了Web的實時通訊,使B/S模式具有了C/S模式的實時通訊能力。WebSocket的工做流程是這 樣的:瀏覽器經過JavaScript向服務端發出創建WebSocket鏈接的請求,在WebSocket鏈接創建成功後,客戶端和服務端就能夠經過 TCP鏈接傳輸數據。由於WebSocket鏈接本質上是TCP鏈接,不須要每次傳輸都帶上重複的頭部數據,因此它的數據傳輸量比輪詢小 了不少。web
創建在 TCP 協議之上,服務器端的實現比較容易。瀏覽器
與 HTTP 協議有着良好的兼容性。默認端口也是80和443,而且握手階段採用 HTTP 協議,所以握手時不容易屏蔽,能經過各類 HTTP 代理服務器。服務器
數據格式比較輕量,性能開銷小,通訊高效。app
能夠發送文本,也能夠發送二進制數據。socket
沒有同源限制,客戶端能夠與任意服務器通訊。ide
協議標識符是ws(若是加密,則爲wss),服務器網址就是 URL。函數
WebSocket 對象做爲一個構造函數,用於新建 WebSocket 實例,執行完以後,客戶端就會與服務端進行鏈接
下面看一個簡單的例子:性能
var ws = new WebSocket('http://127.0.0.1:8003');ws.onopen = function (evt) { console.log('鏈接已打開!'); ws.send('Hello WebSocket!!!');}ws.onmessage = function (message) { console.log('接收到信息:' + message.data); ws.close();}ws.onclose = function (evt) { consoel.log('鏈接已關閉!')}
var ws = new WebSocket('http://127.0.0.1:8003');
執行上面語句以後,客戶端就會與服務器進行鏈接。this
實例對象的onopen屬性,用於指定鏈接成功後的回調函數。加密
ws.onopen = function () { ws.send('Hello Server!');}
若是要指定多個回調函數,可使用addEventListener方法。
ws.addEventListener('open', function (event) { ws.send('Hello Server!');});
實例對象的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"); }}
實例對象的send()方法用於向服務器發送數據。
// 發送文本的例子ws.send('your message');
// 發送 Blob 對象的例子var file = document .querySelector('input[type="file"]') .files[0];ws.send(file);
實例對象的onerror屬性,用於指定報錯時的回調函數。
socket.onerror = function(event) { // 這裏寫報錯事件 };socket.addEventListener("error", function(event) { // 這裏寫監聽的報錯事件});
實例對象的onclose屬性,用於指定鏈接關閉後的回調函數。
ws.onclose = function(event) { var code = event.code; var reason = event.reason; var wasClean = event.wasClean; // 這裏寫關閉事件};ws.addEventListener("close", function(event) { var code = event.code; var reason = event.reason; var wasClean = event.wasClean; //這裏寫監聽的關閉事件});
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;}
webSocket.bufferedAmount
實例對象的bufferedAmount屬性,表示還有多少字節的二進制數據沒有發送出去。它能夠用來判斷髮送是否結束
var data = new ArrayBuffer(10000000);socket.send(data);if (socket.bufferedAmount === 0) { // 發送完畢} else { // 發送還沒結束}
webSocket.onerror
實例對象的onerror屬性,用於指定報錯時的回調函數
socket.onerror = function(event) { // handle error event};socket.addEventListener("error", function(event) { // handle error event});