PHP中Push(推送)技術的探討

隨着人們對Web即時應用需求的不斷上升,Server Push(推送)技術在聊天、消息提醒尤爲是社交網絡等方面開始興起,成爲實時應用的數據流核心。這篇日誌試圖探討的即是各類適合於PHP的Push的實現方式以及其優劣。 javascript

1. 什麼是Server Push php

想象在聊天應用中,若是使用傳統的ajax來承擔消息的傳入,那麼通常是經過每隔必定時間拉取一次信息的方式實現,可是其實這種方式有大量查詢是浪費的。聊天等Web應用更須要服務器在特定時間來主動告知前端有新的消息(Push),而不是前端每時每刻問服務器:「來消息了嗎?」(Pull)。這也正是爲何這個技術常被叫作反向ajax。 html

其餘別名:Comet,反向Ajax 前端

 

2. 如何實現Push html5

其實所謂的推送技術也沒有多麼複雜,目前從大類上有3種,一種仍然創建在ajax基礎上,還有一種創建在框架基礎上,最後一種拋棄了傳統的HTTP協議,使用Flash或者HTML5的WebSockets技術。接下來將對這三種類別產生的不一樣的方式進行探討。 java


1) Ajax 長輪詢 node

Ajax長輪詢從本質上來講仍然是一種pull,可是實時性較高,無用請求減小不少,是一種不錯的Push實現方案。不過它只減小了網絡上的無謂消耗。 web

核心: 客戶端發起一個ajax請求,服務端將請求擱置(pending)或者說掛起,直到到了超時時間(timeout)或須要推送時返回;客戶端則等待ajax返回後處理數據,再發起下一個ajax請求。 ajax

優勢: 兼容性較高,實現簡單 跨域

缺點: 對於php這種語言來講,若是要作到實時,那麼服務端就要承受大得多的壓力,由於擱置到何時每每是不肯定的,這就要php腳本每次擱置都進行一個while循環。
固然,若是服務器刷新每秒級,那尚可接受,只是實時性上退化了。

注意: 瀏覽器有鏈接數限制。我得出的結論是若是當前頁面上有一個ajax請求處於等待返回狀態,那麼其餘ajax請求都會被擱置(Chrome, Firefox已測)。彷佛跟頁面標記有關,一個規範的HTML能夠同時有多個請求。若是頁面有通常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

相關文章
相關標籤/搜索