我试图弄清楚如何使用长轮询来触发网页刷新(整个页面而不是单个部分)。尽管只更新页面的一部分而不是单个部分会更好,但我宁愿只完成初始页面刷新部分,然后从那里继续。话虽如此,我想知道是否有人能够指出我如何去做这件事的正确方向?我一直在网上搜索长轮询的例子,但不幸的是还没有找到类似的东西。几乎我会有一个网页,我可以根据服务器上的某些条件使用长轮询远程刷新(debian 上的 apache),例如,如果我有一个基于 bash 脚本的 cgi 页面,该页面根据服务器时间显示 am 或 pm ,
1 回答
好吧,首先。如果您执行长轮询请求,您需要记住,在浏览器中查看的每个页面都将与您的服务器建立开放连接。这要求您的服务器基础架构能够在不消耗大量内存的情况下处理此问题,并且不会耗尽可用连接来处理长轮询请求。
我不认为你使用 php,但这是一个很好的例子:所以如果你有 apache 和 php 模块,一方面通过 apache 的配置限制最大连接,另一方面对于每个连接整个 php如果您有很多页面视图,则加载的模块会占用大量内存。如果你使用 php-fpm 作为 fcgi,还有一个可用客户端的最大数量,你也不想增加这个数量超过一定的限制。
所以通常我建议不要对公共网站使用长轮询请求,如果你没有一个好的服务器后端,它有一些很好的逻辑来处理这个。
根据您可以考虑以下解决方案的要求,如果您知道该页面应该在哪个时间间隔检查刷新:
你可以添加一个属性data-check-for-refresh-at
和data-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 圈,而且内存使用率也很低。然后,如果 url 发生更改,将通知服务器应该通知所有侦听此 url 更改的客户端。然后服务器将响应提交给客户端(发布订阅系统)。根据要通知的客户端数量,通知可能应该排队并以智能方式处理,以便您可以更好地平衡传出流量。使用这种方法,您更有可能遇到最大允许的 openports/filedescriptor 问题,然后遇到 cpu 或内存使用问题。
当然,这是一个非常简单的描述,但我认为足以了解它是如何实现的。
Quick&Dirty 解决方案
它是伪代码而不是真实代码,因此这不适用于复制和过去,还假设服务器$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.