開(kāi)放、平等、協(xié)作、快速、分享
WebSocket是HTML5新增的協(xié)議,它的目的是在瀏覽器和服務(wù)器之間建立一個(gè)不受限的雙向通信的通道,比如說(shuō),服務(wù)器可以在任意時(shí)刻發(fā)送消息給瀏覽器。
為什么傳統(tǒng)的HTTP協(xié)議不能做到WebSocket實(shí)現(xiàn)的功能?這是因?yàn)镠TTP協(xié)議是一個(gè)請(qǐng)求-響應(yīng)協(xié)議,請(qǐng)求必須先由瀏覽器發(fā)給服務(wù)器,服務(wù)器才能響應(yīng)這個(gè)請(qǐng)求,再把數(shù)據(jù)發(fā)送給瀏覽器。換句話說(shuō),瀏覽器不主動(dòng)請(qǐng)求,服務(wù)器是沒(méi)法主動(dòng)發(fā)數(shù)據(jù)給瀏覽器的。
這樣一來(lái),要在瀏覽器中搞一個(gè)實(shí)時(shí)聊天,在線炒股(不鼓勵(lì)),或者在線多人游戲的話就沒(méi)法實(shí)現(xiàn)了,只能借助Flash這些插件。
也有人說(shuō),HTTP協(xié)議其實(shí)也能實(shí)現(xiàn)啊,比如用輪詢或者Comet。輪詢是指瀏覽器通過(guò)JavaScript啟動(dòng)一個(gè)定時(shí)器,然后以固定的間隔給服務(wù)器發(fā)請(qǐng)求,詢問(wèn)服務(wù)器有沒(méi)有新消息。這個(gè)機(jī)制的缺點(diǎn)一是實(shí)時(shí)性不夠,二是頻繁的請(qǐng)求會(huì)給服務(wù)器帶來(lái)極大的壓力。
Comet本質(zhì)上也是輪詢,但是在沒(méi)有消息的情況下,服務(wù)器先拖一段時(shí)間,等到有消息了再回復(fù)。這個(gè)機(jī)制暫時(shí)地解決了實(shí)時(shí)性問(wèn)題,但是它帶來(lái)了新的問(wèn)題:以多線程模式運(yùn)行的服務(wù)器會(huì)讓大部分線程大部分時(shí)間都處于掛起狀態(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ù)表示連接“正常工作”。
以上兩種機(jī)制都治標(biāo)不治本,所以,HTML5推出了WebSocket標(biāo)準(zhǔn),讓瀏覽器和服務(wù)器之間可以建立無(wú)限制的全雙工通信,任何一方都可以主動(dòng)發(fā)消息給對(duì)方。
WebSocket并不是全新的協(xié)議,而是利用了HTTP協(xié)議來(lái)建立連接。我們來(lái)看看WebSocket連接是如何創(chuàng)建的。
首先,WebSocket連接必須由瀏覽器發(fā)起,因?yàn)檎?qǐng)求協(xié)議是一個(gè)標(biāo)準(zhǔn)的HTTP請(qǐng)求,格式如下:
GET ws://localhost:3000/ws/chat HTTP/1.1Host: localhost Upgrade: websocket Connection: Upgrade Origin: http://localhost:3000Sec-WebSocket-Key: client-random-string Sec-WebSocket-Version: 13
該請(qǐng)求和普通的HTTP請(qǐng)求有幾點(diǎn)不同:
GET請(qǐng)求的地址不是類似/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類似。首先,瀏覽器用wss://xxx
創(chuàng)建WebSocket連接時(shí),會(huì)先通過(guò)HTTPS創(chuàng)建安全的連接,然后,該HTTPS連接升級(jí)為WebSocket連接,底層通信走的仍然是安全的SSL/TLS協(xié)議。
很顯然,要支持WebSocket通信,瀏覽器得支持這個(gè)協(xié)議,這樣才能發(fā)出ws://xxx
的請(qǐng)求。目前,支持WebSocket的主流瀏覽器如下:
Chrome
Firefox
IE >= 10
Sarafi >= 6
Android >= 4.4
iOS >= 8
由于WebSocket是一個(gè)協(xié)議,服務(wù)器具體怎么實(shí)現(xiàn),取決于所用編程語(yǔ)言和框架本身。Node.js本身支持的協(xié)議包括TCP協(xié)議和HTTP協(xié)議,要支持WebSocket協(xié)議,需要對(duì)Node.js提供的HTTPServer做額外的開(kāi)發(fā)。已經(jīng)有若干基于Node.js的穩(wěn)定可靠的WebSocket實(shí)現(xiàn),我們直接用npm安裝使用即可。
上一篇:測(cè)試1
24小時(shí)免費(fèi)咨詢
請(qǐng)輸入您的聯(lián)系電話,座機(jī)請(qǐng)加區(qū)號(hào)