如何使用长轮询自动刷新网页

时间:2013-02-04 15:34:52

标签: ajax cgi long-polling

我试图弄清楚如何使用长轮询来触发网页刷新(整个页面而不是单个部分)。虽然更新部分页面而不是单个部分会更好,但我宁愿只关闭初始页面刷新部分,然后从那里继续。话虽如此,我想知道是否有人能够指出我是如何做到这一点的正确方向?我一直在寻找在线长期投票的例子,但遗憾的是还没有找到类似的东西。几乎我会有一个网页,我可以根据服务器上的某些条件(debian上的apache)使用长轮询进行远程刷新,例如,如果我有一个基于bash脚本的cgi页面,根据服务器时间显示am或pm ,当服务器上的时间从am变为pm或反之,服务器将在客户端触发页面刷新,因此cgi页面将重新加载并显示正确的数据。

1 个答案:

答案 0 :(得分:1)

首先,好吧。如果你做长轮询请求,你需要记住,在浏览器中查看的每个页面都会有一个与服务器的开放连接。 这要求您的服务器基础架构能够在没有大量内存消耗的情况下处理此问题,并且不会用尽空闲连接来处理长轮询请求。

我不认为你使用php但它是一个很好的例子:所以如果你有php模块的apache,一方面是apache配置的最大连接限制,另一方面是每个连接的限制整个php模块已加载,如果你有很多页面浏览量,它会占用大量内存。如果你使用php-fpm作为fcgi,那么也有最大数量的可用客户端,你也不希望在一定限度内增加这个数字。

所以我建议不要对公共网站使用长轮询请求,如果你没有一个好的服务器后端,它有一些很好的逻辑来处理它。

根据您可以考虑以下解决方案的要求,如果您知道该页面应检查刷新的间隔:

您可以将属性data-check-for-refresh-atdata-modified-at添加到您的html节点:

<html data-check-for-refresh-at='2013-02-04 12:00:00 GMT' data-modified-at='2013-01-01 12:00:00 GMT'>

使用javascript解析此问题,然后在此时使用该请求提交modified-at时间进行刷新检查。如果内容发生变化,您将提交新内容,下次客户端应检查更新。

另一件重要的事情是,你应该在客户端为这个刷新时间添加一个随机偏移,否则你可能是自己的DDOS。因为所有客户端都会同时发送刷新请求。

编辑(基于评论)

首先简要说明如何为真实系统完成:

服务器不应该为每个连接使用一个线程或进程,而应该使用事件驱动方法(如果流已准备好读取或写入,则注册回调以通知)。然后,如果长轮询请求到达,则服务器存储关于客户机想要通知哪些改变的信息。然后连接正在睡觉不再需要为该连接浪费cpu圈,直到客户端需要通知,内存使用率也很低。然后,如果更改了网址,将通知服务器应该通知所有听取此网址更改的客户端。然后,服务器将响应提交给客户端(发布订阅系统)。根据要通知的客户端数量,通知应该以智能方式排队和处理,这样您就可以更好地平衡传出流量。使用这种方法,您将更有可能遇到最大允许的openports / filedescriptor问题,然后遇到cpu或内存使用问题。

当然这是一个非常简单的描述,但我认为这足以让他知道如何实现它。

快速和肮脏的解决方案 它是伪代码然后是真实代码,因此这对复制和过去不起作用,也假设服务器在任何长轮询请求到达之前为$notificationFile创建文件):

长轮询请求将调用这样的php脚本:

set_time_limit(0);

/*
$urlToCheck and  $modificationTimeToCheckAgainst should be initialized by the values send by client as parameter for the long polling request
$someTime should be the maximum time the long polling request should be keept alive
*/
$forceResponseTimeout =  microtime(true) + $someTime;
$urlToCheck = "the/url/to/observe.html"; 
$modificationTimeToCheckAgainst = "2013-02-05 00:00:00"; //should be the time in seconds (not a real date)

$notificationFile = "./tmp/observer-file-".sha1($urlToCheck);

$responseStatus = "did-not-change";
while( microtime(true) < $forceResponseTimeout ) {
   clearstatcache(); //need to clear cache otherwise we don't have the right modification date (also not the beast idea to keep cpu usage low)
   if( filemtime(".update-check-file-".sha1($pathToCheck)) > $modificationTimeToCheckAgainst ) {
        $responseStatus = "changed";
        break;
   }
   usleep(100); //this is a bad idea because it creates a high cpu usage, even with the sleep
}

echo $responseStatus;  //here some json response should be created, the client then gets the information if it should resend the long polling request or if it should do a refresh.

更新脚本应如下所示:

 $urlThatIsUpdated = "the/url/to/observe.html";

 //doing the update of the file


 $notificationFile = "./tmp/observer-file-".sha1($urlThatIsUpdated);

 touch($notificationFile); //updates the modification time of the notification file, which should be recognized by the script above.