Web應用從服務器主動推送數據到客戶端的方式


通常情況下,打開網頁或app去查詢或者刷新時,客戶端向服務器發出請求然後返回數據,客戶端與服務端對應的模式是: 客戶端請求–服務端響應, 而在有些情況下,服務端會主動推送一些信息到客戶端,例如:新聞的訂閱,天氣的提醒等等,那麼在這樣的模式下,會有些問題值得思考:

1.應用服務器如何確定每一個應用所在的設備

2.服務端把消息推到哪,客戶端又不像服務器有一個固定的地址

服務端主動推送到客戶端是怎麼一個過程?

結合一個實際問題分析下:

問題提出:
外賣app, 商家在商家後臺需要實時的獲取到有沒有新訂單,有的話是幾個;這個需求類似與日常中使用QQ或者微信時的新信息提醒一樣,只要有新信息就需要提醒

最近工作中遇到一個場景,商家在商家後臺需要實時的獲取到有沒有新訂單,有的話是幾個;這個需求類似與日常中使用QQ或者微信時的新信息提醒一樣,只要有新信息就需要提醒;商家基本在PC上使用,各式瀏覽器都有:如 IE系列(7.0,8.0,9.0及以上),chrome內核,firefox等;功能所屬的部署在Tomcat 6.0上,如果技術需要可以部署到 Tomcat 7.0上;

我們先做做技術調研,這種瀏覽器與服務器實時通信的方式有哪些方式。

1. AJAX輪詢

這是我們最自然想到的。 採用常規AJAX輪詢的方式,每10s或者30s輪詢一次,既可以判斷出有有多少個新訂單進入,且這種時間間隔對於消息提醒也是可以接受的。這種技術方式實現起來非常簡單,目前的機器都是可以機器的,前端瀏覽器也都支持。

但是這種方式會有非常嚴重的問題,就是需要不斷的向服務器發送消息詢問,如果有1w個商家打開了瀏覽器,採用10s輪詢的方式,則服務器則會承擔1000 的QPS,這1w個商家可能只有10個有訂單通知;這種方式會對服務器造成極大的性能浪費。

還有一個類似的輪詢是使用JSONP跨域請求的方式輪詢,在實現起來有差別,但基本原理都是相同的,都是客戶端不斷的向服務器發起請求。

優點

實現簡單。

缺點

這是通過模擬服務器發起的通信,不是實時通信,不顧及應用的狀態改變而盲目檢查更新,導致服務器資源的浪費,且會加重網絡負載,拖累服務器。

2. iframe

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 中的加載顯示問題。

3. comet

Comet是一種用於Web的推送技術,能使服務器實時地將更新的信息傳送到客戶端,而無須客戶端發出請求,目前有兩種實現方式:

長輪詢(long polling)

長輪詢 (long polling) 是在打開一條連接以後保持,等待服務器推送來數據再關閉,可以採用HTTP長輪詢XHR長輪詢兩種方式。

HTTP 和JSONP方式的長輪詢
把 script 標籤附加到頁面上以讓腳本執行。服務器會掛起連接直到有事件發生,接着把腳本內容發送回瀏覽器,然後重新打開另一個 script 標籤來獲取下一個事件,從而實現長輪詢的模型。

XHR長輪詢

這種方式是使用比較多的長輪詢模式。

客戶端打開一個到服務器端的 AJAX 請求然後等待響應;服務器端需要一些特定的功能來允許請求被掛起,只要一有事件發生,服務器端就會在掛起的請求中送回響應並關閉該請求。客戶端 JavaScript 響應處理函數會在處理完服務器返回的信息後,再次發出請求,重新建立連接;如此循環。

現在瀏覽器已經支持CROS的跨域方式請求,因此HTTP和JSONP的長輪詢方式是慢慢被淘汰的一種技術,建議採用XHR長輪詢。

長輪詢優缺點:
優點
客戶端很容易實現良好的錯誤處理系統和超時管理,實現成本與Ajax輪詢的方式類似。
缺點
需要服務器端有特殊的功能來臨時掛起連接。當客戶端發起的連接較多時,服務器端會長期保持多個連接,具有一定的風險。

Comet實現框架

CometD

CometD 框架是基於 HTTP 的事件驅動通信解決方案,使用了Bayeux通信協議,提供了一個 Java 服務器部件和一個 Java 客戶端部件,還有一個基於 jQuery 和 Dojo 的 JavaScript 客戶端庫。

Bayeux 通信協議主要是基於 HTTP,提供了客戶端與服務器之間的響應性雙向異步通信。Bayeux 協議基於通道進行通信,通過該通道從客戶端到服務器、從服務器到客戶端或從客戶端到客戶端(但是是通過服務器)路由和發送消息。Bayeux 是一種 “發佈- 訂閱” 協議。

CometD 與三個傳輸協議綁定在一起:JSON、JSONP 和 WebSocket。他們都依賴於 Jetty Continuations 和 Jetty WebSocket API。在默認情況下,可以在 Jetty 6、Jetty 7、和 Jetty 8 中以及其他所有支持 Servlet 3.0 Specification 的服務中使用 CometD。

服務器和內部構件

Atmosphere框架

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

Pushlet 使用了觀察者模型:客戶端發送請求,訂閱感興趣的事件;服務器端爲每個客戶端分配一個會話 ID 作爲標記,事件源會把新產生的事件以多播的方式發送到訂閱者的事件隊列裏。

Pushlet 最後更新於2010年2月5號,之後至今沒有再更新。

Cometd 和Atmosphere框架參見示例代碼 (https://github.com/brucefengnju/cometdatoms)。

Comet實現要點

不要在同一客戶端同時使用超過兩個的 HTTP 長連接

HTTP 1.1 規範中規定,客戶端不應該與服務器端建立超過兩個的 HTTP 連接, 新的連接會被阻塞,在IE瀏覽器中嚴格遵守了這種規定。

服務器端的性能和可擴展性

一般 Web 服務器會爲每個連接創建一個線程,如果在大型的商業應用中使用 Comet,服務器端需要維護大量併發的長連接。在這種應用背景下,服務器端需要考慮負載均衡和集羣技術;或是在服務器端爲長連接作一些改進。

在客戶和服務器之間保持“心跳”信息

在瀏覽器與服務器之間維持一個長連接會爲通信帶來一些不確定性:因爲數據傳輸是隨機的,客戶端不知道何時服務器纔有數據傳送。服務器端需要確保當客戶端不再工作時,釋放爲這個客戶端分配的資源,防止內存泄漏。因此需要一種機制使雙方知道雙方都在正常運行。

服務器端在阻塞讀時會設置一個時限,超時後阻塞讀調用會返回,同時發給客戶端沒有新數據到達的心跳信息。此時如果客戶端已經關閉,服務器往通道寫數據會出現異常,服務器端就會及時釋放爲這個客戶端分配的資源。

如果客戶端使用的是基於 AJAX 的長輪詢方式;服務器端返回數據、關閉連接後,經過某個時限沒有收到客戶端的再次請求,會認爲客戶端不能正常工作,會釋放爲這個客戶端分配、維護的資源。

當服務器處理信息出現異常情況,需要發送錯誤信息通知客戶端,同時釋放資源、關閉連接。

4. websocket

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的方式來實現,後面上線運行一段時間之後再來給大家介紹。

轉載於 : https://blog.csdn.net/shuo1992/article/details/59477055

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章