背景:一直都觉得信息推送是个很实用的功能。以前想到的最初实现方案是:用ajax隔段时间请求一次后台,由后台取出最新消息后作为返回值给ajax回调展示。今天看到了一个不太一样的解决方案:在php端通过while判断信息有没有发生变更,有则返回给前台展示,展示完后继续发送ajax请求给php后台监视信息;没有的时候,php端while就保持循环监视信息状态,这样请求没有结束,ajax的状态不会完成,也就不用重新发送请求了。
两种方案后来分析了下,大致结果如下
第一种隔段时间发送一次的,因为请求频率的问题,必然导致请求次数多。但是这种的每个请求都会很快放开,不需要监视信息变化,只关注请求进来时的信息就可以了。
第二种由php端通过while轮询监视信息是否变化,有变化的时候结束请求,返回给ajax显示,再发送下一次的监视请求;没变化则while循环一直监视。这种方案的话,会大大的减少请求次数问题,但是会导致每个用户对应一个服务器端php监视业务。另外php是没有多线程概念的,用apache的时候有个可以限制最大访问量的设置项MaxRanges。这些问题考虑进去的话会导致一些服务器端同时访问量超标的问题。
第三种听同事谈到的strophe.js是用于解决web im的已封装好插件。(应用的话之后在写)
备注:以上两种方案,具体应用的话,可能还是需要看场景取舍吧
第一种方案的代码,就略了(主要是while,setTimeout,ajax,递归调用之类的)。和下面第二种应用的代码很多会相同的。
上第二种代码:
<?php
// 设置请求运行时间不限制,解决因为超过服务器运行时间而结束请求
ini_set("max_execution_time", "0");
$filename = dirname(__FILE__).'/data.txt';
$msg = isset($_GET['msg']) ? $_GET['msg'] : '';
// 判断页面提交过来的修改内容是否为空,不为空则将内容写入文件,并中断流程
if ($msg != '')
{
file_put_contents($filename,$msg);
exit;
}
/* 获取文件上次修改时间戳 和 当前获取到的最近一次文件修改时间戳
* 文件上次修改时间戳 初始 默认值为0
* 最近一次文件修改时间戳 通过 函数 filemtime()获取
*/
$lastmodif = isset($_GET['timestamp']) ? $_GET['timestamp'] : 0;
clearstatcache(); // 清除文件状态缓存
$currentmodif = filemtime($filename);
/* 如果当前返回的文件修改unix时间戳小于或等于上次的修改时间,
* 表明文件没有更新不需要推送消息
* 如果当前返回的文件修改unix时间戳大于上次的修改时间
* 表明文件有更新需要输出修改的内容作为推送消息
*/
while ($currentmodif <= $lastmodif)
{
usleep(10000); // 休眠10ms释放cpu的占用
clearstatcache(); // 清除文件状态缓存
$currentmodif = filemtime($filename);
}
// 推送信息处理(需要推送说明文件有更改,推送信息包含本次修改时间、内容)
$response = array();
$response['msg'] = file_get_contents($filename);
$response['timestamp'] = $currentmodif;
echo json_encode($response);
flush();
?>
html页面代码
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Comet demo</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript" src="./jquery-1.8.2.min.js"></script>
<script type="text/javascript" src="./json2.js"></script>
<script>
var timestamp = 0;
var url = 'backend.php';
var error = false;
// 通过ajax建立和php端处理函数的连接(通过递归调用建立长时间的连接)
function connect(){
$.ajax({
data : {'timestamp' : timestamp},
url : url,
type : 'get',
timeout : 0,
success : function(response){
var data = JSON.parse(response);
error = false;
timestamp = data.timestamp;
if (data.msg != undefined && data.msg != "")
{
$("#content").append("<div>" + data.msg + "</div>");
}
},
error : function(){
error = true;
setTimeout(function(){ connect();}, 5000);
},
complete : function(){
if (error)
// 请求有错误时,延迟5s再连接
setTimeout(function(){connect();}, 5000);
else
connect();
}
})
}
// 发送信息
function send(msg){
$.ajax({
data : {'msg' : msg},
type : 'get',
url : url
})
}
// 创建长时间的连接
$(document).ready(function(){
connect();
})
</script>
</head>
<body>
<div id="content"></div>
<form action="" method="get"
οnsubmit="send($('#word').val());$('#word').val('');return false;">
<input type="text" name="word" id="word" value="" />
<input type="submit" name="submit" value="Send" />
</form>
</body>
</html>
需要导入js资源:jquery,json2.js