2012年(272)
分类: 网络与安全
2012-06-26 13:15:56
In web development, Comet is a to describe a model in which a long-held request allows a to data to a browser, without the browser explicitly requesting it. Comet is an for multiple techniques for achieving this interaction. All methods have in common that they rely on browser-native technologies such as , rather than on proprietary plugins.
In theory, the Comet approach differs from the , in which a browser requests a complete web page or chunks of data to update a web page. However in practice, Comet applications typically use with to detect new information on the server. The concept predates the coining of the neologism, and is known by several other names, including Ajax Push, , Two-way-web, HTTP Streaming and among others.
实现Comet 的方式有很多种,常见的有。
出于个人爱好,我不喜欢用iframe,而Ajax 又有跨域的限制,所以我使用动态加载script的办法来实现Comet
实现思路:
1. 使用javascript动态加载一个script
2. script指向我们服务端的php
3. php返回数据,并且移除掉刚才动态生成的script,同时生成一个新的script,继续加载服务端的地址
4. 如此循环就可以保持一个连接
值得注意的是关于 keep-alive
在HTTP/1.1的标准中个已经默认将所有的连接都设置为 keep-alive,直到服务器返回一个 Connection: close 为止。 HTTP/1.0中需要手动设置一下。
此外IE还有个问题就是cache的问题,IE真的是一个很矬的浏览器!!!
下面是我的实现代码:
client 端:
<html>
<head>
head>
<body>
<script type="text/javascript" >
var comet = {
author: "axis@ph4nt0m.org",
cometHandler: "cometHandler", // Do not Change this!
cometServer: "cometS.php",
timeout: 3000, //ms
requestData: "",
responseData: "",
request: function(cometServer, timeout, data){
// check params
if (typeof(cometServer) != "undefined"){
comet.cometServer = cometServer;
}
if (typeof(timeout) != "undefined"){
comet.timeout = timeout;
}
if (typeof(data) != "undefined"){
comet.requestData = data;
}
var handler = document.createElement("script");
handler.id = comet.cometHandler;
// IE must refresh cache
var d = new Date();
handler.src = comet.cometServer + "?" + comet.requestData + "×tamp=" + d.getTime();
// IE 太矬了,居然识别不到这个 onerror
handler.onerror = function(msg, file, line){
// alert(msg);
// free handler
var remover = document.getElementById(comet.cometHandler);
remover.parentNode.removeChild(remover);
// reconnect to server after 2 seconds
setTimeout(function(){ comet.request(); }, comet.timeout);
};
try {
document.getElementsByTagName("head")[0].appendChild(handler);
}
catch (e) {
document.getElementsByTagName("body")[0].appendChild(handler);
}
},
response: function(responseData){
var remover = document.getElementById(comet.cometHandler);
remover.parentNode.removeChild(remover);
if (typeof(responseData) != "undefined"){
comet.responseData = responseData;
}
comet.request();
comet.callback(responseData);
},
callback: function(responseData){
doSomething(responseData);
}
};
comet.request("cometS.php", 5000, "a=1\&b=2");
function doSomething(data){
var d = document.createElement("div");
d.innerHTML = data["Search Engines"][3];
document.body.appendChild(d);
}
script>
body>
html>
服务端:
$arr = array("Search Engines" =>
array (
0=> "http//google.com",
1=> "http//yahoo.com",
2=> "http//msn.com/",
3=> date(DATE_RFC822)),
"Social Networking Sites" =>
array (
0 => "http//",
1 => "http//",
2 => "http//vkontakte.ru",)
);
sleep(5);
?>
comet.response();
可以看到,实现的代码很简洁。
使用方式很简单,加载了 comet 后,客户端的调用方法是:
comet.request(服务端的地址, 超时时间, queryString);
在服务端,只需要在代码里返回一个
comet.response(返回数据);
即可。
然后可以通过修改 callback 函数去对返回数据进行处理。
上面POC的运行效果:
这个POC的客户端会去请求服务器,服务器收到请求后,会等待5秒,然后才响应该请求。所以这是服务端主动去告诉客户端一些东西。和以往的 setInterval 不一样。
已知bug:如果在IE下连接出错,就会中断程序,因为检测不到onerror。在firefox下连接出错,会每隔3秒重试。