一、什么是WebScoket??
WebSocket 是一種網(wǎng)絡傳輸協(xié)議,可在單個 TCP 連接上進行全雙工通信,位于 OSI 模型的應用層。WebSocket 使得客戶端和服務器之間的數(shù)據(jù)交換變得更加簡單,允許服務端主動向客戶端推送數(shù)據(jù)。在 WebSocket API 中,瀏覽器和服務器只需要完成一次握手,兩者之間就可以創(chuàng)建持久性的連接,并進行雙向數(shù)據(jù)傳輸。
下圖是輪詢與websocket的區(qū)別
websocket
1.2、WebSocket 優(yōu)點
- 較少的控制開銷。在連接創(chuàng)建后,服務器和客戶端之間交換數(shù)據(jù)時,用于協(xié)議控制的數(shù)據(jù)包頭部相對較小。
- 更強的實時性。由于協(xié)議是全雙工的,所以服務器可以隨時主動給客戶端下發(fā)數(shù)據(jù)。相對于 HTTP 請求需要等待客戶端發(fā)起請求服務端才能響應,延遲明顯更少。
- 保持連接狀態(tài)。與 HTTP 不同的是,WebSocket 需要先創(chuàng)建連接,這就使得其成為一種有狀態(tài)的協(xié)議,之后通信時可以省略部分狀態(tài)信息。
- 更好的二進制支持。WebSocket 定義了二進制幀,相對 HTTP,可以更輕松地處理二進制內(nèi)容。
- 可以支持擴展。WebSocket 定義了擴展,用戶可以擴展協(xié)議、實現(xiàn)部分自定義的子協(xié)議。
二、WebScoket API??
在瀏覽器中要使用 WebSocket 提供的能力,我們就必須先創(chuàng)建 WebSocket 對象,該對象提供了用于創(chuàng)建和管理 WebSocket 連接,以及可以通過該連接發(fā)送和接收數(shù)據(jù)的 API。
2.1、構(gòu)造函數(shù)
const myWebSocket = new WebSocket(url [, protocols]);
- url:表示連接的 URL,這是 WebSocket 服務器將響應的 URL
- protocols(可選):一個協(xié)議字符串或者一個包含協(xié)議字符串的數(shù)組。這些字符串用于指定子協(xié)議,這樣單個服務器可以實現(xiàn)多個 WebSocket 子協(xié)議。比如,你可能希望一臺服務器能夠根據(jù)指定的協(xié)議(protocol)處理不同類型的交互。如果不指定協(xié)議字符串,則假定為空字符串。
2.2、屬性
WebSocket 對象包含以下屬性:
每個屬性的具體含義如下:
- binaryType:使用二進制的數(shù)據(jù)類型連接。
- bufferedAmount(只讀):未發(fā)送至服務器的字節(jié)數(shù)。
- extensions(只讀):服務器選擇的擴展。
- onclose:用于指定連接關(guān)閉后的回調(diào)函數(shù)。
- onerror:用于指定連接失敗后的回調(diào)函數(shù)。
- onmessage:用于指定當從服務器接受到信息時的回調(diào)函數(shù)。
- onopen:用于指定連接成功后的回調(diào)函數(shù)。
- protocol(只讀):用于返回服務器端選中的子協(xié)議的名字。
- readyState(只讀):返回當前 WebSocket 的連接狀態(tài),共有 4 種狀態(tài):
CONNECTING — 正在連接中,對應的值為 0;
OPEN — 已經(jīng)連接并且可以通訊,對應的值為 1;
CLOSING — 連接正在關(guān)閉,對應的值為 2;
CLOSED — 連接已關(guān)閉或者沒有連接成功,對應的值為 3。
- url(只讀):返回值為當構(gòu)造函數(shù)創(chuàng)建 WebSocket 實例對象時 URL 的絕對路徑。
2.3、方法
- close([code[, reason]]):該方法用于關(guān)閉 WebSocket 連接,如果連接已經(jīng)關(guān)閉,則此方法不執(zhí)行任何操作。
- send(data):該方法將需要通過 WebSocket 鏈接傳輸至服務器的數(shù)據(jù)排入隊列,并根據(jù)所需要傳輸?shù)臄?shù)據(jù)的大小來增加 bufferedAmount 的值 。若數(shù)據(jù)無法傳輸(比如數(shù)據(jù)需要緩存而緩沖區(qū)已滿)時,套接字會自行關(guān)閉。
2.4、 事件
使用 addEventListener() 或?qū)⒁粋€事件監(jiān)聽器賦值給 WebSocket 對象的 oneventname 屬性,來監(jiān)聽下面的事件。
- close:當一個 WebSocket 連接被關(guān)閉時觸發(fā),也可以通過 onclose 屬性來設(shè)置。
- error:當一個 WebSocket 連接因錯誤而關(guān)閉時觸發(fā),也可以通過 onerror 屬性來設(shè)置。
- message:當通過 WebSocket 收到數(shù)據(jù)時觸發(fā),也可以通過 onmessage 屬性來設(shè)置。
- open:當一個 WebSocket 連接成功時觸發(fā),也可以通過 onopen 屬性來設(shè)置。
三、其他???♀?
3.1、WebSocket 與 HTTP 有什么關(guān)系
WebSocket 是一種與 HTTP 不同的協(xié)議。兩者都位于 OSI 模型的應用層,并且都依賴于傳輸層的 TCP 協(xié)議。 雖然它們不同,但是 RFC 6455 中規(guī)定:WebSocket 被設(shè)計為在 HTTP 80 和 443 端口上工作,并支持 HTTP 代理和中介,從而使其與 HTTP 協(xié)議兼容。 為了實現(xiàn)兼容性,WebSocket 握手使用 HTTP Upgrade 頭,從 HTTP 協(xié)議更改為 WebSocket 協(xié)議。
3.2、WebSocket 與長輪詢有什么區(qū)別
長輪詢就是客戶端發(fā)起一個請求,服務器收到客戶端發(fā)來的請求后,服務器端不會直接進行響應,而是先將這個請求掛起,然后判斷請求的數(shù)據(jù)是否有更新。如果有更新,則進行響應,如果一直沒有數(shù)據(jù),則等待一定的時間后才返回。
長輪詢的本質(zhì)還是基于 HTTP 協(xié)議,它仍然是一個一問一答(請求 — 響應)的模式。而 WebSocket 在握手成功后,就是全雙工的 TCP 通道,數(shù)據(jù)可以主動從服務端發(fā)送到客戶端。
3.3、什么是 WebSocket 心跳
網(wǎng)絡中的接收和發(fā)送數(shù)據(jù)都是使用 SOCKET 進行實現(xiàn)。但是如果此套接字已經(jīng)斷開,那發(fā)送數(shù)據(jù)和接收數(shù)據(jù)的時候就一定會有問題??墒侨绾闻袛噙@個套接字是否還可以使用呢?這個就需要在系統(tǒng)中創(chuàng)建心跳機制。所謂 “心跳” 就是定時發(fā)送一個自定義的結(jié)構(gòu)體(心跳包或心跳幀),讓對方知道自己 “在線”。 以確保鏈接的有效性。
而所謂的心跳包就是客戶端定時發(fā)送簡單的信息給服務器端告訴它我還在而已。代碼就是每隔幾分鐘發(fā)送一個固定信息給服務端,服務端收到后回復一個固定信息,如果服務端幾分鐘內(nèi)沒有收到客戶端信息則視客戶端斷開。
在 WebSocket 協(xié)議中定義了 心跳 Ping 和 心跳 Pong 的控制幀:
- 心跳 Ping 幀包含的操作碼是 0x9。如果收到了一個心跳 Ping 幀,那么終端必須發(fā)送一個心跳 Pong 幀作為回應,除非已經(jīng)收到了一個關(guān)閉幀。否則終端應該盡快回復 Pong 幀。
- 心跳 Pong 幀包含的操作碼是 0xA。作為回應發(fā)送的 Pong 幀必須完整攜帶 Ping 幀中傳遞過來的 “應用數(shù)據(jù)” 字段。如果終端收到一個 Ping 幀但是沒有發(fā)送 Pong 幀來回應之前的 Ping 幀,那么終端可以選擇僅為最近處理的 Ping 幀發(fā)送 Pong 幀。此外,可以自動發(fā)送一個 Pong 幀,這用作單向心跳。
