2

我正在使用 stream_select() 但它在几秒钟后返回 0 个描述符,而我的函数在仍有数据要读取时返回。

一个不寻常的事情是,如果您将超时设置为 0,那么我总是将描述符的数量设为零。

$num = stream_select($read, $w, $e, 0);
4

4 回答 4

4

stream_select() 必须在循环中使用

stream_select()函数基本上只是轮询您在前三个参数中提供的流选择器,这意味着它将等到以下事件之一发生:

  • 一些数据到达
  • 或达到超时(使用 $tv_sec 和 $tv_usec 设置)而不获取任何数据。

所以接收 0作为返回值是完全正常的,这意味着当前轮询周期中没有新数据。

我建议将函数放在这样的循环中:

$EOF = false;

do {
    $tmp  = null;
    $ready = stream_select($read, $write, $excl, 0, 50000);

    if ($ready === false ) {
        // something went wrong!!
        break;
    } elseif ($ready > 0) {
        foreach($read as $r) {
            $tmp .= stream_get_contents($r);
            if (feof($r)) $EOF = true;
        }

        if (!empty($tmp)) {
            //
            // DO SOMETHING WITH DATA
            //
            continue;
        }
    } else {
        // No data in the current cycle
    }
} while(!$EOF);

请注意,在此示例中,脚本完全忽略了输入流之外的所有内容。此外,“if”语句的第三部分是完全可选的。

于 2016-05-30T13:18:39.667 回答
3

它返回数字0还是FALSE布尔值?FALSE意味着有一些错误,但零可能只是因为超时或流没有发生任何有趣的事情,你应该做一个新的选择等。

我猜这可能发生在零超时的情况下,因为它会立即检查并返回。此外,如果您阅读有关流选择的 PHP 手册,您将看到有关使用零超时的警告:

使用超时值 0 可以让您即时轮询流的状态,但是,在循环中使用 0 超时值不是一个好主意,因为它会导致您的脚本消耗过多的 CPU 时间。

如果这是一个 TCP 流并且您想要检查连接是否关闭,您应该检查来自freadetc 的返回值以确定其他对等方是否已关闭连接。关于read流数组参数:

将监视读取数组中列出的流以查看字符是否可用于读取(更准确地说,查看读取是否不会阻塞 - 特别是,流资源也在文件末尾准备好,在这种情况下fread() 将返回一个长度为零的字符串)。

于 2012-08-03T17:53:23.453 回答
0

http://www.php.net/stream_select

由于当前 Zend 引擎的限制,不可能将像 NULL 这样的常量修饰符直接作为参数传递给希望通过引用传递此参数的函数。而是使用临时变量或表达式,最左边的成员是临时变量:

<?php $e = NULL; stream_select($r, $w, $e, 0); ?>
于 2012-08-03T16:08:19.140 回答
0

我有一个类似的问题,这是由底层套接字超时引起的。

例如。我创建了一些流

$streams = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP);

然后分叉,并使用如下块

  stream_set_blocking($pipes[1], 1);
  stream_set_blocking($pipes[2], 1);
  $pipesToRead = array($pipes[1], $pipes[2]);

  while (!feof($pipesToRead[0]) || !feof($pipesToRead[1])) {
     $reads = $pipesToRead;
     $writes = null;
     $excepts = $pipesToRead;
     $tSec = null;
     stream_select($reads, $writes, $excepts, $tSec);
     // while it's generating any kind of output, duplicate it wherever it
     // needs to go
     foreach ($reads as &$read) {
        $chunk = fread($read, 8192);
        foreach ($streams as &$stream)
           fwrite($stream, $chunk);
     }
  }

忽略那里可能出现的其他问题,忽略了我$tSec对 stream_select 的参数,并且“流”将在 60 秒不活动后超时并产生 EOF。

如果我在创建流后添加以下内容

stream_set_timeout($streams[0], 999);
stream_set_timeout($streams[1], 999);

然后我得到我想要的结果,即使基础流上没有活动超过 60 秒。

我觉得这可能是一个错误,因为我不希望在底层流上不活动 60 秒后出现 EOF,并且我不想插入一些任意大的值以避免在我的进程空闲时达到超时一段时间。

此外,即使 60 秒的超时仍然存在,我认为它应该只是在我的stream_select()通话中超时并且我的循环应该能够继续。

于 2018-11-20T02:53:55.973 回答