3

我开始使用 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();在客户端连接断开之前调用函数(如)?为什么我的脚本在调用.close();EventSource 后没有终止?!

感谢帮助!——</p>

4

6 回答 6

6

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

问题是:用户连接到您的站点,并且EventSource对象被实例化。建立到服务器的连接并请求返回值的push.php请求。您的服务器按要求执行并运行脚本,这 - 再次 - 只不过是死锁。没有错误,所以只要 php.ini 允许它运行,它就可以继续运行。该.close()方法确实取消了输出流(或者应该取消),但是您的脚本正忙于执行其无限循环或休眠。假设由于客户端断开连接而停止脚本就像假设任何客户端都可能干扰服务器所做的事情。安全方面,这将是可能发生的最糟糕的情况。现在,回答您的实际问题:是什么导致了问题,如何解决?
答案:标题

看看这个 PHP 小例子:脚本不是在服务器端保持活动(通过无限循环),而是通过设置正确的标头。

就像旁注一样:请mysql_*尽快放弃,它正在被弃用(最终),使用PDOmysqli_*代替。老实说,这并不难。

于 2012-10-16T16:20:45.700 回答
4

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

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

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

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

如果套接字连接关闭,这将导致脚本终止。

于 2015-03-22T22:56:03.277 回答
0

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

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

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

于 2012-10-16T15:57:15.997 回答
0

1.

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

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

  1. 即使在 PHP 上找不到检测断开客户端的方法,也可以在 N 秒后停止执行,EventSource 会自动重新连接。

http://www.php.net/manual/ru/function.connection-aborted.php 此页面上的评论说,无论如何,你应该在 connection_status 之前使用“flush”,你应该在 N 秒后断开连接,因为你无法检测到“坏”断开连接。

3. 回显“重试:1000\n”;// 用它来告诉 EventSource 重新连接延迟(以 ms 为单位)

于 2012-10-19T08:07:51.943 回答
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);
}
于 2014-03-22T09:28:16.380 回答
0

正如 Elias Van Ootegem 指出的那样,您的脚本永远不会终止,因此您有一堆 MySQL 连接处于活动状态。更令人担忧的是,您有大量资源以 PHP 循环的形式使用,而且看不到尽头!

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

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

如果您按照他在 github 上的示例,在实现中作者实际上使用了一个在 X 秒后终止的循环。请参阅脚本底部的 do 循环和注释。

解决方案是给你的循环一个生命周期。

By defining a limit to the loop, IE X itterations or after X amount of time to trigger the end of the loop or die();, you will make it so that if the client disconnects there is a limit to how long a script will remain active. If the client is still there after X amount of time, they will simply re connect.

于 2016-01-22T04:36:52.980 回答