2009-11-23 129 views
2

我是新来这个网站,所以我真的希望我会提供所有关于我的问题的必要信息。Ajax长轮询(彗星)+ PHP上lighttpd v1.4.22多个实例问题

我一直在尝试使用长轮询来创建“新邮件到达通知”。目前,我正在通过我网站中每个页面的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秒内被写入的次数比一次多,但是只有当我一页一页地进行时才会启动。

如果有任何其他信息可能有帮助,请让我知道。

谢谢。

回答

0

您可能会尝试定期检查connection_aborted()。请注意,connection_aborted()可能没有提及事实:连接实际上已被中止,直到你写了一些输出并完成了flush()

事实上,只是定期产生一些输出可能足以让php注意到连接本身并关闭,并自动杀死脚本。

+0

谢谢您的回答。每次我回复一些数据时,这个解决方案不会触发ajax响应函数吗?使此解决方案成为常规轮询而不是长轮询。 – fibonacci 2009-11-23 21:20:00

1

长轮询请求在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中,你可以听的关闭。

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不再存在,所以它不会启动另一个循环。

+0

谢谢你的回答。我的ajax函数poll_new_messages()有一个响应处理程序got_new_message_count()函数。响应处理程序在触发时调用poll_new_messages()。 因此,在这两种情况下,我将最终得到相同数量的无限循环或没有响应处理函数(如果在CLOSE上,我将不再调用poll_new_messages)。 – fibonacci 2009-11-23 21:27:54

+0

在Javascript中,你可以检查“CLOSE”,如果是的话,重新调查。否则,显示计数。如果用户更改页面,当循环超时时,它不会从您的处理程序重新启动,因为处理程序不再侦听(从该页面)。 – seanmonstar 2009-11-24 00:05:39

+0

当另一个$ newMessageCount再次到达时,会发生什么情况,此事件没有处理程序?您提出的解决方案只会通知用户一次(如果用户不会更改页面并再次开始长轮询)。 – fibonacci 2009-11-24 06:43:13

1

我想我找到了解决我的问题。如果有人能够告诉我,如果这是在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;