【问题标题】:How to ensure that PHP SSE doesn't "disconnect"如何确保 PHP SSE 不会“断开连接”
【发布时间】:2017-12-13 18:46:50
【问题描述】:

我的网站上运行了一个小的额外聊天室服务,我正在使用 SSE 不断向客户发送聊天更新,但是,由于断开连接和自动重新连接,事件源的消息似乎不断触发,或者至少是这样我在网上浏览了几个小时后才发现。

这是我的 PHP

header("Content-Type: text/event-stream");
header('Cache-Control: no-cache');

$matchid = $_GET["curMatch"];

$root = $_SERVER['DOCUMENT_ROOT'];
$filename = $root . "/pickup/chat/chatroom.txt";
$lastMod = NULL;

while(true){
    if(connection_status() != CONNECTION_NORMAL) {
        $conn->close();
        break;
    }

    clearstatcache();   

    $checker = filemtime($filename);
    if($checker != $lastMod){       
        $lastMod = $checker;
        echo "data: 1\n\n";
        ob_end_flush();
        flush();

        usleep(400);
    }   
}

这里是 jQuery

matchID = 1;
if(typeof(EventSource) !== "undefined") {       
    var chatSource = new EventSource("/pickup/php/check-chat-sse.php?curMatch="+matchID);
    chatSource.onmessage = function(event) {
        var dt = new Date();
        var time = dt.getHours() + ":" + dt.getMinutes() + ":" + dt.getSeconds();
        console.log("Chat Server responded: @" +time);          
        console.log(event.data);            

        $.ajax({
            type: "POST",
            url: "/pickup/chat/"+matchID+".txt",
            datatype: 'text',
            success: function (response) {     
                $("#chat-content").html(response);
            }
        });
        if (hidden == true){
            $("#chat-toggle").addClass("newMessage");
        }
    }   
}

最后,控制台日志

聊天服务器回复:@20:36:54 聊天服务器回复:@20:37:24 聊天服务器回复:@20:38:52

这会导致每次服务器重新连接时都会添加 .newMessage 类,从而使用户在没有新消息时认为有新消息。我也在 SSE 上运行一个更复杂的系统,也遇到同样的问题,所以如果我能找到解决方案,一切都会更好。

那么我如何确保用户在不创建反向 AJAX 轮询的情况下不会断开连接并重新连接,因为这是大多数人的建议。任何建议或帮助将不胜感激。

【问题讨论】:

    标签: php server-sent-events


    【解决方案1】:

    当客户端浏览器断开连接时,php 进程将被 Apache 自动关闭(我假设您使用的是 Apache,因为您没有指定它)。所以你的 while() 循环的前四行是不需要的,这可能会导致问题。 (但是,如果您确实保留了它们,请开始记录 connection_status() 的返回值,以便您知道它关闭连接的原因。)

    但是,由于您的重新连接每 30 秒发生一次,我的猜测是 PHP 脚本只是超时了。尝试添加:

    set_time_limit(0);
    

    在脚本的最顶部。 (或者,将 set_time_limit(10) 之类的内容放在您的 while 循环中是一种更复杂的方法,可以捕获真正的锁定代码。)

    如果不是这样,我猜你需要发送一些保持活动的消息。 (我的书,带有 HTML5 SSE 的数据推送应用程序,详细介绍了如何实现它。)


    顺便说一句,您是否考虑过在 SSE 正文中发送实际的聊天消息,而不是仅仅发送“有新数据”消息然后要求客户端为他们做额外的请求?整体上应该会更有效率。

    【讨论】:

    • 这似乎已经成功了,我处理文本文件的加载浏览器端的原因是如果服务器响应但文本文件仍然相同,则进行一些其他负载测试,现在这个已修复,我会让服务器发送数据。您是否介意解释为什么 while 循环内的 set_time_limit(10) 更复杂。直到一周前,我还在使用 AJAX 轮询,所以我对 SSE 还是很陌生。我会尽快买那本书。
    • @RuanKruger set_time_limit 旨在捕获程序错误,例如无限循环,或等待永远不会释放的锁等。大多数php脚本只需要运行一秒钟,所以默认的 30s 是一个很好的缓冲。在脚本顶部将其设置为零会关闭此安全网功能:通过将其设置在循环内,您可以恢复该安全网。请参阅php.net/set_time_limit 了解更多信息。
    猜你喜欢
    • 1970-01-01
    • 2019-12-07
    • 1970-01-01
    • 1970-01-01
    • 2012-07-15
    • 1970-01-01
    • 2021-12-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多