gpt4 book ai didi

php - 套接字服务器 + 事件源魔术断开

转载 作者:行者123 更新时间:2023-12-04 23:25:33 25 4
gpt4 key购买 nike

我已经成功实现了下一个方案:一个 php 套接字服务器脚本,它向所有连接的客户端脚本广播消息,并且这些客户端脚本由前端脚本上的事件源监听。所以,基本上,方案是:server.php -> client.php -> front.php

但是我一直在努力处理 client.php 中的这一部分:

while(TRUE)
{
$read = array();
$read[] = $client_socket;

if( socket_select($read, $write, $except, 10) === FALSE ){
$errorcode = socket_last_error();
$errormsg = socket_strerror($errorcode);
file_put_contents("select_result.log", "Could not listen on socket : [$errorcode] $errormsg".PHP_EOL);
}

if( !($client_message = @socket_read($client_socket, 1024)) ){
$errorcode = socket_last_error();
$errormsg = socket_strerror($errorcode);
file_put_contents("read_result.log", "Couldn't read socket: [$errorcode] $errormsg".PHP_EOL, FILE_APPEND);
}

if($client_message == FALSE) {
$client_message = "event: keep_alive" . PHP_EOL
. "data: keep_alive" . PHP_EOL . PHP_EOL;
}

echo $client_message;

if( ob_get_level() > 0 ) ob_flush();
flush();
}

当在浏览器中打开 front.php 脚本(使用 event-source)时,它工作正常,但是它也以某种方式检测到断开连接,当我在浏览器窗口中关闭或重新加载 front.php 时。以下是检测断开连接的 server.php 的一部分:

if( !($client_input = @socket_read($client, 1024))) {
$errorcode = socket_last_error();
$errormsg = socket_strerror($errorcode);
echo "$errorcode".PHP_EOL;
}

if ( $client_input === FALSE ) {
$socket_key = array_search($client, $client_sockets);
socket_getpeername($client, $client_address, $client_port);
socket_close($client);//?!!!
unset($client_sockets[$socket_key]);
echo "[$client_address : $client_port disconnected]".PHP_EOL;
}

如您所见,当无法从客户端读取数据时会发生这种情况。理论上,当我关闭 front.php 时,client.php 应该仍然在后台无限循环工作,因为我没有任何循环中断,但是 - 惊喜! - 它停止了。通过实验,我发现这是由于 ob_flush() 函数而发生的。注释时,server.php 未检测到断开连接(浏览器窗口关闭/重新加载)。怎么会这样?根据手册,ob_flush() 不返回任何值。也没有检测到错误……我不知道该怎么想,也找不到为什么会这样。请帮忙。

最佳答案

我假设您正在使用 Apache 或 client.php 前面的东西。当您的 front.php 运行 var es = new EventSource('client.php') 时,会在浏览器和 Apache 之间创建一个专用的 TCP/IP 套接字。 Apache 运行 PHP,告诉它加载并运行 client.php。 (然后 client.php 创建一个套接字来监听来自 server.php 的消息。)

当浏览器关闭时(或者您调用 es.close(),或者由于某种原因浏览器和 Apache 之间的套接字连接丢失),Apache 将立即(*)关闭PHP 进程(运行 client.php 的进程)。当该 PHP 进程消失时,client.php 和 server.php 之间的套接字将关闭(立即关闭,或者下次 server.php 尝试读取/写入它时)。

*:通常是“立即”。有时,如果套接字没有完全关闭,它可能会停留一小会儿(几秒钟,绝不会超过一分钟)。

我认为您的ob_flush() 观察有点误会;我的猜测是,由于不调用 ob_flush(),缓冲区中有东西卡住,这意味着 Apache 使 PHP 进程保持事件状态,直到某个超时到期。顺便说一句,我使用了 @ob_flush();@flush() 习惯用法; ob_flush() 之前的 @ 基本上在做您的 ob_get_level() 检查正在做的事情(但我依稀记得听说有一种情况检查并不总是可靠的)。

关于php - 套接字服务器 + 事件源魔术断开,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20613136/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com