You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 22:20:19