轉自:http://www.cnblogs.com/study-everyday/p/6140498.htmlhtml
一般狀況下,打開網頁或app去查詢或者刷新時,客戶端向服務器發出請求而後返回數據,客戶端與服務端對應的模式是: 客戶端請求--服務端響應, 而在有些狀況下,服務端會主動推送一些信息到客戶端,例如:新聞的訂閱,天氣的提醒等等,那麼在這樣的模式下,會有些問題值得思考:前端
1.應用服務器如何肯定每個應用所在的設備jquery
2.服務端把消息推到哪,客戶端又不像服務器有一個固定的地址git
服務端主動推送到客戶端是怎麼一個過程?github
結合一個實際問題分析下:web
問題提出: 外賣app, 商家在商家後臺須要實時的獲取到有沒有新訂單,有的話是幾個;這個需求相似與平常中使用QQ或者微信時的新信息提醒同樣,只要有新信息就須要提醒chrome
最近工做中遇到一個場景,商家在商家後臺須要實時的獲取到有沒有新訂單,有的話是幾個;這個需求相似與平常中使用QQ或者微信時的新信息提醒同樣,只要有新信息就須要提醒;商家基本在PC上使用,各式瀏覽器都有:如 IE系列(7.0,8.0,9.0及以上),chrome內核,firefox等;功能所屬的部署在Tomcat 6.0上,若是技術須要能夠部署到 Tomcat 7.0上;跨域
咱們先作作技術調研,這種瀏覽器與服務器實時通訊的方式有哪些方式。瀏覽器
這是咱們最天然想到的。 採用常規AJAX輪詢的方式,每10s或者30s輪詢一次,既能夠判斷出有有多少個新訂單進入,且這種時間間隔對於消息提醒也是能夠接受的。這種技術方式實現起來很是簡單,目前的機器都是能夠機器的,前端瀏覽器也都支持。服務器
可是這種方式會有很是嚴重的問題,就是須要不斷的向服務器發送消息詢問,若是有1w個商家打開了瀏覽器,採用10s輪詢的方式,則服務器則會承擔1000 的QPS,這1w個商家可能只有10個有訂單通知;這種方式會對服務器形成極大的性能浪費。
還有一個相似的輪詢是使用JSONP跨域請求的方式輪詢,在實現起來有差異,但基本原理都是相同的,都是客戶端不斷的向服務器發起請求。
優勢
實現簡單。
缺點
這是經過模擬服務器發起的通訊,不是實時通訊,不顧及應用的狀態改變而盲目檢查更新,致使服務器資源的浪費,且會加劇網絡負載,拖累服務器。
Comet是一種用於Web的推送技術,能使服務器實時地將更新的信息傳送到客戶端,而無須客戶端發出請求,目前有兩種實現方式:
長輪詢 (long polling) 是在打開一條鏈接之後保持,等待服務器推送來數據再關閉,能夠採用HTTP長輪詢和XHR長輪詢兩種方式。
把 script 標籤附加到頁面上以讓腳本執行。服務器會掛起鏈接直到有事件發生,接着把腳本內容發送回瀏覽器,而後從新打開另外一個 script 標籤來獲取下一個事件,從而實現長輪詢的模型。
這種方式是使用比較多的長輪詢模式。
客戶端打開一個到服務器端的 AJAX 請求而後等待響應;服務器端須要一些特定的功能來容許請求被掛起,只要一有事件發生,服務器端就會在掛起的請求中送回響應並關閉該請求。客戶端 JavaScript 響應處理函數會在處理完服務器返回的信息後,再次發出請求,從新創建鏈接;如此循環。
如今瀏覽器已經支持CROS的跨域方式請求,所以HTTP和JSONP的長輪詢方式是慢慢被淘汰的一種技術,建議採用XHR長輪詢。
優勢
客戶端很容易實現良好的錯誤處理系統和超時管理,實現成本與Ajax輪詢的方式相似。
缺點
須要服務器端有特殊的功能來臨時掛起鏈接。當客戶端發起的鏈接較多時,服務器端會長期保持多個鏈接,具備必定的風險。
iframe 是很早就存在的一種 HTML 標記, 經過在 HTML 頁面裏嵌入一個隱蔵幀,而後將這個隱蔵幀的 SRC 屬性設爲對一個長鏈接的請求,服務器端就能源源不斷地往客戶端輸入數據。
優勢:
這種方式每次數據傳送不會關閉鏈接,鏈接只會在通訊出現錯誤時,或是鏈接重建時關閉(一些防火牆常被設置爲丟棄過長的鏈接, 服務器端能夠設置一個超時時間, 超時後通知客戶端從新創建鏈接,並關閉原來的鏈接)。
缺點
IE、Morzilla Firefox 下端的進度欄都會顯示加載沒有完成,並且 IE 上方的圖標會不停的轉動,表示加載正在進行。
Google 的天才們使用一個稱爲「htmlfile」的 ActiveX 解決了在 IE 中的加載顯示問題,並將這種方法用到了 gmail+gtalk 產品中。Alex Russell 在 「What else is burried down in the depth’s of Google’s amazing JavaScript?」文章中介紹了這種方法。Zeitoun 網站提供的 comet-iframe.tar.gz,封裝了一個基於 iframe 和 htmlfile 的 JavaScript comet 對象,支持 IE、Mozilla Firefox 瀏覽器,能夠做爲參考。
咱們經常使用的網頁版的gtalk就是這種實現方式,Google的開發人員使使用一個稱爲「htmlfile」的 ActiveX 解決了在 IE 中的加載顯示問題。
CometD 框架是基於 HTTP 的事件驅動通訊解決方案,使用了Bayeux通訊協議,提供了一個 Java 服務器部件和一個 Java 客戶端部件,還有一個基於 jQuery 和 Dojo 的 JavaScript 客戶端庫。
Bayeux 通訊協議主要是基於 HTTP,提供了客戶端與服務器之間的響應性雙向異步通訊。Bayeux 協議基於通道進行通訊,經過該通道從客戶端到服務器、從服務器到客戶端或從客戶端到客戶端(可是是經過服務器)路由和發送消息。Bayeux 是一種 「發佈- 訂閱」 協議。
CometD 與三個傳輸協議綁定在一塊兒:JSON、JSONP 和 WebSocket。他們都依賴於 Jetty Continuations 和 Jetty WebSocket API。在默認狀況下,能夠在 Jetty 六、Jetty 七、和 Jetty 8 中以及其餘全部支持 Servlet 3.0 Specification 的服務中使用 CometD。
服務器和內部構件
Atmosphere提供了一個通用 API,以便使用許多 Web 服務器(包括 Tomcat、Jetty、GlassFish、Weblogic、Grizzly、JBossWeb、JBoss 和 Resin)的 Comet 和 WebSocket 特性。它支持任何支持 Servlet 3.0 Specification 的 Web 服務器。
Atmosphere 提供了一個 jQuery 客戶端庫,該庫可使鏈接設置變得更容易,它可以自動檢測可使用的最佳傳輸協議(WebSockets 或 CometD)。Atmosphere 的 jQuery 插件的用法與 HTML5 WebSockets API 類似。
Pushlet 使用了觀察者模型:客戶端發送請求,訂閱感興趣的事件;服務器端爲每一個客戶端分配一個會話 ID 做爲標記,事件源會把新產生的事件以多播的方式發送到訂閱者的事件隊列裏。
Pushlet 最後更新於2010年2月5號,以後至今沒有再更新。
Cometd 和Atmosphere框架參見示例代碼 (https://github.com/brucefengnju/cometdatoms)。
不要在同一客戶端同時使用超過兩個的 HTTP 長鏈接
HTTP 1.1 規範中規定,客戶端不該該與服務器端創建超過兩個的 HTTP 鏈接, 新的鏈接會被阻塞,在IE瀏覽器中嚴格遵照了這種規定。
服務器端的性能和可擴展性
通常 Web 服務器會爲每一個鏈接建立一個線程,若是在大型的商業應用中使用 Comet,服務器端須要維護大量併發的長鏈接。在這種應用背景下,服務器端須要考慮負載均衡和集羣技術;或是在服務器端爲長鏈接做一些改進。
在客戶和服務器之間保持「心跳」信息
在瀏覽器與服務器之間維持一個長鏈接會爲通訊帶來一些不肯定性:由於數據傳輸是隨機的,客戶端不知道什麼時候服務器纔有數據傳送。服務器端須要確保當客戶端再也不工做時,釋放爲這個客戶端分配的資源,防止內存泄漏。所以須要一種機制使雙方知道雙方都在正常運行。
服務器端在阻塞讀時會設置一個時限,超時後阻塞讀調用會返回,同時發給客戶端沒有新數據到達的心跳信息。此時若是客戶端已經關閉,服務器往通道寫數據會出現異常,服務器端就會及時釋放爲這個客戶端分配的資源。
若是客戶端使用的是基於 AJAX 的長輪詢方式;服務器端返回數據、關閉鏈接後,通過某個時限沒有收到客戶端的再次請求,會認爲客戶端不能正常工做,會釋放爲這個客戶端分配、維護的資源。
當服務器處理信息出現異常狀況,須要發送錯誤信息通知客戶端,同時釋放資源、關閉鏈接。
WebSocket是HTML5開始提供的一種在單個 TCP 鏈接上進行全雙工通信的協議。WebSocket通信協議於2011年被IETF定爲標準RFC 6455,WebSocketAPI被W3C定爲標準。在WebSocket API中,瀏覽器和服務器只須要作一個握手的動做,而後,瀏覽器和服務器之間就造成了一條快速通道。二者之間就直接能夠數據互相傳送。
瀏覽器 | 版本支持 |
---|---|
Chrome | 4+ |
Firefox | 4+ |
IE | 10+ |
Opera | 10+ |
Safari | 5+ |
詳情查看 Browser compatibility
WebSocket的實現已經有不少種版本,詳細能夠查看DEMO。
總結下來長輪詢不是一個很好的方案,並且對於服務器而言是有風險的;另外支持WebSocket協議的瀏覽器都比較新,特比是IE須要10以上的版本;而咱們的業務是面向於商家端,商家的瀏覽器版本相對較低,不少對WebSocket都不支持;相對而言Comet的方式比較適合,也有相應的實現框架,實現成本最低;所以最後咱們仍是決定使用Comet的方式來實現,後面上線運行一段時間以後再來給你們介紹。