PHP+ReactSocket循环发送TCP消息异常:仅建立连接无消息
循环读取stdin发送TCP消息时服务器收不到内容的问题
编写PHP脚本通过循环读取标准输入发送TCP消息,服务器仅能收到连接请求,无法接收消息;移除循环后功能正常。使用telnet可正常发送消息。
问题代码示例
#!/bin/php <?php use React\Socket\ConnectionInterface; use React\Socket\TcpConnector; require dirname(__DIR__) . '/vendor/autoload.php'; while (true) { $line = trim(fgets(STDIN)); echo "try to send $line\n"; try { $client = new TcpConnector(); $client ->connect('tcp://127.0.0.1:8080') ->then( function (ConnectionInterface $connection) use ($line) { echo "fulfilled\n"; $connection->write($line); $connection->end(); }, function () { echo "rejected\n"; }, function () { echo "onProgress\n"; } ); } catch (Throwable $e) { echo $e->getMessage(); } // break; // 取消注释后正常工作 }
脚本运行输入
./console.php foo try to send foo bar try to send bar
服务器端输出
new connection: tcp://127.0.0.1:40936 new connection: tcp://127.0.0.1:40944
移除循环后的运行情况
./console.php foo try to send foo fulfilled
问题原因与解决方案
原因
ReactPHP是异步非阻塞框架,所有IO操作依赖内部事件循环执行。但同步的while(true)循环会一直阻塞主线程,导致React的事件循环无法启动,连接成功后的回调(write和end操作)根本没有执行机会,因此服务器只收到连接请求,收不到消息内容。
解决方法
改用ReactPHP提供的异步方式处理stdin输入,让事件循环正常运行。以下是修正后的代码:
#!/bin/php <?php use React\Socket\ConnectionInterface; use React\Socket\TcpConnector; use React\Stream\ReadableResourceStream; use React\EventLoop\Factory; require dirname(__DIR__) . '/vendor/autoload.php'; // 创建React事件循环 $loop = Factory::create(); // 异步监听stdin输入 $stdin = new ReadableResourceStream(STDIN, $loop); // 初始化TCP连接器(复用实例,无需每次创建) $connector = new TcpConnector($loop); // 监听stdin的数据输入事件 $stdin->on('data', function ($data) use ($connector) { // 拆分输入的多行内容 $lines = explode("\n", trim($data)); foreach ($lines as $line) { if (empty($line)) continue; echo "try to send $line\n"; $connector ->connect('tcp://127.0.0.1:8080') ->then( function (ConnectionInterface $connection) use ($line) { echo "fulfilled\n"; $connection->write($line); $connection->end(); }, function () { echo "rejected\n"; } ); } }); // 启动事件循环 $loop->run();
说明
- 用
ReadableResourceStream异步监听stdin,避免阻塞主线程 - 复用
TcpConnector实例,无需每次循环创建新对象 - 启动React的事件循环
$loop->run(),让所有异步操作正常执行
内容的提问来源于stack exchange,提问作者atmacola
相关产品推荐
相关产品推荐

