PHP事件源继续执行

时间:2012-10-16 15:53:09

标签: php javascript html5 server-sent-events

我开始使用JavaScript EventSource对象在HTML5中使用push。我对PHP的工作解决方案非常满意:

$time = 0;
while(true) {
    if(connection_status() != CONNECTION_NORMAL) {
        mysql_close()
        break;
    }
    $result = mysql_query("SELECT `id` FROM `table` WHERE UNIX_TIMESTAMP(`lastUpdate`) > '".$time."'");
    while($row = mysql_fetch_array($result)) {
        echo "data:".$row["id"].PHP_EOL;
        echo PHP_EOL;
        ob_flush();
        flush();
    }
    $time = time();
    sleep(1);
}

但突然间我的WebApp再也无法访问MySQL错误“连接太多”。

事实证明,在JavaScript中关闭事件源后,MySQL连接没有关闭:

window.onload = function() {
    sse = new EventSource("push.php");
    sse.onmessage = function(event) {
        console.log(event.data.split(":")[1]);
    }
}
window.onbeforeunload = function() {
    sse.close();
}

所以我猜PHP脚本不会停止执行。在客户端连接断开之前,有没有办法调用函数(如die();)?为什么我的脚本在EventSource上调用.close();后终止了?!

感谢您的帮助! -

6 个答案:

答案 0 :(得分:5)

首先关闭:当您将代码包装在一个巨大的while(true)循环中时,您的脚本将永远不会终止。当你的脚本“用尽代码执行”时,与数据库的连接将被关闭,但由于你已经写了一个死锁,这种情况不会发生......永远不会发生。
这不是一个EventSource问题,只是做它应该做的事情。老实说,真的,可悲的是你的错。

事情是:用户连接到您的站点,并实例化EventSource对象。建立与服务器的连接,并请求返回值push.php。您的服务器按照要求执行操作并运行脚本,即-again-只是一个死锁。没有错误,只要php.ini允许它运行,它就可以继续运行。 .close()方法确实取消了输出流(或者更确切地说它应该),但是你的脚本忙于执行无限循环或休眠。假设由于客户端断开连接而停止脚本就像假设任何客户端可能干扰服务器所做的那样。在安全方面,这将是可能发生的最坏情况。现在,回答你的实际问题:导致问题的原因是什么,如何修复?答案: HEADERS

查看this little PHP example:脚本不是在服务器端保持活动状态(通过无限循环),而是通过设置正确的标头。

正如旁注:请尽快抛弃mysql_*,暂时弃用(最后),使用PDOmysqli_*。老实说,这并不难。

答案 1 :(得分:3)

我有完全相同的问题,据我所知,原因是apache没有终止php脚本,直到我试图再次通过关闭的套接字连接写入数据。

我的数据库中没有任何更改,因此没有输出。

要解决这个问题,我只需在我的while循环中回显一个事件源注释,如:

echo ": heartbeat\n\n";
ob_flush();
flush();

如果套接字连接已关闭,则会导致脚本终止。

答案 2 :(得分:0)

您可能想尝试将其添加到循环中:

if(connection_status() != CONNECTION_NORMAL)
{
    break;
}

但是当客户端断开连接时,php应该停止。

答案 3 :(得分:0)

1

window.onbeforeunload = function() {
    sse.close();
}

这不是必需的,EventSource将在页面卸载时关闭。

  1. 即使你找不到在PHP上检测断开连接的客户端的方法,你也可以在N秒后停止执行,EventSource会自动重新连接。
  2. http://www.php.net/manual/ru/function.connection-aborted.php 这个页面上的评论说,你应该在connection_status之前使用“flush” 无论如何,你应该在N秒后断开连接,因为你无法检测到“坏”断开连接。

    3。 echo“retry:1000 \ n”; //使用它来告诉EventSource以ms为单位的重新连接延迟

答案 4 :(得分:0)

$time = 0;
while(true) { 
    if(connection_status() != CONNECTION_NORMAL) {
        mysql_close()
        break;
    }
    $result = mysql_query("SELECT id FROM table WHERE UNIX_TIMESTAMP(lastUpdate) > '".$time."'");
    while($row = mysql_fetch_array($result)) {
        $rect[] = $row;
    }
    for($i-0;$i echo "data:".implode('',$disp)."\n\n"; $time = time(); sleep(1);
}

答案 5 :(得分:0)

正如Elias Van Ootegem指出的那样,您的脚本永远不会终止,因此您有一堆MySQL连接处于活动状态。更值得一提的是,你有一大堆资源以PHP循环的形式运行,并且看不到尽头!

不幸的是,保持不是“标题”的解决方案。在此链接referenced by Elias的示例中,php脚本终止,客户端javascript实际上必须重新打开连接。您可以使用以下代码

进行测试
source.addEventListener('open', function(e) {
  // Connection was opened.
    console.log("Opening new connection");
}, false);

如果你在github上关注他的例子,在实现中作者实际上使用了一个在X秒后终止的循环。 See the do loop and comments at bottom of the script.

解决方案是为您的循环提供生命周期。

通过定义循环限制,IE X itterations或在触发循环结束的X时间或die();之后,您将使其成为如果客户端断开连接,那么如何限制一个脚本将保持活动状态。如果客户在X时间后仍然在那里,他们将只是重新连接。