Web端即時通信技術因受限於瀏覽器的設計限制,一直以來實現起來並不容易,主流的Web端即時通信方案大體有4種:傳統Ajax短輪詢、Comet技術、WebSocket技術、SSE(Server-sent Events)。本文將簡要介紹這4種技術的原理,並指出各自的異同點、優缺點等。javascript
1996年IETF HTTP工做組發佈了HTTP協議的1.0版本 ,到如今廣泛使用的版本1.1,HTTP協議經歷了17 年的發展。這種分佈式、無狀態、基於TCP的請求/響應式、在互聯網盛行的今天獲得普遍應用的協議,相對於互聯網的迅猛發展,它彷佛進步地很慢。互聯網從興起到如今,經歷了門戶網站盛行的web1.0時代,然後隨着ajax技術的出現,發展爲web應用盛行的web2.0時代,現在又朝着web3.0的方向邁進。反觀http協議,從版本1.0發展到1.1,除了默認長鏈接以外就是緩存處理、帶寬優化和安全性等方面的不痛不癢的改進。它一直保留着無狀態、請求/響應模式,彷佛曆來沒意識到這應該有所改變。
好在HTML5的時代已經到來,爲Web端即時通信的實現帶來了WebSocket和SSE(Server-sent Events)兩種技術方案。php
傳統的web應用要想與服務器交互,必須提交一個表單(form),服務器接收並處理傳來的表單,而後返回全新的頁面,由於先後兩個頁面的數據大部分都是相同的,這個過程傳輸了不少冗餘的數據、浪費了帶寬。因而Ajax技術便應運而生。
Ajax是Asynchronous JavaScript and XML的簡稱,由Jesse James Garrett 首先提出。這種技術開創性地容許瀏覽器腳本(JS)發送http請求。Outlook Web Access小組於98年使用,並很快成爲IE4.0的一部分,可是這個技術一直很小衆,直到2005年初,google在他的goole groups、gmail等交互式應用中普遍使用此種技術,才使得Ajax迅速被你們所接受。
Ajax的出現使客戶端與服務器端傳輸數據少了不少,也快了不少,也知足了以豐富用戶體驗爲特色的web2.0時代 初期發展的須要,可是慢慢地也暴露了他的弊端。好比沒法知足即時通訊等富交互式應用的實時更新數據的要求。這種瀏覽器端的小技術畢竟仍是基於http協議,http協議要求的請求/響應的模式也是沒法改變的,除非http協議自己有所改變。html
以即時通訊爲表明的web應用程序對數據的Low Latency要求,傳統的基於輪詢的方式已經沒法知足,並且也會帶來很差的用戶體驗。因而一種基於http長鏈接的「服務器推」技術便被hack出來。這種技術被命名爲Comet,這個術語由Dojo Toolkit 的項目主管Alex Russell在博文Comet: Low Latency Data for the Browser首次提出,並沿用下來。
其實,服務器推很早就存在了,在經典的client/server模型中有普遍使用,只是瀏覽器太懶了,並無對這種技術提供很好的支持。可是Ajax的出現使這種技術在瀏覽器上實現成爲可能, google的gmail和gtalk的整合首先使用了這種技術。隨着一些關鍵問題的解決(好比 IE 的加載顯示問題),很快這種技術獲得了承認,目前已經有不少成熟的開源Comet框架。
如下是典型的Ajax和Comet數據傳輸方式的對比,區別簡單明瞭。典型的Ajax通訊方式也是http協議的經典使用方式,要想取得數據,必須首先發送請求。在Low Latency要求比較高的web應用中,只能增長服務器請求的頻率。Comet則不一樣,客戶端與服務器端保持一個長鏈接,只有客戶端須要的數據更新時,服務器才主動將數據推送給客戶端。
Comet的實現主要有兩種方式,基於Ajax的長輪詢(long-polling)方式和基於 Iframe 及 htmlfile 的流(http streaming)方式。
有關Comet技術的詳細介紹文章請參見:《Comet技術詳解:基於HTTP長鏈接的Web端實時通訊技術》、《WEB端即時通信:HTTP長鏈接、長輪詢(long polling)詳解》、《WEB端即時通信:不用WebSocket也同樣能搞定消息的即時性》、《開源Comet服務器iComet:支持百萬併發的Web端即時通信方案》。
html5
瀏覽器發出XMLHttpRequest 請求,服務器端接收到請求後,會阻塞請求直到有數據或者超時才返回,瀏覽器JS在處理請求返回信息(超時或有效數據)後再次發出請求,從新創建鏈接。在此期間服務器端可能已經有新的數據到達,服務器會選擇把數據保存,直到從新創建鏈接,瀏覽器會把全部數據一次性取回。
java
Iframe是html標記,這個標記的src屬性會保持對指定服務器的長鏈接請求,服務器端則能夠不停地返回數據,相對於第一種方式,這種方式跟傳統的服務器推則更接近。
在第一種方式中,瀏覽器在收到數據後會直接調用JS回調函數,可是這種方式該如何響應數據呢?能夠經過在返回數據中嵌入JS腳本的方式,如「<script type="text/javascript">js_func(「data from server 」)</script>」,服務器端將返回的數據做爲回調函數的參數,瀏覽器在收到數據後就會執行這段JS腳本。
可是這種方式有一個明顯的不足之處:IE、Morzilla Firefox 下端的進度欄都會顯示加載沒有完成,並且 IE 上方的圖標會不停的轉動,表示加載正在進行。Google 的天才們使用一個稱爲「htmlfile」的 ActiveX 解決了在 IE 中的加載顯示問題,並將這種方法應用到了 gmail+gtalk 產品中。web
若是說Ajax的出現是互聯網發展的必然,那麼Comet技術的出現則更多透露出一種無奈,僅僅做爲一種hack技術,由於沒有更好的解決方案。Comet解決的問題應該由誰來解決纔是合理的呢?瀏覽器,html標準,仍是http標準?主角應該是誰呢?本質上講,這涉及到數據傳輸方式,http協議應首當其衝,是時候改變一下這個懶惰的協議的請求/響應模式了。
W3C給出了答案,在新一代html標準html5中提供了一種瀏覽器和服務器間進行全雙工通信的網絡技術Websocket。從Websocket草案得知,Websocket是一個全新的、獨立的協議,基於TCP協議,與http協議兼容、卻不會融入http協議,僅僅做爲html5的一部分。因而乎腳本又被賦予了另外一種能力:發起websocket請求。這種方式咱們應該很熟悉,由於Ajax就是這麼作的,所不一樣的是,Ajax發起的是http請求而已。
與http協議不一樣的請求/響應模式不一樣,Websocket在創建鏈接以前有一個Handshake(Opening Handshake)過程,在關閉鏈接前也有一個Handshake(Closing Handshake)過程,創建鏈接以後,雙方便可雙向通訊。
有關WebSocket的詳細介,請參見即時通信網有關WebSocket的系列文章:《WebSocket詳解(一):初步認識WebSocket技術》、《WebSocket詳解(二):技術原理、代碼演示和應用案例》、《WebSocket詳解(三):深刻WebSocket通訊協議細節》。
從瀏覽器支持角度來看,WebSocket已經近在眼前,但仍有一段較長的路要走,特別是在中國這個IE六、七、8依然盛行的國家,舊版本瀏覽器的消亡須要很長一段時間,在徹底實現瀏覽器全兼容前,Comet技術可能仍然是最好的解決方案。不過,當前也已存在一些比較成熟的封裝方案來解決這種兼容性限制,好比:開源的Socket.io,詳見《Socket.IO介紹:支持WebSocket、用於WEB端的即時通信的框架》。ajax
SSE(Server-Sent Event,服務端推送事件)是一種容許服務端向客戶端推送新數據的HTML5技術。與由客戶端每隔幾秒從服務端輪詢拉取新數據相比,這是一種更優的解決方案。
與WebSocket相比,它也能從服務端向客戶端推送數據。那如何決定你是用SSE仍是WebSocket呢?歸納來講,WebSocket能作的,SSE也能作,反之亦然,但在完成某些任務方面,它們各有千秋。
WebSocket是一種更爲複雜的服務端實現技術,但它是真正的雙向傳輸技術,既能從服務端向客戶端推送數據,也能從客戶端向服務端推送數據。
WebSocket和SSE的瀏覽器支持率差很少,大多數主流桌面瀏覽器二者都支持。在Android 4.3以及更早的版本中,系統默認瀏覽器二者都不支持,Firefox和Chrome則徹底支持;Android 4.4中,系統默認瀏覽器二者都支持;Safari從5.0開始支持SSE(iOS系統從4.0開始),但直到6.0才正確地支持WebSocket(6.0以前的Safari所實現的WebSocket協議存在安全問題,因此一些主流瀏覽器已經禁用了基於這個協議的實現)。
與WebSocket相比,SSE有一些顯著的優點。我的認爲它最大的優點就是便利:不須要添加任何新組件,用任何你習慣的後端語言和框架就能繼續使用。你不用爲新建虛擬機、弄一個新的IP或新的端口號而勞神,就像在現有網站中新增一個頁面那樣簡單。我喜歡把這稱爲既存基礎設施優點。
SSE的第二個優點是服務端的簡潔。相對而言,WebSocket則很複雜,不借助輔助類庫基本搞不定(我試過,使人痛苦)。
由於SSE能在現有的HTTP/HTTPS協議上運做,因此它能直接運行於現有的代理服務器和認證技術。而對WebSocket而言,代理服務器須要作一些開發(或其餘工做)才能支持,在寫這本書時,不少服務器尚未(雖然這種情況會改善)。SSE還有一個優點:它是一種文本協議,腳本調試很是容易。事實上,在本書中,咱們會在開發和測試時用curl,甚至直接在命令行中運行後端腳本。
不過,這就引出了WebSocket相較SSE的一個潛在優點:WebSocket是二進制協議,而SSE是文本協議(一般使用UTF-8編碼)。固然,咱們能夠經過SSE鏈接傳輸二進制數據:在SSE中,只有兩個具備特殊意義的字符,它們是CR和LF,而對它們進行轉碼並不難。但用SSE傳輸二進制數據時數據會變大,若是須要從服務端到客戶端傳輸大量的二進制數據,最好仍是用WebSocket。
WebSocket相較SSE最大的優點在於它是雙向交流的,這意味向服務端發送數據就像從服務端接收數據同樣簡單。用SSE時,通常經過一個獨立的Ajax請求從客戶端向服務端傳送數據。相對於WebSocket,這樣使用Ajax會增長開銷,但也就多一點點而已。如此一來,問題就變成了「何時須要關心這個差別?」若是須要以1次/秒或者更快的頻率向服務端傳輸數據,那應該用WebSocket。0.2次/秒到1次/秒的頻率是一個灰色地帶,用WebSocket和用SSE差異不大;但若是你指望重負載,那就有必要肯定基準點。頻率低於0.2次/秒左右時,二者差異不大。
從服務端向客戶端傳輸數據的性能如何?若是是文本數據而非二進制數據(如前文所提到的),SSE和WebSocket沒什麼區別。它們都用TCP/IP套接字,都是輕量級協議。延遲、帶寬、服務器負載等都沒有區別,除非……呃?除非什麼?
當你在享用SSE的既存基礎設施優點,並在客戶端和服務端腳本之間設了一個網絡服務器,區別就顯現出來了。一個SSE鏈接不只使用一個套接字,還會佔用一個Apache線程或進程,若是用PHP,它會爲這個鏈接專門建立一個PHP新實例。Apache和PHP會使用大量的內存,這會限制服務器所能支持的並行鏈接數。因此,要作到用SSE在數據傳輸性能上和WebSocket徹底同樣,須要寫一個本身的後端服務器,固然,那些在任何狀況下都會用本身的服務器並使用Node.js的人,會以爲這有什麼稀奇的。
說一下WebSocket在舊版本瀏覽器上的兼容。當前,大約超過2/3的瀏覽器支持這些新技術,移動端瀏覽器的支持率會低一些。依慣例,每當須要雙向套接字時,就會用到Flash,而且WebSocket的向後兼容一般是用Flash來作,這已經至關複雜了,若是瀏覽器上沒有Flash,狀況更糟。歸納來講,WebSocket難兼容,SSE易兼容。有關SSE的專項介紹文章請參見:《SSE技術詳解:一種全新的HTML5服務器推送事件技術》。後端
(本文同步發佈於:http://www.52im.net/thread-336-1-1.html)瀏覽器
- 更多即時通信技術資料:http://www.52im.net/forum.php?mod=collection&op=all緩存
- 即時通信開發交流羣:215891622 [推薦]
Web端即時通信新手入門貼:
《新手入門貼:詳解Web端即時通信技術的原理》
關於Ajax短輪詢:
找這方面的資料沒什麼意義,除非忽悠客戶,不然請考慮其它3種方案便可。
有關Comet技術的詳細介紹請參見:
《Comet技術詳解:基於HTTP長鏈接的Web端實時通訊技術》
《WEB端即時通信:HTTP長鏈接、長輪詢(long polling)詳解》
《WEB端即時通信:不用WebSocket也同樣能搞定消息的即時性》
《開源Comet服務器iComet:支持百萬併發的Web端即時通信方案》
有關WebSocket的詳細介紹請參見:
《WebSocket詳解(一):初步認識WebSocket技術》
《WebSocket詳解(二):技術原理、代碼演示和應用案例》
《WebSocket詳解(三):深刻WebSocket通訊協議細節》
《Socket.IO介紹:支持WebSocket、用於WEB端的即時通信的框架》
《socket.io和websocket 之間是什麼關係?有什麼區別?》
有關SSE的詳細介紹文章請參見:
《SSE技術詳解:一種全新的HTML5服務器推送事件技術》
更多WEB端即時通信文章請見:
http://www.52im.net/forum.php?mod=collection&action=view&ctid=15