我正在使用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返回有效的元数据数组,即使客户端已断开连接。
答案 0 :(得分:0)
自从问这个问题以来已经有一段时间了,但是我发现对我有用的是使用SplObjectStorage()作为连接池。这是一个(外部)没有索引的集合。它对于连接非常有效。
我认为最初问题的根源在于您正在取消设置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);
}
}
});