PHP中的stream_select()问题

PHP中的stream_select()问题,php,timeout,Php,Timeout,我正在使用stream_select(),但它在几秒钟后返回0个描述符,并在仍有数据要读取时返回我的函数 然而,一件不寻常的事情是,如果将超时设置为0,那么我总是将描述符的数量设置为0 $num = stream_select($read, $w, $e, 0); 由于当前Zend引擎的限制,无法 将常数修饰符(如NULL)作为参数直接传递给 函数,该函数期望通过引用传递此参数。 而是使用临时变量或最左边的表达式 作为临时变量的成员: 它是否返回数字0或FALSE布尔值FALSE表示出现了一

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

然而,一件不寻常的事情是,如果将超时设置为0,那么我总是将描述符的数量设置为0

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

由于当前Zend引擎的限制,无法 将常数修饰符(如NULL)作为参数直接传递给 函数,该函数期望通过引用传递此参数。 而是使用临时变量或最左边的表达式 作为临时变量的成员:


它是否返回数字
0
FALSE
布尔值
FALSE
表示出现了一些错误,但零可能只是因为超时或流没有发生任何有趣的事情,您应该执行新的选择等操作

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

使用超时值0允许您即时轮询流的状态,但是,在循环中使用0超时值不是一个好主意,因为这将导致脚本占用太多CPU时间

如果这是一个TCP流,并且您想要检查连接是否关闭,那么您应该检查
fread
等的返回值,以确定另一个对等方是否关闭了连接。关于
read
streams数组参数:

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

必须在循环中使用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”语句的第三部分是完全可选的。

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

我创建了一些流

$streams = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP);
然后fork,并使用如下所示的块

  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);
     }
  }
忽略其他可能出错的地方,stream_select的my
$tSec
参数将被忽略,“stream”将在不活动60秒后超时并产生EOF

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

stream_set_timeout($streams[0], 999);
stream_set_timeout($streams[1], 999);
然后我得到了我想要的结果,即使底层流上没有活动超过60秒

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


此外,即使60秒超时仍然存在,我认为它应该在我的
stream_select()
调用上超时,我的循环应该能够继续。

没有任何其他信息,我建议使用strace运行脚本并检查基础select SYSCALL的返回值。进一步读取
tv_sec
参数至
stream_select
()显示,当它为“null”时,函数返回的唯一方法是在其中一个流上发生事件。如果PHP不会无限期地挂起,这意味着超时值必须是这样一个事件,因此我对这种行为不会感到惊讶。我将尝试在
tv\u sec
中传递一个值,看看这是否意味着我可以删除对
stream\u set\u timeout
的调用。。。
stream_set_timeout($streams[0], 999);
stream_set_timeout($streams[1], 999);