php反向通信,Flex+PHP反向推送(長輪詢)

反向推送技術現在非常流行, 而長輪詢是實現反向推送的關鍵技術之一.

//如果要轉載本文請注明出處,免的出現版權紛爭,我不喜歡看到那種轉載了我的作品卻不注明出處的人 Seven{See7di#Gmail.com}

HTTP 協議的成功毋庸置疑。它是 Internet上大部分信息交換的基礎。然而,它也有一些局限性。特別是,它是無狀態、單向的協議。請求被發送到 Web 服務器,服務器處理請求並發回一個響應 —僅此而已。請求必須由客戶機發出,而服務器則只能在對請求的響應中發送數據。這至少會影響很多類型的 Web應用程序的實用性。典型的例子就是聊天程序。另外還有一些例子,例如比賽的比分或電子郵件程序。

HTTP的這些局限性也是它取得一定成功的原因。請求/響應周期使它成為了經典的模型,即每個連接使用一個線程。只要能夠快速為請求提供服務,這種方法就有巨大的可伸縮性。每秒鍾可以處理大量的請求,只需使用少量的服務器就可以處理很大數量的用戶。對於很多經典的 Web應用程序,例如內容管理系統、搜索應用程序和電子商務站 點等等而言,這非常適合。在以上任何一種 Web應用程序中,服務器提供用戶請求的數據,然后關閉連接,並釋放那個線程,使之可以為其他請求服務。如果提供初始數據之后仍可能存在交互,那么將連接保持為打開狀態,因此線程就不能釋放出來,服務器也就不能為很多用戶服務。

但是,如果想在對請求做出響應並發送初始數據之后,仍然保持與用戶的交互呢?在 Web 早期,這一點常使用 meta刷新實現。這將自動指示瀏覽器在指定秒數之后重新裝載頁面,從而支持簡陋的輪詢(polling)。這不僅是一種糟糕的用戶體驗,而且通常效率非常低下。如果沒有新的數據要顯示在頁面上呢?這時不得不重新呈現同樣的頁面。如果對頁面的更改很少,並且頁面的大部分沒有變化呢?同樣,不管是否有必要,都得重新請求和獲取頁面上的一切內容。

Ajax 的發明和流行改變了上述狀況。現在,服務器可以異步通信,因此不必重新請求整個頁面。現在可以進行增量式的更新。只需使用XMLHttpRequest 輪詢服務器。這項技術通常被稱作Comet。這項技術存在一些變體,每種變體具有不同的性能和可伸縮性。我們來看看這些不同風格的 Comet。

Comet 風格

Ajax 的出現使 Comet 成為可能。HTTP的單向性質可以有效地加以規避。實際上有一些不同的方法可以繞過這一點。您可能已經猜到,支持 Comet 的最容易的方式是輪詢(poll)。使用XMLHttpRequest 向服務器發出調用,返回后,等待一段固定的時間(通常使用 JavaScript 的 setTimeout函數),然后再次調用。這是一項非常常見的技術。例如,大多數 webmail 應用程序就是通過這種技術在電子郵件到達時顯示電子郵件的。

這項技術有優點也有缺點。在這種情況下,您期望快速返回響應,就像任何其他 Ajax請求一樣。在請求之間必須有一段暫停。否則,連續不斷的請求會沖垮服務器,並且這種情況下顯然不具有可伸縮性。這段暫停使應用程序產生一個延時。暫停的時間越長,服務器上的新數據就需要越多的時間才能到達客戶機。如果縮短暫停時間,又將重新面臨沖垮服務器的風險。但是另一方面,這顯然是最簡單的實現Comet 的方式。

現在應該指出,很多人認為輪詢並不屬於 Comet。相反,他們認為 Comet 是對輪詢的局限性的一個解決方 案。最常見的 “真正的”Comet 技術是輪詢的一種變體,即長輪詢(longpolling)。輪詢與長輪詢之間的主要區別在於服務器花多長的時間作出響應。長輪詢通常將連接保持一段較長的時間 —通常是數秒鍾,但是也可能是一分鍾甚至更長。當服務器上發生某個事件時,響應被發送並隨即關閉,輪詢立即重新開始。

