1 背景javascript
「服務器推送技術」(ServerPushing)是最近Web技術中最熱門的一個流行術語。它是繼「Ajax」以後又一個倍受追捧的Web技術。「服務器推送技術」最近的流行跟「Ajax 」有着密切的關係。java
隨着 Ajax技術的興起,讓廣大開發人員又一次看到了使用瀏覽器來替代桌面應用的機會,而且此次機會很是大。Ajax將整個頁面的刷新變成頁面局部的刷新,而且數據的傳送是以異步方式進行,這使得網絡延遲帶來的視覺差別將會消失。web
可是,在瀏覽器中的 Ajax應用中存在一個致命的缺陷沒法知足傳統桌面系統的需求。那就是「服務器發起的消息傳遞」(Server-Initiated Message Delivery)。在不少的應用當中,服務器軟件須要向客戶端主動發送消息或信息。由於服務器掌握着系統的主要資源,可以最早得到系統的狀態變化和事件的發生。當這些變化發生的時候,服務器須要主動的向客戶端實時的發送消息。例如股票的變化。在傳統的桌面系統這種需求沒有任何問題,由於客戶端和服務器之間一般存在着持久的鏈接,這個鏈接能夠雙向傳遞各類數據。而基於HTTP協議的 Web應用卻不行。算法
2 客戶端獲得通知的方式編程
咱們知道, Web的訪問機制天生是設計用來 pull數據的,也就是隻容許 Browser端主動發起請求,server是被動的響應,不容許Server向 Browser發出一個 connection請求,也就是說沒有爲server向 Browser push數據提供設計實現.雖然沒有直接的實現方法,卻可使用一些變通的方式完成相似的功能。瀏覽器
2.1 傳統輪詢服務器
在 Web早期,這一點常使用meta刷新實現。這將自動指示瀏覽器在指定秒數以後從新裝載頁面,從而支持簡陋的輪詢(polling)。例如在HTML文件中加入 <META HTTP-RQUIV="Refresh" CONTENT=12>,實際上就是 HTTP 頭標告知瀏覽器每 12 秒更新一次文檔。網絡
優勢 :不須要服務器端的配置。架構
缺點 :併發
a) 糟糕的用戶體驗
b) 對服務器的壓力很大,而且形成帶寬的極大浪費。
2.2 Ajax 輪詢
Ajax隔一段時間(一般使用JavaScript的setTimeout函數)就去服務器查詢是否有改變,從而進行增量式的更新。可是間隔多長時間去查詢成了問題,由於性能和即時性形成了嚴重的反比關係。間隔過短,接二連三的請求會沖垮服務器,間隔太長,務器上的新數據就須要越多的時間才能到達客戶機。
優勢:
a) 不須要太多服務器端的配置。
b) 下降帶寬的負荷(由於服務器返回的不是完整頁面)。
缺點:
a) 對服務器的壓力並不會有明顯的減小。
b) 實時性差,有必定的延遲。
應用: 這是一項很是常見的技術,例如,大多數 webmail應用程序就是經過這種技術在電子郵件到達時顯示電子郵件的。
2.3 Comet
Comet方式通俗的說就是一種長鏈接機制(long lived http)。一樣是由Browser端主動發起請求,可是Server端以一種彷佛很是慢的響應方式給出回答。這樣在這個期間內,服務器端可使用同一個connection把要更新的數據主動發送給Browser。所以請求可能等待較長的時間,期間沒有任何數據返回,可是一旦有了新的數據,它將當即被髮送到客戶機。Comet又有不少種實現方式,可是總的來講對Server端的負載都會有增長.雖然對於單位操做來講,每次只須要建議一次connection,可是因爲connection是保持較長時間的,對於 server端的資源的佔用要有所增長。
優勢: 實時性好(消息延時小);性能好(能支持大量用戶)
缺點: 長期佔用鏈接,喪失了無狀態高併發的特色。
應用: 股票系統、實時通信。
2.4 Flash XML Socket
這種方案實現的基礎是:1、Flash提供了 XMLSocket類。2、 JavaScript 和 Flash的緊密結合:在 JavaScript能夠直接調用 Flash程序提供的接口。
缺點:
a) 由於XMLSocket沒有HTTP隧道功能,XMLSocket類不能自動穿過防火牆;
b) 由於是使用套接口,須要設置一個通訊端口,防火牆、代理服務器也可能對非HTTP通道端口進行限制;
應用: 網絡聊天室,網絡互動遊戲。
2.5 Java Applet 套接口
在客戶端使用 Java Applet,經過 java.net.Socket或java.net.DatagramSocket或java.net.MulticastSocket 創建與服務器端的套接口鏈接,從而實現「服務器推送 」。
缺點: 須要客戶端安裝 JAVA虛擬機。
3 Comet 介紹
Comet 有時也稱反向 Ajax或服務器端推技術(server-side push)。其思想很簡單:將數據直接從服務器推到瀏覽器,而沒必要等到瀏覽器請求數據。聽起來簡單,可是若是熟悉Web 應用程序,尤爲是HTTP協議,那麼您就會知道,這毫不簡單。實現Comet風格的 Web應用程序,同時保證在瀏覽器和服務器上的可伸縮性,這只是在最近幾年才成爲可能。目前一些主流網站都有相似的原理,例如:webQQ、開心網、校內等等,它們中消息動態都是採用相似的技術,只是具體實現方式不同。
COMET的精髓就在於用服務器與javascript來維持瀏覽器的長鏈接,同時完成服務器端事件的瀏覽器端響應。這樣的事件廣播機制是跨網絡的,同時也是實時的。
採用了 Comet技術的服務器在客戶機作出一個請求後,和客戶機創建一個永久的鏈接,而後服務器會根據客戶機的請求不斷把數據包推向客戶,這個推的過程是不間斷的。由服務器推向客戶機的數據在客戶機的瀏覽器上會不斷產生新的內容,並且不會產生Client pull那樣的HTML文檔頭,從而大大減小了延遲的時間,向(服務器響應--客戶機請求)同步邁進了一步。
服務器推送一般效率要比客戶端拖曳效率高,由於它沒必要爲後續數據創建新的鏈接。因爲始終保持鏈接,即便沒有數據傳輸時也是這樣,所以服務器必須願意分配這些TCP/IP端口,對於TCP/IP端口數有限的服務器這將是一個嚴重的問題。
客戶端拖曳效率低,由於這必須每次爲傳送數據創建新的鏈接。可是它沒必要始終保持鏈接。在實際狀況中,創建HTTP鏈接一般須要花費至關多的時間,多達一秒甚至更多。所以從性能上考慮,服務器推送對於最終用戶更有吸引力,特別是對於須要常常更新信息的狀況下。
服務器推送相對客戶端拖曳的另外一點優點是,服務器推送相對比較容易控制。例如,服務器每一次推送時都保持一個鏈接,但它又隨時能夠關閉其中的任何鏈接,而不須要在服務器上設置特殊的算法。而客戶端拖曳在一樣的狀況下要麻煩許多,它每次要與服務器創建鏈接,服務器爲了處理將客戶端拖曳請求與特定的最終用戶匹配等狀況,須要使用至關麻煩的算法。
如上所述,在服務器推送中,多個響應中鏈接始終保持,使服務器可在任什麼時候間發送更多的數據。一個明顯的好處是服務器徹底可以控制更新數據的時間和頻率。另外,這種方法效率高,由於始終保持鏈接。缺點是保持鏈接狀態會浪費服務器端的資源。服務器推送還比較容易中斷。
4 Comet 實現(Java語言)
4.1 死循環法
最簡單的天然是死循環法,若是使用觀察者模式則能夠進一步提升性能。
可是這種作法的缺點在於客戶端請求了這個 servlet後, web 服務器會開啓一個線程執行 servlet 的代碼,而 servlet 由遲遲不願結束,形成該線程也沒法被釋放。因而乎,一個客戶端一個線程,當客戶端數量增長時,服務器依然會承受很大的負擔。
4.2 改寫web服務器
目前的趨勢是從 web 服務器內部入手,用 nio ( JDK 1.4 提出的 java.nio 包)改寫 request/response 的實現,再利用線程池加強服務器的資源利用率,從而解決這個問題,目前支持這一非 J2EE 官方技術的服務器有 Glassfish 和 Jetty 。
JDK 1.4 版本 ( 包括以後的版本 ) 最顯著的新特性就是增長了 NIO(New IO) ,可以以非阻塞的方式處理網絡的請求,這就使得在 Java 中只須要少許的線程就能處理大量的併發請求了。
Jetty 6設計來處理大量併發鏈接,它使用Java語言的不堵塞 I/O(java.nio)庫而且使用優化的輸出緩衝架構。Jetty也有一個處理長鏈接的殺手鐗:一個稱爲 Continuations的特性。
Grizzly 做爲 GlassFish 中很是重要的一個項目,就是用 NIO 的技術來實現應用服務器中的高性能純 Java 的 HTTP 引擎。 Grizzly 仍是一個獨立於 GlassFish 的框架結構,能夠單獨用來擴展和構建本身的服務器軟件。
特色: 使用 NIO 不是一件簡單的技術,它的一些特色使得編程的模型比原來阻塞的方式更爲複雜。
4.3 使用框架
基於 Java 的成熟的服務器推送框架有 DWR 。
DWR是一個開放源碼的使用Apache許可協議的解決方案,它包含服務器端Java庫、一個 DWR servlet以及 JavaScript庫。雖然 DWR不是 Java平臺上惟一可用的Ajax-RPC 工具包,可是它是最成熟的,並且提供了許多有用的功能。從最簡單的角度來講,DWR是一個引擎,能夠把服務器端Java對象的方法公開給JavaScript 代碼。使用DWR 能夠有效地從應用程序代碼中把Ajax的所有請求 -響應循環消除掉。這意味着客戶端代碼不再須要直接處理XMLHttpRequest對象或者服務器的響應。再也不須要編寫對象的序列化代碼或者使用第三方工具才能把對象變成XML。甚至再也不須要編寫servlet代碼把 Ajax請求調整成對 Java域對象的調用。
DWR 從 2.0開始增長了 push 功能 , 也就是在異步傳輸的狀況下能夠從 Web-Server 端發送數據到 Browser