【星課堂】一文帶你瞭解webSocket

星河Salaxy發表於2022-03-25

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

· 比賽排行榜實時更新


相關文章