什麼是WebSocket?php
WebSocket是HTML5開始提供的一種在TCP鏈接上進行全雙工通信的協議,是一種服務器推送技術。html
WebSocket出現以前客戶端如何獲取服務端的實時數據?html5
Comet:是一種服務器向頁面推送數據的技術。有如下實現方式:node
(1) ajax輪詢:瀏覽器定時向服務器發送請求,詢問服務器是否有新信息。web
(2) 長輪詢:客戶端發送請求後,服務器會保持鏈接,直到有新數據返回給客戶端或請求超時。客戶端收到數據並處理完,或者請求超時後,再向服務端發送新請求。ajax
(3) HTTP流:瀏覽器向服務器發送一個請求,服務器保持鏈接打開,而後週期性地向瀏覽器發送數據。瀏覽器經過偵聽readystatechange
事件及檢測readyState
的值是否爲3,是則比較此前接收到的數據,決定從收到的數據中的什麼位置開始取得最新的數據。小程序
(4) SSE:服務器發送事件,是圍繞只讀Comet交互推出的API。使用SSE API建立到服務器的單向鏈接,服務器能夠經過這個鏈接發送任意數量的數據。SSE支持ajax輪詢、長輪詢和HTTP流,能在斷開鏈接時自動肯定什麼時候從新鏈接。微信小程序
爲何須要WebSocket?瀏覽器
(1) HTTP協議的侷限緩存
(2) 輪詢、HTTP流、SSE方式存在侷限性:
WebSocket是一種與服務器進行全雙工、雙向通訊的信道,專門爲快速傳輸小數據設計。適用於聊天室等須要雙向通訊的場景。
WebSocket
的特色
(1) 雙向通訊,服務器能夠主動向客戶端推送信息,客戶端也能夠主動向服務器發送信息
(2) 創建在TCP協議之上
(3) 與HTTP協議有着良好的兼容性
(4) 數據格式比較輕量,性能開銷小,通訊高效
(5) 能夠發送文本,也能夠發送二進制數據
(6) 沒有同源限制,是否與某個域中的頁面通訊,徹底取決於服務器(經過握手信息能夠知道請求來自何方)
(7) 協議標識符爲ws
或wss
,服務器網址就是URL
WebSocket協議與HTTP協議的聯繫和區別
(1) 聯繫
(2)區別
WebSocket | HTTP |
---|---|
是HTML5新增的一種通訊協議 | 與HTML無直接關係 |
雙向通訊 | 單向通訊 |
持久鏈接,整個通信過程創建在一次鏈接中 | 非持久鏈接,每次請求要從新創建鏈接 |
創建WebSocket鏈接的過程
客戶端向服務器發送一個升級協議的HTTP請求,這個請求頭部包含Connection
和Upgrade
字段,表示客戶端須要使用WebSocket
協議。服務器將HTTP協議升級成WebSocket
協議後返回客戶端響應數據,即完成了握手階段,創建了WebSocket
鏈接,這個鏈接會持續存在,直到客戶端或服務器主動關閉鏈接。
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
}
複製代碼
WebSocket的應用
雙向通訊,如聊天室。
(1) 微信小程序對WebSocket
進行了封裝,wx.connectSocket()
能夠理解爲建立了一個WebSocket
實例SocketTask
。
(2) socket.io
支持WebSocket
、輪詢、HTTP流等方式。
WebSocket的降級方案
WebSocket
協議不一樣於HTTP
,須要創建和維護WebSocket
服務器。若是現有服務器不能用於WebSocket
通訊,能夠組合使用XHR
和SSE
實現雙向通訊。【WebSocket
至關於在SSE
的基礎上增長了send()
方法】
詳解:
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!");
});
複製代碼
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
屬性:鏈接的狀態
(4) 方法
注:SSE方式服務器返回的數據是流信息,響應的MIME
類型必須是text/event-stream
,即設置響應頭部:
Content-Type: text/event-stream
複製代碼
HTTP與WebSocket的生命週期
WebSocket握手的請求頭和響應頭
請求中的header:
Connection: Upgrade
:指示這是一個升級請求Upgrade: websocket
:表示升級爲websocket
協議Sec-WebSocket-Key
:向服務器提供所需的信息,確認客戶端有權請求升級到WebSocket
,防止濫用。此頭部由客戶端自動生成,沒法經過XMLHttpRequest.setRequestHeader()
方法添加。Sec-WebSocket-Protocol
:以優先順序指定客戶端要使用的一個或多個協議Sec-WebSocket-Version
:指定客戶端但願使用的WebSocket
協議版本Sec-WebSocket-Extensions
:指定要求服務器使用的一個或多個WebSocke
t擴展服務端響應中的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
類似WebSocket API
(1) 使用構造函數建立WebSocket
對象
var socket = new WebSocket(url, [protocol]); // protocol指定了可接收的子協議
複製代碼
(2) 屬性
WebSocket.readyState
:返回實例對象的當前狀態
WebSocket.CONNECTING
,正在鏈接WebSocket.OPEN
,鏈接成功WebSocket.CLOSING
,正在關閉鏈接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
:關閉鏈接
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節