長輪詢相對於一般輪詢的優點在於,數據一旦可用,便立即從服務器發送到客戶機。請求可能等待較長的時間,期間沒有任何數據返回,但是一旦有了新的數據,它將立即被發送到客戶機。因此沒有延時。如果您使用過基於 Web 的聊天程序,或者聲稱 “實時” 的任何程序,那么它很可能就是使用了這種技術。

下面我就Flex和PHP來舉例說明一下,常輪詢如何實現.

首先將一下PHP端的代碼,很簡單

//timeout in seconds

$timeout = 60;

// log start time

$start_time = time();

// get messge from local file

function get_msg(){

return file_get_contents('msg.txt');

}

// get message

$last_msg = get_msg();

// start the loop

while (true){

// get current time

$current_time = time();

// check if we are timed out

if ($current_time - $start_time > $timeout){

echo 'timeout! no new message!';

break;

}

// get latest message

$current_msg = get_msg();

// check if the message has been changed

if ($last_msg != $current_msg){

echo $current_msg;

break;

}

// sleep 1 sec

sleep(1);

}

分析上面的代碼, 其實原理就是在php中執行一個循環, 每次循環的時候去訪問服務器上的數據, 可以是數據庫也可以是一個文本文件,這里采用文本文件, 然后判斷文本文件的內容是否更新過,如果更新過則將數據返回給客戶端. 在循環當中我們放入了 sleep(1)函數讓代碼每次循環的時候暫停1秒鍾,這樣不至於過度損耗服務器CPU的資源.

下面是flex端的代碼<?xml version="1.0" encoding="utf-8"?>

// request object

private var req:URLRequest;

// loader object

private var loader:URLLoader;

// timer

private var timer:Timer;

[Bindable]

private var count:Number = 0;

// do some initializing

private function init():void{

req = new URLRequest('http://127.0.0.1:8080/long_polling.php');

loader = new URLLoader();

loader.addEventListener(HTTPStatusEvent.HTTP_STATUS, onStatusChange);

loader.addEventListener(Event.COMPLETE, onComplete);

loader.addEventListener(IOErrorEvent.IO_ERROR, onIOError);

timer = new Timer(1000);

timer.addEventListener(TimerEvent.TIMER, onTimer, false, 0, true);

}

// update the second count

private function onTimer(event:TimerEvent):void{

count ++;

}

// start the request

private function startRequest():void{

count = 0;

loader.load(req);

timer.start();

this.txtLogs.text += 'Request started!\n';

}

// status changed

private function onStatusChange(event:HTTPStatusEvent):void{

this.txtLogs.text += 'Status changed to '+ String(event.status)+'\n';

}

// result returned

private function onComplete(event:Event):void{

this.txtLogs.text += 'Completed! Result is '+String(event.currentTarget.data)+'\n';

this.txtLogs.text += 'Start another request!\n';

this.startRequest();

}

// error handler

private function onIOError(event:IOErrorEvent):void{

this.txtLogs.text += 'IO Error: '+String(event)+'\n';

this.stopRequest();

}

// stop the request

private function stopRequest():void{

count = 0;

this.txtLogs.text += 'Request stopped!\n';

this.txtLogs.text += '<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>\n'

this.timer.stop();

this.loader.close();

}

]]>

我們新建一個flex項目, 然后在界面上放置4個空間, 兩個按鈕, 一個是開始請求, 一個是結束請求, 還有一個label用來顯示當前請求所花的時間, 最后再放一個TextArea來顯示log.

請求的原理也同樣簡單, 通過URLLoader和URLRequest來實現, 和普通的http請求並無兩樣.不過在一次請求獲取到結果的時候(走到onComplete()函數), 我們需要重新開始另外一次查詢,通過這種方式我們就可以模擬出一個類似與C/S架構的網絡連接, 而服務端上的任何更新則會自動推送到客戶端了.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值