查閱詞典Comet中文是“彗星”的意思,起初我見(jiàn)到這個(gè)單詞的時(shí)候,我就猜想優(yōu)美名字背后到底是什么呢?他是一種WEB服務(wù)器推的應(yīng)用技術(shù)(Server Push)。Server Push就如同它自己的名字一樣,將更多華麗的web體驗(yàn)“推”進(jìn)了我們的視野。有 一些觀點(diǎn) 將Comet比作是 Ajax 的接班人,這個(gè)觀點(diǎn) 我無(wú)法茍同,我認(rèn)為Ajax 與Comet 并不存在取代關(guān)系。 從實(shí)質(zhì)上講 Comet 還是Ajax的應(yīng)用。
要講清楚Comet是什么的問(wèn)題?我不妨將話題扯遠(yuǎn)點(diǎn),我們先了解下web開(kāi)發(fā)的歷史。
大家一定還記得從前,我們?cè)谡搲?cè)賬號(hào),一點(diǎn)了提交按鈕,頁(yè)面就一片空白(服務(wù)器在刷新頁(yè)面,處理提交數(shù)據(jù)),ie的狀態(tài)圖就不停的轉(zhuǎn),一個(gè)提交按鈕一點(diǎn),頁(yè)面就再也不能進(jìn)行其他操作了(因?yàn)檫@里的數(shù)據(jù)請(qǐng)求和界面操作是同步的)。我們就傻等著服務(wù)器處理完數(shù)據(jù)后返回,以前網(wǎng)速也慢,服務(wù)器性能也差。那么這個(gè)等待時(shí)間就會(huì)挑戰(zhàn)大家的容忍極限。這個(gè)就是Ajax誕生要解決的問(wèn)題。
其實(shí)在Ajax這個(gè)名字沒(méi)有出現(xiàn)的時(shí)候,‘Ajax’的應(yīng)用就已經(jīng)存在了。那時(shí)前輩們就已經(jīng)在WEB方面為追求更完美的用戶體驗(yàn),為追求異步通信,為追求局部刷新摸索出了一些可重用的方式方法。大致方法有2種:
一種是頁(yè)面中放入一個(gè)隱藏的frame 頁(yè)面,這個(gè)頁(yè)面有一個(gè)表單form對(duì)象。而數(shù)據(jù)的提交,就交給這個(gè) frame 頁(yè)面。就算是刷新也是這個(gè)頁(yè)面刷新,而這個(gè)頁(yè)面由于是隱藏的或者高度和寬度設(shè)置為0的,所以刷新時(shí)候用戶感覺(jué)不到。那么當(dāng)數(shù)據(jù)返回的時(shí)候也就能夠達(dá)到局部刷新的效果。而且用戶操作的頁(yè)面不用被卡住,這樣也達(dá)到異步通信的效果了。這種是比較古老和麻煩的方法。
另外一種和當(dāng)今的Ajax就很類似了。開(kāi)發(fā)人員開(kāi)發(fā)自己的ActiveX 控件,這個(gè)控件的功能基本和現(xiàn)在Ajax 差不多,其實(shí)Ajax 大家也可以看成是一個(gè)ActiveX 控件,只是各大瀏覽器都實(shí)現(xiàn)了這個(gè)ActiveX 控件。所以現(xiàn)在我們開(kāi)發(fā)Ajax應(yīng)用,不用自己開(kāi)發(fā)這個(gè)ActiveX 控件。
Ajax實(shí)現(xiàn)了對(duì)XMLHTTP對(duì)象的封裝,這個(gè)對(duì)象有一系列接口,比較重要的是發(fā)送異步數(shù)據(jù)的接口。
2.那Comet是在什么歷史背景下誕生的呢?
當(dāng)服務(wù)器端數(shù)據(jù)發(fā)生變化時(shí),客戶端如何即時(shí)得到通知呢?這個(gè)就是Comet誕生的背景。
1.
傳統(tǒng)方法定時(shí)刷新,就是隔一個(gè)時(shí)間段瀏覽器刷新一次。(沒(méi)有用戶受得了這種方法,服務(wù)器也害怕遇到這種事情)
2.
長(zhǎng)輪詢(long-polling)
Ajax隔一段時(shí)間就去服務(wù)器查詢是否有更新,但是多長(zhǎng)時(shí)間去查詢成了問(wèn)題。因?yàn)樾阅芎图磿r(shí)性造成了嚴(yán)重的反比關(guān)系。
3.在前面兩種方法被否定后,想到了服務(wù)器推送至客戶端這種模式,但是web開(kāi)發(fā)客戶端是一個(gè)瀏覽器(并不是我們自己控制的GUI客戶端)。所以Comet登場(chǎng),簡(jiǎn)單說(shuō)還是利用Ajax與服務(wù)器建立http長(zhǎng)連接查詢是否有數(shù)據(jù)更新,服務(wù)器收到一個(gè)連接如果沒(méi)有數(shù)據(jù)更新就阻塞這個(gè)連接不要返回給客戶端,直到有新數(shù)據(jù)再返回給客戶端。Web客戶端,發(fā)起的連接一旦被返回,或者超時(shí)就再次建立http長(zhǎng)連接。這樣就能保證數(shù)據(jù)的即時(shí)更新,以及盡量減少服務(wù)器的計(jì)算工作。 2. Comet的一些應(yīng)用
目前Comet主要應(yīng)用在一些股票web客戶端,以及一些基于web的即時(shí)聊天系統(tǒng)中。
比較成熟的框架有Dojo ,Dwr 等一些Ajax框架中實(shí)現(xiàn)了該功能。
3.
Comet
優(yōu)、
缺點(diǎn)
3.1 缺點(diǎn)
長(zhǎng)期占用連接,喪失了無(wú)狀態(tài)高并發(fā)的特點(diǎn)。
server push不會(huì)是一個(gè)沒(méi)有副作用的解決方案,是否適合還要仔細(xì)權(quán)衡。
3.2 優(yōu)點(diǎn)
Ø
實(shí)時(shí)性好(消息延時(shí)小)
Ø
性能好(能支持大量用戶)
4.其他服務(wù)器推技術(shù)
Comet 只是眾多服務(wù)器推技術(shù)中的一種,目前市面上還有許多其他流行服務(wù)器推技術(shù)。
4.1
Flash XMLSocket
這種方案實(shí)現(xiàn)的基礎(chǔ)是:
1.
Flash 提供了 XMLSocket 類。
2.
JavaScript 和 Flash 的緊密結(jié)合:在 JavaScript 可以直接調(diào)用 Flash 程序提供的接口。
但此方案的缺點(diǎn)在于:
1.
因?yàn)?nbsp;XMLSocket 沒(méi)有 HTTP 隧道功能,XMLSocket 類不能自動(dòng)穿過(guò)防火墻;
2.
因?yàn)槭鞘褂锰捉涌冢枰O(shè)置一個(gè)通信端口,防火墻、代理服務(wù)器也可能對(duì)非 HTTP 通道端口進(jìn)行限制;
不過(guò)這種方案在一些網(wǎng)絡(luò)聊天室,網(wǎng)絡(luò)互動(dòng)游戲中已得到廣泛使
用
。
4.2 Java Applet 套接口
在客戶端使用 Java Applet,通過(guò)
java.net.Socket
或
java.net.DatagramSocket
或
java.net.MulticastSocket
建立與服務(wù)器端的套接口連接,從而實(shí)現(xiàn)“服務(wù)器推”。
這種方案最大的不足在于 Java applet
需要客戶端安裝JAVA虛擬機(jī)
。
5. 總結(jié)
Comet
不存在什么新技術(shù),沒(méi)有什么神秘可言
。
瓶頸主要集中在web server這一塊,一般成熟的
Comet
商業(yè)應(yīng)用都會(huì)有一套它自己專用的web server,比如lightstreamer就是這樣!
實(shí)例解析:
服務(wù)端:
$filename = dirname(__FILE__).'/data.txt';
$msg = isset($_GET['msg']) ? $_GET['msg'] : '';
if ($msg != '')
{
//寫(xiě)入內(nèi)容至文件
file_put_contents($filename,$msg);
die();
}
set_time_limit(0);
$lastmodif = isset($_GET['timestamp']) ? $_GET['timestamp'] : 0;
//取得文件最后修改時(shí)間
$currentmodif = filemtime($filename);
while ($currentmodif <= $lastmodif)
{
//有釋放CPU占用率的作用
usleep(10000);
//清除文件緩存信息
clearstatcache();
$currentmodif = filemtime($filename);
}
// return a json array
$response = array();
$response['msg'] = file_get_contents($filename);
$response['timestamp'] = $currentmodif;
echo json_encode($response);
ob_flush();
flush();
?>
客戶端:
{
if (!WebApp._noerror_)
{
setTimeout(WebApp.WebMain, 5000);
}else
{
setTimeout(WebApp.WebMain, 10);
}
WebApp._noerror_ = false;
}
可以看到不管成功失敗都將開(kāi)始一次新的ajax請(qǐng)求。也就是保持了連接。
使用方法:
1.需要php服務(wù)器;
2.開(kāi)兩個(gè)不同瀏覽器即可掩飾效果。
這只是一個(gè)介紹原理型demo,請(qǐng)勿商業(yè)使用。
DEMO下載