WebSocket解說以及協(xié)議
[重要通告]如您遇疑難雜癥,本站支持知識付費(fèi)業(yè)務(wù),掃右邊二維碼加博主微信,可節(jié)省您寶貴時(shí)間哦!
WebSocket是HTML5新增的協(xié)議,它的目的是在瀏覽器和服務(wù)器之間建立一個(gè)不受限的雙向通信的通道,比如說,服務(wù)器可以在任意時(shí)刻發(fā)送消息給瀏覽器。
為什么傳統(tǒng)的HTTP協(xié)議不能做到WebSocket實(shí)現(xiàn)的功能?這是因?yàn)镠TTP協(xié)議是一個(gè)請求-響應(yīng)協(xié)議,請求必須先由瀏覽器發(fā)給服務(wù)器,服務(wù)器才能響應(yīng)這個(gè)請求,再把數(shù)據(jù)發(fā)送給瀏覽器。換句話說,瀏覽器不主動請求,服務(wù)器是沒法主動發(fā)數(shù)據(jù)給瀏覽器的。
這樣一來,要在瀏覽器中搞一個(gè)實(shí)時(shí)聊天,在線炒股(不鼓勵),或者在線多人游戲的話就沒法實(shí)現(xiàn)了,只能借助Flash這些插件。
也有人說,HTTP協(xié)議其實(shí)也能實(shí)現(xiàn)啊,比如用輪詢或者Comet。輪詢是指瀏覽器通過JavaScript啟動一個(gè)定時(shí)器,然后以固定的間隔給服務(wù)器發(fā)請求,詢問服務(wù)器有沒有新消息。這個(gè)機(jī)制的缺點(diǎn)一是實(shí)時(shí)性不夠,二是頻繁的請求會給服務(wù)器帶來極大的壓力。
Comet本質(zhì)上也是輪詢,但是在沒有消息的情況下,服務(wù)器先拖一段時(shí)間,等到有消息了再回復(fù)。這個(gè)機(jī)制暫時(shí)地解決了實(shí)時(shí)性問題,但是它帶來了新的問題:以多線程模式運(yùn)行的服務(wù)器會讓大部分線程大部分時(shí)間都處于掛起狀態(tài),極大地浪費(fèi)服務(wù)器資源。另外,一個(gè)HTTP連接在長時(shí)間沒有數(shù)據(jù)傳輸?shù)那闆r下,鏈路上的任何一個(gè)網(wǎng)關(guān)都可能關(guān)閉這個(gè)連接,而網(wǎng)關(guān)是我們不可控的,這就要求Comet連接必須定期發(fā)一些ping數(shù)據(jù)表示連接“正常工作”。
以上兩種機(jī)制都治標(biāo)不治本,所以,HTML5推出了WebSocket標(biāo)準(zhǔn),讓瀏覽器和服務(wù)器之間可以建立無限制的全雙工通信,任何一方都可以主動發(fā)消息給對方。
WebSocket協(xié)議
WebSocket并不是全新的協(xié)議,而是利用了HTTP協(xié)議來建立連接。我們來看看WebSocket連接是如何創(chuàng)建的。
首先,WebSocket連接必須由瀏覽器發(fā)起,因?yàn)檎埱髤f(xié)議是一個(gè)標(biāo)準(zhǔn)的HTTP請求,格式如下:
GET ws://localhost:3000/ws/chat HTTP/1.1
Host: localhost
Upgrade: websocket
Connection: Upgrade
Origin: http://localhost:3000
Sec-WebSocket-Key: client-random-string
Sec-WebSocket-Version: 13
該請求和普通的HTTP請求有幾點(diǎn)不同:
- GET請求的地址不是類似
/path/
,而是以ws://
開頭的地址; - 請求頭
Upgrade: websocket
和Connection: Upgrade
表示這個(gè)連接將要被轉(zhuǎn)換為WebSocket連接; Sec-WebSocket-Key
是用于標(biāo)識這個(gè)連接,并非用于加密數(shù)據(jù);Sec-WebSocket-Version
指定了WebSocket的協(xié)議版本。
隨后,服務(wù)器如果接受該請求,就會返回如下響應(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é)議。
版本號和子協(xié)議規(guī)定了雙方能理解的數(shù)據(jù)格式,以及是否支持壓縮等等。如果僅使用WebSocket的API,就不需要關(guān)心這些。
現(xiàn)在,一個(gè)WebSocket連接就建立成功,瀏覽器和服務(wù)器就可以隨時(shí)主動發(fā)送消息給對方。消息有兩種,一種是文本,一種是二進(jìn)制數(shù)據(jù)。通常,我們可以發(fā)送JSON格式的文本,這樣,在瀏覽器處理起來就十分容易。
為什么WebSocket連接可以實(shí)現(xiàn)全雙工通信而HTTP連接不行呢?實(shí)際上HTTP協(xié)議是建立在TCP協(xié)議之上的,TCP協(xié)議本身就實(shí)現(xiàn)了全雙工通信,但是HTTP協(xié)議的請求-應(yīng)答機(jī)制限制了全雙工通信。WebSocket連接建立以后,其實(shí)只是簡單規(guī)定了一下:接下來,咱們通信就不使用HTTP協(xié)議了,直接互相發(fā)數(shù)據(jù)吧。
安全的WebSocket連接機(jī)制和HTTPS類似。首先,瀏覽器用wss://xxx
創(chuàng)建WebSocket連接時(shí),會先通過HTTPS創(chuàng)建安全的連接,然后,該HTTPS連接升級為WebSocket連接,底層通信走的仍然是安全的SSL/TLS協(xié)議。
瀏覽器
很顯然,要支持WebSocket通信,瀏覽器得支持這個(gè)協(xié)議,這樣才能發(fā)出ws://xxx
的請求。目前,支持WebSocket的主流瀏覽器如下:
- Chrome
- Firefox
- IE >= 10
- Sarafi >= 6
- Android >= 4.4
- iOS >= 8
服務(wù)器
由于WebSocket是一個(gè)協(xié)議,服務(wù)器具體怎么實(shí)現(xiàn),取決于所用編程語言和框架本身。Node.js本身支持的協(xié)議包括TCP協(xié)議和HTTP協(xié)議,要支持WebSocket協(xié)議,需要對Node.js提供的HTTPServer做額外的開發(fā)。已經(jīng)有若干基于Node.js的穩(wěn)定可靠的WebSocket實(shí)現(xiàn),我們直接用npm安裝使用即可。
問題未解決?付費(fèi)解決問題加Q或微信 2589053300 (即Q號又微信號)右上方掃一掃可加博主微信
所寫所說,是心之所感,思之所悟,行之所得;文當(dāng)無敷衍,落筆求簡潔。 以所舍,求所獲;有所依,方所成!