PHP ServerPush (推送) 技术的探讨
轉(zhuǎn)自:http://blog.163.com/bailin_li/blog/static/17449017920124811524364/
需求:
我想做個(gè)會(huì)員站內(nèi)通知的功能。不想用以前的ajax查詢,聽(tīng)說(shuō)有個(gè)推技術(shù)。以下文章介紹的不錯(cuò),來(lái)自轉(zhuǎn)載,
==================================================================================
PHP中Push(推送)技術(shù)的探討? [http://vistaswx.com/blog/article/php-server-push]
?
隨著人們對(duì)Web即時(shí)應(yīng)用需求的不斷上升,Server Push(推送)技術(shù)在聊天、消息提醒尤其是社交網(wǎng)絡(luò)等方面開(kāi)始興起,成為實(shí)時(shí)應(yīng)用的數(shù)據(jù)流核心。這篇日志試圖探討的便是各種適合于PHP的Push的實(shí)現(xiàn)方式以及其優(yōu)劣。
1. 什么是Server Push
想象在聊天應(yīng)用中,如果使用傳統(tǒng)的ajax來(lái)承擔(dān)消息的傳入,那么一般是通過(guò)每隔一定時(shí)間拉取一次信息的方式實(shí)現(xiàn),但是其實(shí)這種方式有大量查詢是浪費(fèi)的。聊天等Web應(yīng)用更需要服務(wù)器在特定時(shí)間來(lái)主動(dòng)告知前端有新的消息(Push),而不是前端每時(shí)每刻問(wèn)服務(wù)器:“來(lái)消息了嗎?”(Pull)。這也正是為什么這個(gè)技術(shù)常被叫做反向ajax。
其他別名:Comet,反向Ajax
?
2. 如何實(shí)現(xiàn)Push
其實(shí)所謂的推送技術(shù)也沒(méi)有多么復(fù)雜,目前從大類上有3種,一種仍然建立在ajax基礎(chǔ)上,還有一種建立在框架基礎(chǔ)上,最后一種拋棄了傳統(tǒng)的HTTP協(xié)議,使用Flash或者HTML5的WebSockets技術(shù)。接下來(lái)將對(duì)這三種類別產(chǎn)生的不同的方式進(jìn)行探討。
1) Ajax 長(zhǎng)輪詢
Ajax長(zhǎng)輪詢從本質(zhì)上來(lái)說(shuō)仍然是一種pull,但是實(shí)時(shí)性較高,無(wú)用請(qǐng)求減少很多,是一種不錯(cuò)的Push實(shí)現(xiàn)方案。不過(guò)它只減少了網(wǎng)絡(luò)上的無(wú)謂消耗。
核心:?客戶端發(fā)起一個(gè)ajax請(qǐng)求,服務(wù)端將請(qǐng)求擱置(pending)或者說(shuō)掛起,直到到了超時(shí)時(shí)間(timeout)或需要推送時(shí)返回;客戶端則等待ajax返回后處理數(shù)據(jù),再發(fā)起下一個(gè)ajax請(qǐng)求。
優(yōu)點(diǎn):?兼容性較高,實(shí)現(xiàn)簡(jiǎn)單
缺點(diǎn):?對(duì)于php這種語(yǔ)言來(lái)說(shuō),如果要做到實(shí)時(shí),那么服務(wù)端就要承受大得多的壓力,因?yàn)閿R置到什么時(shí)候往往是不確定的,這就要php腳本每次擱置都進(jìn)行一個(gè)while循環(huán)。
當(dāng)然,如果服務(wù)器刷新每秒級(jí),那尚可接受,只是實(shí)時(shí)性上退化了。
注意:?瀏覽器有連接數(shù)限制。我得出的結(jié)論是如果當(dāng)前頁(yè)面上有一個(gè)ajax請(qǐng)求處于等待返回狀態(tài),那么其他ajax請(qǐng)求都會(huì)被擱置(Chrome, Firefox已測(cè))。如果頁(yè)面有一般ajax需求怎么辦?解決方法是開(kāi)個(gè)框架,框架中使在另一個(gè)域名下進(jìn)行Comet長(zhǎng)輪詢,需要注意跨域問(wèn)題。
PHP實(shí)現(xiàn):?Jquery+php實(shí)現(xiàn)comet
相關(guān):Ajax跨域和js跨域解決方案
?
2) Frame 長(zhǎng)連接
受到ajax啟發(fā),出現(xiàn)了框架下的長(zhǎng)連接。
核心:?Frame中發(fā)起一個(gè)普通請(qǐng)求,服務(wù)器將其擱置;需要推送時(shí)輸出直接執(zhí)行
腳本,然后繼續(xù)保持連接。如果擔(dān)心超時(shí)問(wèn)題可以改成框架論詢。
優(yōu)點(diǎn):?與1一樣具有高兼容特性
缺點(diǎn):?最大的問(wèn)題是如果框架在載入,那么瀏覽器就好一直顯示“載入中”,這就弱爆了(解決方法參見(jiàn)文末的相關(guān)閱讀資源)。同樣服務(wù)器也要能hold住大量循環(huán)……另外,是否有同域連接限制沒(méi)測(cè)試。
?
?
3) Flash/HTML5 WebSockets
用flash來(lái)發(fā)起WebSockets,秒殺前面一切問(wèn)題。
優(yōu)點(diǎn):?標(biāo)準(zhǔn)化, RealTime, Push
缺點(diǎn):?服務(wù)器需要能應(yīng)對(duì)WebSockets;還有如果既沒(méi)有Flash又不支持HTML5的怎么辦?
PHP實(shí)現(xiàn):?Start Using HTML5 WebSockets Today
?
6) 使用兼容封裝層(socket.io)
以上每種方法都有優(yōu)劣,那么終極解決方案便是合在一起!能WebSockets時(shí)候就WebSockets,不支持HTML5特性就退化到Flash,沒(méi)有Flash則退化到Ajax長(zhǎng)輪詢。這也是我的Rainbowfish所采用的方式。
優(yōu)點(diǎn):?高度封裝,編寫非常容易,幾乎不需要關(guān)心如何去實(shí)現(xiàn)的。實(shí)時(shí),超低負(fù)載,高并發(fā)。
缺點(diǎn):?其實(shí)算不上缺點(diǎn),socket.io的服務(wù)器端要求是node.js,而不是php。
個(gè)人看法:?如果你是獨(dú)立主機(jī),能運(yùn)行程序,那么socket.io配合node.js是個(gè)非常高效的選擇。為什么呢?因?yàn)樗€可以避免php的服務(wù)端高負(fù)載。
Rainbowfish的消息系統(tǒng)通過(guò)這種方式實(shí)現(xiàn): 所有客戶端都通過(guò)socket.io掛在nodejs服務(wù)器上(注意: 只是掛著,不需要任何循環(huán),因?yàn)樗鞘录?qū)動(dòng)的);需要推送消息了,服務(wù)器就與nodejs通信(比如訪問(wèn)某個(gè)地址來(lái)實(shí)現(xiàn)),告訴它推送什么消息到哪里;nodejs收到推送信號(hào)后,則通過(guò)socket.io實(shí)時(shí)傳輸數(shù)據(jù)給瀏覽器。這個(gè)其實(shí)也是一條單向的路,因?yàn)閚odejs服務(wù)器不具備與php通信的能力,實(shí)際上也不需要,網(wǎng)頁(yè)上直接連php就可以了。
?
3. 結(jié)束語(yǔ)
事實(shí)上,第一個(gè)方法(Ajax Long Pull)是一個(gè)不錯(cuò)的方法,只是如果使用php完成的話服務(wù)器負(fù)載上有點(diǎn)大,但這其實(shí)是通病;而最后列舉的socket.io方案完全避免了這個(gè)問(wèn)題,因?yàn)樗鼘儆诹硪环N架構(gòu),并且這種組合也可以配合幾乎所有的腳本語(yǔ)言實(shí)現(xiàn)push。
對(duì)于實(shí)時(shí)性要求非常高的應(yīng)用,或許使用php實(shí)現(xiàn)實(shí)時(shí)部分并不是一個(gè)好的選擇,將會(huì)面臨非常大的服務(wù)器負(fù)載(可以通過(guò)編寫支持等待事件的擴(kuò)展來(lái)解決這個(gè)問(wèn)題);如果只是消息提示等,則可以調(diào)整服務(wù)器上刷新的間隔降低到秒的級(jí)別,負(fù)載尚可接受。不過(guò)無(wú)論哪種用途,配合那些非阻塞語(yǔ)言或許才是最好的選擇。
4. 相關(guān)閱讀
How to implement COMET with PHP
Start Using HTML5 WebSockets Today
Comet(Wikipedia)
Ajax跨域和js跨域解決方案
Jquery+php實(shí)現(xiàn)comet
==============================================================================================
?
comet研究[http://lync.in/research-on-comet/]
?
在Web應(yīng)用中,客戶端的AJAX技術(shù)已經(jīng)非常普遍也非常深入人心了,但與此同時(shí),另一些應(yīng)用,諸如在線監(jiān)控,實(shí)時(shí)數(shù)據(jù)顯示,即時(shí)通訊等需要將后臺(tái)數(shù)據(jù)變化情況實(shí)時(shí)顯示到前臺(tái),這樣的由服務(wù)器push的行為(也許會(huì)讓你想到blackberry)則需要另一種方案來(lái)解決,也就是本文所要介紹的Comet —— 無(wú)需安裝插件,保持http長(zhǎng)連接的服務(wù)器推方案。
以下兩點(diǎn)是方案中必須顧及到的。
瀏覽器通用性,對(duì)各種不同實(shí)現(xiàn)結(jié)構(gòu)模型的支持。
長(zhǎng)連接對(duì)于服務(wù)器資源的占用,以及服務(wù)器的承受能力。
Comet的客戶端與服務(wù)端交互流
業(yè)界對(duì)于Comet實(shí)現(xiàn)有兩種主要的解決方案:
基于AJAX的輪詢(long polling)方式
這種方式就是由客戶端發(fā)出AJAX請(qǐng)求,然后服務(wù)端阻塞請(qǐng)求直至有響應(yīng)或超時(shí)??蛻舳嗽诮邮盏椒?wù)端的指令之后會(huì)進(jìn)行響應(yīng)并發(fā)出新的請(qǐng)求。
從實(shí)現(xiàn)層面上來(lái)說(shuō),當(dāng)XMLHttpRequest的狀態(tài)為4也就是load的狀態(tài)時(shí)會(huì)進(jìn)行客戶端處理,而Gecko(Firefox)和Webkit(Chrome,Safari)目前支持在readystate為3的時(shí)候讀取(當(dāng)然只能讀取到所有該請(qǐng)求已返回的串內(nèi)容,所以需要自行確定指令邊界),Trident(IE)目前如果中途去讀取會(huì)拋出錯(cuò)誤,IE8中使用XDomainRequest可以適當(dāng)解決這個(gè)問(wèn)題(參見(jiàn)Eric Law的COMET Streaming in Internet Explorer[])。
目前,開(kāi)心網(wǎng)采用的是這一種方式。
?
基于iframe及htmlfile的流(streaming)方式
這種方式是使用了iframe的機(jī)制,然后使得這個(gè)iframe請(qǐng)求一個(gè)特定的URL,并通過(guò)對(duì)這個(gè)頁(yè)面的加載不斷的從服務(wù)端抓回?cái)?shù)據(jù),這里從服務(wù)端抓回的數(shù)據(jù)大多是對(duì)頁(yè)面當(dāng)前JavaScript函數(shù)的引用和操作。
這個(gè)方案的一個(gè)明顯不足之處是頁(yè)面會(huì)一直顯示正在加載,而這在IE上會(huì)更明顯。Google的天才們想到了用htmlfile的ActiveX控件來(lái)解決這個(gè)問(wèn)題的方案,詳細(xì)描述可以參見(jiàn)Alex Russell的What else is burried down in the depth's of Google's amazing JavaScript?
目前,人人網(wǎng)和GTalk采用的是這種方式。
除了文首所提到的通用性和性能之外,還有幾點(diǎn)是需要列入考量范圍的。
數(shù)據(jù)交換的格式。由于數(shù)據(jù)交換的形式是推送,所以不可避免的會(huì)有指令隊(duì)列的存在,于是數(shù)據(jù)結(jié)構(gòu)是需要前后臺(tái)詳細(xì)約定的,執(zhí)行指令和數(shù)據(jù)指令都需要有嚴(yán)格的界定,一般來(lái)說(shuō),JSON的方案比較普遍。
瀏覽器本身的連接數(shù)限制。HTTP 1.1規(guī)范中聲明客戶端不應(yīng)該與服務(wù)器端建立超過(guò)兩個(gè)的 HTTP 連接,而IE又嚴(yán)格遵守了這一點(diǎn),所以前臺(tái)在處理請(qǐng)求的時(shí)候需要謹(jǐn)慎控制請(qǐng)求的數(shù)量。
其實(shí),Comet技術(shù)在AJAX大紅大紫的2005年之后的2006年時(shí)是業(yè)界一個(gè)很熱的討論點(diǎn),目前的這兩種方式非常成熟,在dojo,dwr等前端框架中都已經(jīng)有這樣的實(shí)現(xiàn),而B(niǎo)ayeux協(xié)議的出現(xiàn)也已經(jīng)在實(shí)質(zhì)上訂下了一種業(yè)界的標(biāo)準(zhǔn)。
Comet的框架前端有Pushlet,dwr和dojo等,服務(wù)端有Jetty,Meteor,Orbited,Glassfish,Alpha,實(shí)現(xiàn)的產(chǎn)品語(yǔ)言也覆蓋了Java,C++,Python,Perl,Ruby,Erlang,.Net等。
下一代HTML5中的WebSocket會(huì)是Comet的一個(gè)新起點(diǎn),但在那之前,在非插件的web層面應(yīng)該不會(huì)有更進(jìn)一步的討論與技術(shù)出現(xiàn)。
本文只是對(duì)Comet這個(gè)技術(shù)進(jìn)行大體的概述,粗陋不明之處難免,在后續(xù)的文章中將會(huì)對(duì)WebSocket進(jìn)行一定的解釋和演示。
參考資料:
這里有一個(gè)php的comet的例子How to implement COMET with PHP。這個(gè)要看看
這是developerWorks上對(duì)于Comet的介紹。
這是當(dāng)前Comet的服務(wù)器端的一些產(chǎn)品及介紹。
當(dāng)然,Wikipedia上面對(duì)Comet的解釋也是非常詳盡。
還可以看看AjaxPatterns上面的一些介紹。
最后,CometDaily是個(gè)值得去了解最新Comet新聞和知識(shí)的地方。
=====================================================================================================
Comet:基于 HTTP 長(zhǎng)連接的“服務(wù)器推”技術(shù)
? [http://www.ibm.com/developerworks/cn/web/wa-lo-comet/]
ps:上述文章應(yīng)該夠你看明白的了。使用一種吧。但我現(xiàn)在還沒(méi)有在項(xiàng)目用推技術(shù),原因,還沒(méi)有來(lái)得及折騰,但在本地測(cè)試都很正常 。
以下提供protype 和 jquery的 +php實(shí)現(xiàn)的代碼例子。[例子代碼來(lái)自網(wǎng)上,已測(cè)試通過(guò)。好用]
http://bbs.php100.com/read-htm-tid-290215-ds-1.html
轉(zhuǎn)載于:https://blog.51cto.com/smileyouth/1630199
總結(jié)
以上是生活随笔為你收集整理的PHP ServerPush (推送) 技术的探讨的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 2015年4月8日主从不同步故障解决(字
- 下一篇: PHP 错误与异常 笔记与总结(14 )