webSocket簡介
webSocket是一種可在單個TCP連線上進行全雙工通訊的網路傳輸協議,同樣是HTML 5規範的組成部分之一。webSocket在2008年誕生,2011年成為國際標準。所有瀏覽器都已經支援了
websocket的特點
建立在 TCP 協議之上,伺服器端的實現比較容易
與 HTTP 協議有著良好的相容性。預設埠也是 80 和 443 ,並且握手階段採用 HTTP 協議,能透過各種 HTTP 代理伺服器
資料格式比較輕量,效能開銷小,通訊高效
可以傳送文字,也可以傳送二進位制資料
沒有同源限制,客戶端可以與任意伺服器通訊
協議識別符號是ws(如果加密,則為wss),伺服器網址就是 URL
websocket握手建立連線過程
來自客戶端的握手看起來像如下形式:
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
Connection 必須設定 Upgrade,表示客戶端希望連線升級;Upgrade欄位必須設定 WebSocket,表示希望升級到 WebSocket 協議
來自伺服器的握手看起來像如下形式:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat
客戶端可以在控制檯 -network-ws下看到 WebSocket 訊息,可以看到,客戶端發起的websocket連線報文類似http報文:
如果服務端支援 websocket,會在響應頭中返回相同的資訊,並且連線狀態置為101(協議切換成功)
一旦客戶端和伺服器都傳送了它們的握手,且如果握手成功,接著開始資料傳輸部分
websocket客戶端的API
建構函式
WebSocket(url[, protocols])
const ws = new WebSocket('ws://localhost:8080/websocket');
協議識別符號,根據window.location.protocol是http還是https確定是用ws還是wss
常量
ws.readyState(只讀)表示當前的連結狀態
l CONNECTING:值為0,表示正在連線
l OPEN:值為1,表示連線成功,可以通訊了
l CLOSING:值為2,表示連線正在關閉
l CLOSED:值為3,表示連線已經關閉,或者開啟連線失敗
屬性
(1)WebSocket.binaryType - DOMString
使用二進位制的資料型別連線。取值應當是"blob"或者"arraybuffer"。"blob"表示使用DOM Blob 物件,而"arraybuffer"表示使用 ArrayBuffer 物件
(2)WebSocket.bufferedAmount (只讀)- unsigned long
未傳送至伺服器的位元組數。呼叫 send()) 方法將多位元組資料加入到佇列中等待傳輸,但是還未發出。該值會在所有佇列資料被髮送後重置為 0。而當連線關閉時不會設為0。如果持續呼叫send(),這個值會持續增長
(3)WebSocket.extensions (只讀)- DOMString
伺服器選擇的擴充套件。目前這個屬性只是一個空字串,或者是一個包含所有擴充套件的列表
(4)WebSocket.onclose - EventListener
用於指定連線關閉後的回撥函式。當 WebSocket 物件的readyState 狀態變為 CLOSED 時會觸發該事件。這個監聽器會接收一個叫close的 CloseEvent 物件
(5)WebSocket.onerror - EventListener
用於指定連線失敗後的回撥函式。會接受一個名為“error”的event物件
(6)WebSocket.onmessage - EventListener
用於指定當從伺服器接收到資訊時的回撥函式。這個Listener會被傳入一個名為"message"的 MessageEvent 物件
(7)WebSocket.onopen - EventListener
用於指定連線成功後的回撥函式。當readyState的值變為 OPEN 的時候會觸發該事件。該事件表明這個連線已經準備好接受和傳送資料。這個監聽器會接受一個名為"open"的事件物件
(8)WebSocket.protocol (只讀)- DOMString
伺服器選擇的下屬協議。這個屬性的取值會被取值為建構函式傳入的protocols引數
(9)WebSocket.readyState(只讀)
當前的連結狀態
(10)WebSocket.url (只讀)
WebSocket 的絕對路徑。傳入構造器的URL
方法
WebSocket.close([code[, reason]]) 關閉當前連結
code 可選:
一個數字值表示關閉連線的狀態號,表示連線被關閉的原因。如果這個引數沒有被指定,預設的取值是1000 (表示正常連線關閉)。請看 CloseEvent 頁面的 list of status codes來看預設的取值
reason 可選:
一個可讀的字串,表示連線被關閉的原因。這個字串必須是不長於123位元組的UTF-8 文字(不是字元)
WebSocket.send(data) 要傳送到伺服器的資料。websocket會對要傳輸的資料進行排隊
示例
const ws = new WebSocket('ws://localhost:8818');
ws.onopen = function(e) {
console.log("連線伺服器成功");
}
ws.onclose = function(e) {
console.log("伺服器關閉");
}
ws.onerror = function() {
console.log("連線出錯");
}
ws.onmessage = function(e){
const time = new Date();
console.log(time+"的訊息:"+e.data);
}
websocket心跳檢測&斷線重連
為了保證連線穩定,需要考慮一些異常情況,如網路波動導致連線中斷,伺服器超時等
1、心跳檢測
WebSocket 為了保持客戶端、服務端的實時雙向通訊,需要確保客戶端、服務端之間的 TCP 通道保持連線沒有斷開。然而,對於長時間沒有資料往來的連線,如果依舊長時間保持著,可能會浪費包括的連線資源。但不排除有些場景,客戶端、服務端雖然長時間沒有資料往來,但仍需要保持連線。這個時候,可以採用心跳來實現。心跳檢測即客戶端定時向服務端傳送心跳訊息,保持連線穩定
2、斷線重連
斷線重連即傳送訊息前,檢測連線狀態,若連線中斷,嘗試n次連線
websocket的特點
location /websocket {
proxy_pass http://ip:port; # websocket伺服器
proxy_http_version 1.1; # http協議切換
proxy_set_header Host $host; # 保留源資訊
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Upgrade $http_upgrade; # 請求協議升級
proxy_set_header Connection $connection_upgrade;
}
websocket服務端的實現
Node的 實現方式有以下幾種。
l Socket.IO
l µWebSockets
l WebSocket-Node
l ws
其中socket.io是基於 Node 的實時應用程式框架,對比原生 webSocket,封裝了更多通用能力,且在不支援webSocket的瀏覽器上,可以降級為輪詢方式通訊。但是,其要求前後端必須統一,即後端使用 socket.io 則前端必須使用 socket.io-client 對應
應用場景
基於websocket的實時通訊的特點,經常能看到其廣泛的應用場景,比如:
· 告警彈幕
· webssh
· 比賽排行榜實時更新