淺淺的(de)聊一下 WebSocket
第一次看到
ws://和wss://時候,感(gan)覺好高級啊,還有這種協議(yi)。
Websocket 歷史
WebSocket是(shi)在2008年(nian)6月(yue)誕生(sheng)的1。經由IEFT標(biao)準(zhun)化(hua)后,2009年(nian)chrome 4第(di)一個提供(gong)了該標(biao)準(zhun)支持,并默認(ren)啟用(yong)。于2011年(nian)由IEFT標(biao)準(zhun)化(hua)為。
現在的瀏覽器均已支持該標準。
Websocket 出現的背景
思考一下我們經常遇到的一種需求場(chang)景,要求在某個網頁下,網頁的內容可以(yi)實時更(geng)新。
這(zhe)種(zhong)情況下,最大眾(zhong)化的方(fang)式就(jiu)是輪詢接口(kou)了,即通過(guo)定時器,定時請求接口(kou),獲(huo)取到最新的信息(xi)后,將內容更新到頁面中,如下:
setInterval(() => {
queryAPI().then(() => update());
}, 1000);
但是(shi)我(wo)們(men)知道,這種(zhong)(zhong)定時(shi)器的延時(shi)并不是(shi)很精確,而且(qie)加上接(jie)口的請求時(shi)延,實(shi)(shi)際(ji)時(shi)間(jian)可(ke)能不止代碼中(zhong)所預先設定的時(shi)間(jian)長度,所以這種(zhong)(zhong)實(shi)(shi)時(shi)更新是(shi)偽實(shi)(shi)時(shi)更新。
除此之(zhi)外,還(huan)有(you)一點可能會經常(chang)遇到(dao),即,我們更(geng)新信(xin)(xin)息(xi)(xi)并總是要更(geng)新整個(ge)(ge)頁(ye)面上所(suo)有(you)可以看到(dao)的(de)信(xin)(xin)息(xi)(xi),我們更(geng)關注一些經常(chang)變化的(de)信(xin)(xin)息(xi)(xi),比如(ru)狀(zhuang)態(tai),狀(zhuang)態(tai)的(de)信(xin)(xin)息(xi)(xi)可能大小(xiao)只有(you)幾個(ge)(ge)字節,但是我們輪(lun)詢(xun)接口拿(na)到(dao)的(de)信(xin)(xin)息(xi)(xi)卻是這個(ge)(ge)頁(ye)面的(de)所(suo)有(you)信(xin)(xin)息(xi)(xi),大小(xiao)自然(ran)不只幾個(ge)(ge)字節,但是除狀(zhuang)態(tai)以外的(de)信(xin)(xin)息(xi)(xi)都可以視(shi)作是冗(rong)余的(de)。

