PHP ServerPush (推送) 技術的探討
需求:
我想做個會員站內通知的功能。不想用以前的ajax查詢,聽說有個推技術。以下文章介紹的不錯,來自轉載,
==================================================================================
PHP中Push(推送)技術的探討? [http://vistaswx.com/blog/article/php-server-push]
?
隨著人們對Web即時應用需求的不斷上升,Server Push(推送)技術在聊天、訊息提醒尤其是社交網路等方面開始興起,成為即時應用的資料流核心。這篇日誌試圖探討的便是各種適合於PHP的Push的實現方式以及其優劣。
1. 什麼是Server Push
想象在聊天應用中,如果使用傳統的ajax來承擔訊息的傳入,那麼一般是通過每隔一定時間拉取一次資訊的方式實現,但是其實這種方式有大量查詢是浪費的。聊天等Web應用更需要伺服器在特定時間來主動告知前端有新的訊息(Push),而不是前端每時每刻問伺服器:“來訊息了嗎?”(Pull)。這也正是為什麼這個技術常被叫做反向ajax。
其他別名:Comet,反向Ajax
?
2. 如何?Push
其實所謂的推送技術也沒有多麼複雜,目前從大類上有3種,一種仍然建立在ajax基礎上,還有一種建立在架構基礎上,最後一種拋棄了傳統的HTTP協議,使用Flash或者HTML5的WebSockets技術。接下來將對這三種類別產生的不同的方式進行探討。
1) Ajax 長輪詢
Ajax長輪詢從本質上來說仍然是一種pull,但是即時性較高,無用請求減少很多,是一種不錯的Push實現方案。不過它只減少了網路上的無謂消耗。
核心:?用戶端發起一個ajax請求,服務端將請求擱置(pending)或者說掛起,直到到了逾時時間(timeout)或需要推送時返回;用戶端則等待ajax返回後處理資料,再發起下一個ajax請求。
優點:?相容性較高,實現簡單
缺點:?對於php這種語言來說,如果要做到即時,那麼服務端就要承受大得多的壓力,因為擱置到什麼時候往往是不確定的,這就要php指令碼每次擱置都進行一個while迴圈。
當然,如果伺服器重新整理每秒級,那尚可接受,只是即時性上退化了。
注意:?瀏 覽器有串連數限制。我得出的結論是如果當前頁面上有一個ajax請求處於等待返回狀態,那麼其他ajax請求都會被擱置(Chrome, Firefox已測)。如果頁面有一般ajax需求怎麼辦?解決方案是開個架構,架構中使在另一個網域名稱下進行Comet長輪詢,需要注意跨域問題。
PHP實現:?Jquery+php實現comet
相關:Ajax跨域和js跨域解決方案
?
2) Frame 長串連
受到ajax啟發,出現了架構下的長串連。
核心:?Frame中發起一個普通請求,伺服器將其擱置;需要推送時輸出直接執行
指令碼,然後繼續保持串連。如果擔心逾時問題可以改成架構論詢。
優點:?與1一樣具有高相容特性
缺點:?最大的問題是如果架構在載入,那麼瀏覽器就好一直顯示“載入中”,這就弱爆了(解決方案參見文末的相關閱讀資源)。同樣伺服器也要能hold住大量迴圈……另外,是否有同域串連限制沒測試。
?
?
3) Flash/HTML5 WebSockets
用flash來發起WebSockets,秒殺前面一切問題。
優點:?標準化, RealTime, Push
缺點:?伺服器需要能應對WebSockets;還有如果既沒有Flash又不支援HTML5的怎麼辦?
PHP實現:?Start Using HTML5 WebSockets Today
?
6) 使用相容封裝層(socket.io)
以上每種方法都有優劣,那麼終極解決方案便是合在一起!能WebSockets時候就WebSockets,不支援HTML5特性就退化到Flash,沒有Flash則退化到Ajax長輪詢。這也是我的Rainbowfish所採用的方式。
優點:?高度封裝,編寫非常容易,幾乎不需要關心如何去實現的。即時,超低負載,高並發。
缺點:?其實算不上缺點,socket.io的伺服器端要求是node.js,而不是php。
個人看法:?如果你是外掛式主控件,能運行程式,那麼socket.io配合node.js是個非常高效的選擇。為什麼呢?因為它還可以避免php的服務端高負載。
Rainbowfish 的訊息系統通過這種方式實現: 所有用戶端都通過socket.io掛在nodejs伺服器上(注意: 只是掛著,不需要任何迴圈,因為它是事件驅動的);需要推送訊息了,伺服器就與nodejs通訊(比如訪問某個地址來實現),告訴它推送什麼訊息到哪 裡;nodejs收到推送訊號後,則通過socket.io即時傳輸資料給瀏覽器。這個其實也是一條單向的路,因為nodejs伺服器不具備與php通訊 的能力,實際上也不需要,網頁上直接連php就可以了。
?
3. 結束語
事 實上,第一個方法(Ajax Long Pull)是一個不錯的方法,只是如果使用php完成的話伺服器負載上有點大,但這其實是通病;而最後列舉的socket.io方案完全避免了這個問題, 因為它屬於另一種架構,並且這種組合也可以配合幾乎所有的指令碼語言實現push。
對於即時性要求非常高的應用,或許使用php實現即時部分並不是一個好的選擇,將會面臨非常大的伺服器負載(可以通過編寫支援等待事件的擴充來解決這個問題);如果只是訊息提示等,則可以調整伺服器上重新整理的間隔降低到秒的層級,負載尚可接受。不過無論哪種用途,配合那些非阻塞語言或許才是最好的選擇。
4. 相關閱讀
How to implement COMET with PHP
Start Using HTML5 WebSockets Today
Comet(Wikipedia)
Ajax跨域和js跨域解決方案
Jquery+php實現comet
==============================================================================================
?
comet研究[http://lync.in/research-on-comet/]
?
在 Web應用中,用戶端的AJAX技術已經非常普遍也非常深入人心了,但與此同時,另一些應用,諸如線上監控,即時資料顯示,即時通訊等需要將後台資料變化 情況即時顯示到前台,這樣的由伺服器push的行為(也許會讓你想到blackberry)則需要另一種方案來解決,也就是本文所要介紹的Comet ―― 無需安裝外掛程式,保持http長已連線的服務器推方案。
以下兩點是方案中必須顧及到的。
- 瀏覽器通用性,對各種不同實現結構模型的支援。
- 長串連對於伺服器資源的佔用,以及伺服器的承受能力。
Comet的用戶端與服務端互動流
業界對於Comet實現有兩種主要的解決方案:
基於AJAX的輪詢(long polling)方式
這種方式就是由用戶端發出AJAX請求,然後服務端阻塞請求直至有響應或逾時。用戶端在接收到服務端的指令之後會進行響應並發出新的請求。
從 實現層面上來說,當XMLHttpRequest的狀態為4也就是load的狀態時會進行用戶端處理,而Gecko(Firefox)和 Webkit(Chrome,Safari)目前支援在readystate為3的時候讀取(當然只能讀取到所有該請求已返回的串內容,所以需要自行確定 指令邊界),Trident(IE)目前如果中途去讀取會拋出錯誤,IE8中使用XDomainRequest可以適當解決這個問題(參見Eric Law的COMET Streaming in Internet Explorer[])。
目前,開心網採用的是這一種方式。
- ?
基於iframe及htmlfile的流(streaming)方式
這種方式是使用了iframe的機制,然後使得這個iframe請求一個特定的URL,並通過對這個頁面的載入不斷的從服務端抓回資料,這裡從服務端抓回的資料大多是對頁面當前JavaScript函數的引用和操作。
這個方案的一個明顯不足之處是頁面會一直顯示正在載入,而這在IE上會更明顯。Google的天才們想到了用htmlfile的ActiveX控制項來解決這個問題的方案,詳細描述可以參見Alex Russell的What else is burried down in the depth's of Google's amazing JavaScript?
目前,人人網和GTalk採用的是這種方式。
除了文首所提到的通用性和效能之外,還有幾點是需要列入考量範圍的。
- 資料交換的格式。由於資料交換的形式是推送,所以不可避免的會有指令隊列的存在,於是資料結構是需要前後台詳細約定的,執行指令和資料指令都需要有嚴格的界定,一般來說,JSON的方案比較普遍。
- 瀏覽器本身的串連數限制。HTTP 1.1規範中聲明用戶端不應該與伺服器端建立超過兩個的 HTTP 串連,而IE又嚴格遵守了這一點,所以前台在處理請求的時候需要謹慎控制請求的數量。
其實,Comet技術在AJAX大紅大紫的2005年之後的2006年時是業界一個很熱的討論點,目前的這兩種方式非常成熟,在dojo,dwr等前端架構中都已經有這樣的實現,而Bayeux協議的出現也已經在實質上訂下了一種業界的標準。
Comet的架構前端有Pushlet,dwr和dojo等,服務端有Jetty,Meteor,Orbited,Glassfish,Alpha,實現的產品語言也覆蓋了Java,C++,Python,Perl,Ruby,Erlang,.Net等。
下一代HTML5中的WebSocket會是Comet的一個新起點,但在那之前,在非外掛程式的web層面應該不會有更進一步的討論與技術出現。
本文只是對Comet這個技術進行大體的概述,粗陋不明之處難免,在後續的文章中將會對WebSocket進行一定的解釋和示範。
參考資料:
- 這裡有一個php的comet的例子How to implement COMET with PHP。這個要看看
- 這是developerWorks上對於Comet的介紹。
- 這是當前Comet的伺服器端的一些產品及介紹。
- 當然,Wikipedia上面對Comet的解釋也是非常詳盡。
- 還可以看看AjaxPatterns上面的一些介紹。
- 最後,CometDaily是個值得去瞭解最新Comet新聞和知識的地方。
- =====================================================================================================
Comet:基於 HTTP 長串連的“伺服器推”技術
? [http://www.ibm.com/developerworks/cn/web/wa-lo-comet/]
ps:上述文章應該夠你看明白的了。使用一種吧。但我現在還沒有在項目用推技術,原因,還沒有來得及折騰,但在本地測試都很正常 。
以下提供protype 和 jquery的 +php實現的代碼例子。[例子代碼來自網上,已測試通過。好用]
http://bbs.php100.com/read-htm-tid-290215-ds-1.html