Ajax 长轮询(彗星)+ php on lighttpd v1.4.22 多实例问题

发布于 2024-08-12 01:34:35 字数 963 浏览 8 评论 0原文

我是这个网站的新手,所以我真的希望我能提供有关我的问题的所有必要信息。

我一直在尝试使用长轮询创建“新消息到达通知”。目前,我正在通过站点中每个页面的 window.onLoad 事件发起轮询请求。

在服务器端,我有一个无限循环:

while(1){
 if(NewMessageArrived($current_user))break;
 sleep(10);
}
echo $newMessageCount;

在客户端,我有以下(简化的)ajax 函数:

poll_new_messages(){
 xmlhttp=GetXmlHttpObject();
 //...
 xmlhttp.onreadystatechange=got_new_message_count;
 //...
 xmlhttp.send();
}

got_new_message_count(){
 if (xmlhttp.readyState==4){
  updateMessageCount(xmlhttp.responseText);
  //...
  poll_new_messages();
 }
}

问题是,每次加载页面时,上述循环都会再次开始。结果是每个用户都有多个无限循环,最终导致我的服务器挂起。

*NewMessageArived() 函数查询 MySQL DB 以获取新的未读消息。

*在 php 脚本的开头,我运行 start_session() 以获取 $current_user 值。

我目前是该网站的唯一用户,因此我可以通过将 time() 写入此循环内的文件来轻松调试此行为。我看到的是,该文件在 10 秒内写入的次数不止一次,但只有当我逐页浏览时才会开始写入。

如果有任何其他信息可能有帮助,请告诉我。

谢谢。

I am new to this site, so I really hope I will provide all the necessary information regarding my question.

I've been trying to create a "new message arrived notification" using long polling. Currently I am initiating the polling request by window.onLoad event of each page in my site.

On the server side I have an infinite loop:

while(1){
 if(NewMessageArrived($current_user))break;
 sleep(10);
}
echo $newMessageCount;

On the client side I have the following (simplified) ajax functions:

poll_new_messages(){
 xmlhttp=GetXmlHttpObject();
 //...
 xmlhttp.onreadystatechange=got_new_message_count;
 //...
 xmlhttp.send();
}

got_new_message_count(){
 if (xmlhttp.readyState==4){
  updateMessageCount(xmlhttp.responseText);
  //...
  poll_new_messages();
 }
}

The problem is that with each page load, the above loop starts again. The result is multiple infinite loops for each user that eventually make my server hang.

*The NewMessageArived() function queries MySQL DB for new unread messages.

*At the beginning of the php script I run start_session() in order to obtain the $current_user value.

I am currently the only user of this site so it is easy for me to debug this behavior by writing time() to a file inside this loop. What I see is that the file is being written more often than once in 10 seconds, but it starts only when I go from page to page.

Please let me know if any additional information might help.

Thank you.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

故事还在继续 2024-08-19 01:34:35

我想我找到了解决问题的方法。如果有人能告诉我这是否是 COMET 中使用的技术以及该解决方案的可扩展性,我将不胜感激。

我使用了这样的基于用户的信号量:

$sem_id = sem_get($current_user);
sem_acquire($sem_id);
while(1){
 if(NewMessageArrived($current_user))break;
 sleep(10);
}
sem_release($sem_id);
echo $newMessageCount;

I think I found a solution to my problem. I would appreciate if anyone could tell, if this is the technique that is being used in COMET and how scalable this solution.

I used a user based semaphore like this:

$sem_id = sem_get($current_user);
sem_acquire($sem_id);
while(1){
 if(NewMessageArrived($current_user))break;
 sleep(10);
}
sem_release($sem_id);
echo $newMessageCount;
天气好吗我好吗 2024-08-19 01:34:35

长轮询请求在 30 秒后超时似乎很常见。因此,在 while 循环中,您可以在 30 秒后回显“CLOSE”。

while(!$new_message && $timer < 30){
    $new_message = NewMessageArrived($current_user);
    if(!$new_message) {
        sleep(10);
        $timer += 10;
    }
}
if($newMessageCount) {
    echo $newMessageCount;
} else {
    echo 'CLOSE';
}

在 Javascript 中,您可以侦听 CLOSE。

function poll_new_messages(){
    xmlhttp=GetXmlHttpObject();
    //...
    xmlhttp.onreadystatechange=got_new_message_count;
    //...
    xmlhttp.send();
}

function got_new_message_count(){
    if (xmlhttp.readyState==4){
        if(xmlhttp.responseText != 'CLOSE') {
            updateMessageCount(xmlhttp.responseText);
        }
        //...
        poll_new_messages();
    }
}

现在,无论如何,PHP 都会在 30 秒内返回响应。如果您在页面上使用停留,并且收到 CLOSE,则只需不更新页面上的计数并重新询问即可。

如果用户移动到新页面,您的 PHP 实例将在 30 秒内停止循环,并返回响应。不过,在新页面上,关心该连接的 XHR 不再存在,因此它不会启动另一个循环。

It seems common for long-polling requests to timeout after 30 seconds. So in your while loop you could echo 'CLOSE' after 30 seconds.

while(!$new_message && $timer < 30){
    $new_message = NewMessageArrived($current_user);
    if(!$new_message) {
        sleep(10);
        $timer += 10;
    }
}
if($newMessageCount) {
    echo $newMessageCount;
} else {
    echo 'CLOSE';
}

In the Javascript, you can listen for the CLOSE.

function poll_new_messages(){
    xmlhttp=GetXmlHttpObject();
    //...
    xmlhttp.onreadystatechange=got_new_message_count;
    //...
    xmlhttp.send();
}

function got_new_message_count(){
    if (xmlhttp.readyState==4){
        if(xmlhttp.responseText != 'CLOSE') {
            updateMessageCount(xmlhttp.responseText);
        }
        //...
        poll_new_messages();
    }
}

Now, the PHP will return a response within 30 seconds, no matter what. If you use stays on the page, and you receive a CLOSE, you just don't update the count on the page, and re-ask.

If the user moves to a new page, your PHP instance will stop the loop regardless within 30 seconds, and return a response. Being on a new page though, the XHR that cared about that connection no longer exists, so it won't start up another loop.

白色秋天 2024-08-19 01:34:35

您可以尝试检查 connection_aborted() 定期。请注意,在您编写一些输出并执行 flush() 之前,connection_aborted() 可能无法识别连接实际上已中止的事实。

事实上,只需定期生成一些输出就足以让 php 注意到连接自行关闭,并自动终止您的脚本。

You might try checking connection_aborted() periodically. Note that connection_aborted() might not pick up on the fact that the connection has in fact been aborted until you've written some output and done a flush().

In fact, just producing some output periodically may be sufficient for php to notice the connection close itself, and automatically kill your script.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文