ReactPHP - 关闭断开的连接

时间:2016-12-19 10:07:34

标签: php sockets reactphp

我正在使用ReactPHP作为TCP侦听器组件。该组件侦听传入连接并与它们交换数据。当客户端与侦听器连接/断开连接时,$ connections数组会更新。

$loop = React\EventLoop\Factory::create();
$connections = [];
$socket = new React\Socket\Server($loop);
$socket->on('connection', function ($conn) use($loop, $db){
    global $connections;
    $connections[] = $conn;
    $conn->on('data', function ($data) use ($conn,$loop, $db) {
        global $connections;
        // ...
        // ...
        $conn->on('close', function ($conn) use($loop, $db){
            global $connections;
            if(($key = array_search($conn, $connections, true)) !== FALSE) {
                unset($connections[$key]);
            }   
        });
});
$socket->listen(16555, '127.0.0.1');
$loop->run();

如果客户通过telnet连接,请关闭'将被发出,所以我可以从$ connection数组中删除关闭的连接。 但是,我也遇到了一些连接到我的监听器的设备的问题。如果我关闭设备'关闭'不会发出。 我试图用定期计时器解决问题:

$loop->addPeriodicTimer(10, function () use($db, $loop){
    global $connections;
    foreach($connections as $c) {
        $remoteAddress = $c->getRemoteAddress();
        $metaData = @stream_get_meta_data($c->stream);
        if(!$metaData) {
            if(($key = array_search($c, $connections, true)) !== FALSE) {
                unset($connections[$key]);
            }   
        }
    }
});

但似乎它不够可靠。函数stream_get_meta_data返回有效的元数据数组,即使客户端已断开连接。

1 个答案:

答案 0 :(得分:0)

自从问这个问题以来已经有一段时间了,但是我发现对我有用的是使用SplObjectStorage()作为连接池。这是一个(外部)没有索引的集合。它对于连接非常有效。

documentation

我认为最初问题的根源在于您正在取消设置foreach中的元素,该元素不会自动更新键,并且最终可能导致对象混乱。

为了使用代码迭代一个集合(或数组),在循环中您可能要删除一个或多个元素,使用 clone 会更安全。

所以您的游泳池在哪里

$connections_pool = new SplObjectStorage();

要迭代(按照您的原始请求)

$loop->addPeriodicTimer(10, function () use($db, $loop){
    global $connections_pool;
    foreach(clone($connections_pool) as $c) {
        $remoteAddress = $c->getRemoteAddress();
        $metaData = @stream_get_meta_data($c->stream);
        if(!$metaData) {
            $connections_pool->offsetUnset($c);            
        }
    }
});