当尝试写入客户端时,消息会被缓冲,在某些情况下,它根本就没有被写入。
当前状态:
当我远程登录到服务器时,Server Ready:
消息很容易按预期打印。
当我发送随机数据(“关闭”除外)时,服务器的终端每秒都很好地显示进度,但是客户端输出会等到所有睡眠后,然后立即打印出来。
最重要的是,当发送“关闭”时,它只是等待强制性的第二个,然后在客户端没有任何写出的情况下关闭。
目标:
我的主要目标是在关闭连接之前将快速消息写入客户端。
CODE:
// server.php
$loop = React\EventLoop\Factory::create();
$socket = new React\Socket\Server($loop);
$socket->on('connection', function ($conn)
{
$conn->write("Server ready:\n");
$conn->on('data', function ($data) use ($conn)
{
$data = trim($data);
if( $data == 'close')
{
$conn->write("Bye\n");
sleep(1);
$conn->close();
}
for ($i = 1; $i<5; $i++) {
$conn->write(". ");
echo '. ';
sleep(1);
}
$conn->write(".\n");
echo ".\n";
$conn->write("You said \"".$data."\"\n");
});
});
$socket->listen(1337, '127.0.0.1');
$loop->run();
概要
为什么我不能在关闭前给客户写任何东西?
答案 0 :(得分:6)
您遇到的问题是因为您忘记了驱动ReactPHP的事件循环。我最近在构建服务器时遇到了这个问题,在遵循代码后,我发现了两件可以帮助你解决问题的事情。
$conn->end('msg');
如果您遵循此代码链,行为就会变得清晰;首先它基本上写入连接,就像你运行$conn->write('msg');
但是它为full-drain
事件注册一个新的事件处理程序,这个处理程序简单地调用$conn->close();
;仅在写缓冲区完全清空时才调度full-drain
事件。所以你可以看到end的使用,只需在关闭连接之前等待写入。 drain
和full-drain
仅在写入流后调度。写缓冲区完全为空时发生full-drain
。在写缓冲区清空超过其drain
后调度softLimit
,默认情况下为{20}字节。
$conn->write('msg')
只将字符串添加到写缓冲区;它实际上并没有写。事件循环需要在给定时间写入之前运行。您对sleep()
的使用不正确,因为这会阻止该行的调用。作为反应,你不想阻止任何代码执行。如果您完成了一项任务,那么让您的函数返回,代码执行返回到反应主事件循环。如果您希望在某些时间间隔内运行,或者只是在循环的下一次迭代中运行,则可以使用$loop->addTimer($seconds, $callback)
,$loop->addPeriodicTimer($seconds, $callback)
,{{1}为主事件循环安排回调}或$loop->nextTick($callback)
最终,这是因为你在编程而没有承认我们仍然处于阻塞线程中。你的代码阻塞,阻止整个反应事件循环,反过来阻止所有反应为你做的事情。将处理时间放回循环以确保它可以执行排队的读/写操作。您只需要循环迭代就可以使写缓冲区开始清空(取决于缓冲区的大小,它可能会也可能不会全部写出来)
如果您的目标只是修复连接关闭位,请将您的通话切换为$loop->futureTick($callback)
,而不是写入 - &gt;关。但是我相信你打印圆点的另一个循环也不会像我认为你期望/希望它的工作方式那样。由于它的目的不是很明确,如果你能告诉我你的目标是什么,我也可以帮助你重组这一步骤。