我們實際只需要一個字段,而且即使(shi)后(hou)端提(ti)供(gong)只返回(hui)狀(zhuang)態的接口(kou),但實際在一個請求中還要計算(suan)ip報文頭的大小(xiao),依舊是很占用帶寬的。
輪(lun)詢這種(zhong)解(jie)決方案目(mu)前依(yi)舊是(shi)非常流行,最新的(de)輪(lun)詢技(ji)術是(shi)Comet,這種(zhong)技(ji)術雖然(ran)可以實(shi)現雙向通信,但仍然(ran)需要反復發出請求。而且在Comet中普遍采(cai)用的(de)也會消耗(hao)服務器資源(yuan)2。
Websocket通信模式
了解(jie)網絡的都知道,數(shu)據傳輸分(fen)為單(dan)工(gong)、半雙(shuang)(shuang)工(gong)、全雙(shuang)(shuang)工(gong)三種工(gong)作(zuo)模式。
Websocket是基于(yu)TCP的,使(shi)用全雙工通信模式的協(xie)議,他使(shi)得客戶端(duan)(duan)(duan)和服務(wu)端(duan)(duan)(duan)之(zhi)間的數據交換變(bian)得更簡單。而且,作(zuo)為一個工作(zuo)在(zai)全雙工模式下的協(xie)議,服務(wu)端(duan)(duan)(duan)可以(yi)在(zai)建立(li)連(lian)接后隨(sui)時向客戶端(duan)(duan)(duan)推送(song)消息。
由于協議是(shi)基(ji)于TCP的(de),所以websocket也是(shi)需要建連和(he)關閉(bi)連接的(de),但要注意的(de)是(shi),一般在(zai)websocket的(de)握(wo)手(shou)(shou)通常指的(de)是(shi):客戶端發(fa)送(song)一個http請(qing)求到服務(wu)端,服務(wu)端響(xiang)應后標志這個鏈(lian)接建立起來。而不是(shi)指tcp的(de)三次握(wo)手(shou)(shou)。
另外在(zai) 1.1節「Background」中介紹(shao):WebSocket通過HTTP端(duan)口的80和443進行工作,并支(zhi)持(chi)HTTP代理和中介。
原文:it is designed to work over HTTP ports 80 and 443 as well as to support HTTP proxies and intermediaries
為(wei)了(le)實現和HTTP的兼容性,WebSocket握手(shou)使用(yong)HTTP的Upgrade頭將HTTP協議轉換(huan)成Websocket協議。
作為一種協議,websocket自然也是有其用于協議控制的頭(tou)部信息的,但是相對(dui)于HTTP請求每(mei)次(ci)都要帶上完整的頭(tou)部信息,傳(chuan)輸(shu)數(shu)據時,websocket數(shu)據包的頭(tou)部信息就相對(dui)較小,從而降低了控(kong)制開銷。
相(xiang)對于前文所提(ti)到的輪詢接口,websocket可以(yi)做到服務(wu)端(duan)直接向客戶端(duan)傳輸數(shu)據,省去了(le)客戶端(duan)發起(qi)請求(qiu)的步驟(zou),同時(shi)沒(mei)有(you)間隔(ge)時(shi)間,只要服務(wu)端(duan)內容變化,就可以(yi)告(gao)知客戶端(duan),實時(shi)性上(shang)有(you)了(le)很大的提(ti)高(gao)。
Websocket 使用
WebSocket使用(yong)十分簡單,只(zhi)需要(yao)關注以下API:
WebSocket(url[, protocol])構造函數
使用 new WebSocket(xxx) 創建(jian)對(dui)象時(shi),會同時(shi)建(jian)立(li)與(yu)服務(wu)器的連(lian)接

WebSocket.onopen,WebSocket.onclose
分別(bie)對應連接(jie)成功、失敗時的(de)(de)回調,這里可以(yi)做一些初始化(hua)、銷毀的(de)(de)工作
WebSocket.onmessage
實(shi)際處理數(shu)據是用的該函(han)數(shu)
在數據處理完成后,需要移除回(hui)調(diao)函數,不然可能會影(ying)響到其他地方(fang)的處理
const ws = new WebSocket('ws://sdf.com');
function handleData(evt) {
// handle server data.
}
ws.onmessage = handleData;
ws.addEventListener('message', handleData);
WebSocket.send
主(zhu)動向服務端發(fa)送(song)消息,可以(yi)通過send和onmessage進行數據(ju)互動,如:
ws.send('list');
?
ws.onmessage = evt => {
const data = evt.data;
if (data === 'hello') {
console.log('world');
return ;
}
try {
const obj = JSON.parse(data);
switch (obj.type) {
case 'list':
// do something.
}
} catch (ex) {}
}
WebSocket.close
關閉連接
Node服(fu)務端的實現(xian),這個(ge)就參(can)考相關的庫(ku)吧(ba),比較復雜。
衍生知識
http協議至(zhi)今,主要(yao)經歷(li)了三個版本。
-
http1.0 短連接,單(dan)工通信
- http/1.0默認的模型是短連接,每個HTTP請求都由他自己獨立完成,下圖左1,可以看到每一個http請求都對應了一個建立連接關閉連接的階段,每一個請求都有TCP握手和揮手的階段。
- 在這個模型下,想要做到實時更新頁面數據,只能考慮輪詢。
-
http1.1 支持(chi)長鏈接,半(ban)雙工通信
- 1.0之后的版本,1.1會讓某個連接保持一定的時間,在這段時間里重復發送一系列請求(下圖左2),就是保活。
- http2.0 支持多路復用,全雙工通信

參考文獻
[1]
[2]
[3]
[4]
[5]
本文首發(fa)于,公眾號(hao)訂閱請關注:

