我們知道http協(xié)議是:無(wú)狀態(tài)的,必須由客戶(hù)端發(fā)起請(qǐng)求,服務(wù)端才能被動(dòng)相應(yīng)。
問(wèn)題:我們需要做實(shí)時(shí)聊天,在線(xiàn)炒股等應(yīng)用,如何讓客戶(hù)端能實(shí)時(shí)取到服務(wù)端最新的數(shù)據(jù)?
1、輪詢(xún),客戶(hù)端設(shè)置一個(gè)定時(shí)器,以固定間隔給服務(wù)端發(fā)送ajax請(qǐng)求 來(lái) 請(qǐng)求數(shù)據(jù)。
????但是,頻繁的請(qǐng)求會(huì)給服務(wù)端帶來(lái)極大壓力。
2、Comet,本質(zhì)也是輪詢(xún),在沒(méi)有相應(yīng)數(shù)據(jù)時(shí),服務(wù)器會(huì)先拖一段時(shí)間,等有消息來(lái)再響應(yīng)請(qǐng)求。
????但是,以多線(xiàn)程模式運(yùn)行的服務(wù)器會(huì)讓大部分線(xiàn)程都出于掛起狀態(tài),極大浪費(fèi)服務(wù)端資源。另外,一個(gè)Http連接在長(zhǎng)時(shí)間沒(méi)有數(shù)據(jù)傳輸?shù)那闆r下,鏈路上任何一個(gè)網(wǎng)關(guān)都可能關(guān)閉這個(gè)連接,而網(wǎng)關(guān)是我們不可控的,這就要求Comet連接定期發(fā)一些ping數(shù)據(jù)表示“連接正常”。
結(jié)論:兩種方法都治標(biāo)不治本。
webSocket協(xié)議出現(xiàn)了
它是利用http協(xié)議來(lái)建立連接,對(duì)http協(xié)議進(jìn)行了改造。
來(lái)看一個(gè)webSocket請(qǐng)求的格式:
GET: ws://localhost:3000/ws/chat HTTP/1.1
Host: localhost
Upgrade: websocket
connect: Upgrade
Origin: http://localhost:3000
Sec-WebSocket-Key: client-random-string
Sec-WebSocket-Version: 13
該請(qǐng)求和普通HTTP請(qǐng)求有哪些不同:
- GET請(qǐng)求的地址不是類(lèi)似
/path/,而是以ws://開(kāi)頭。 - 請(qǐng)求頭
Upgrade: websocket和Connection: Upgrade表示這個(gè)連接將要被轉(zhuǎn)換為WebSocket連接。 -
Sec-WebSocket-Key是用于標(biāo)識(shí)這個(gè)連接,并非用于加密數(shù)據(jù)。 -
Sec-WebSocket-Version指定了WebSocket的協(xié)議版本。
隨后,服務(wù)器如果接受該請(qǐng)求,就會(huì)返回如下反應(yīng):
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: server-random-string
該響應(yīng)代碼101表示本次連接的HTTP協(xié)議即將被更改,更改后的協(xié)議就是Upgrade: websocket指定的WebSocket協(xié)議。
版本號(hào)和子協(xié)議規(guī)定了雙方能理解的數(shù)據(jù)格式,以及是否支持壓縮等等。如果僅使用WebSocket的API,就不需要關(guān)心這些。
現(xiàn)在,一個(gè)WebSocket連接就建立成功,瀏覽器和服務(wù)器就可以隨時(shí)主動(dòng)發(fā)送消息給對(duì)方。消息有兩種,一種是文本,一種是二進(jìn)制數(shù)據(jù)。通常,我們可以發(fā)送JSON格式的文本,這樣,在瀏覽器處理起來(lái)就十分容易。
為什么WebSocket連接可以實(shí)現(xiàn)全雙工通信而HTTP連接不行呢?實(shí)際上HTTP協(xié)議是建立在TCP協(xié)議之上的,TCP協(xié)議本身就實(shí)現(xiàn)了全雙工通信,但是HTTP協(xié)議的請(qǐng)求-應(yīng)答機(jī)制限制了全雙工通信。WebSocket連接建立以后,其實(shí)只是簡(jiǎn)單規(guī)定了一下:接下來(lái),咱們通信就不使用HTTP協(xié)議了,直接互相發(fā)數(shù)據(jù)吧。
安全的WebSocket連接機(jī)制和HTTPS類(lèi)似。首先,瀏覽器用wss://xxx創(chuàng)建WebSocket連接時(shí),會(huì)先通過(guò)HTTPS創(chuàng)建安全的連接,然后,該HTTPS連接升級(jí)為WebSocket連接,底層通信走的仍然是安全的SSL/TLS協(xié)議。
瀏覽器兼容
Chrome
Firefox
IE >=10
Sarafi >=6
Android >=4.4
IOS >= 8
服務(wù)器
由于Webpack是一個(gè)協(xié)議,服務(wù)器具體怎么實(shí)現(xiàn),取決于所用編程語(yǔ)言和框架本身。Node.js本身支持的協(xié)議包括TCP和HTTP協(xié)議,要支持WebSocket協(xié)議,需要對(duì)Node.js提供的HTTPServer做額外的開(kāi)發(fā)。已經(jīng)有若干基于Node.js的穩(wěn)定可靠的WebSocket實(shí)現(xiàn),我們直接用npm安裝即可。