PHP中的stream_select()问题

时间:2012-08-03 16:00:28

标签: php timeout

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

不同寻常的是,如果将时间设置为0,那么我总是将描述符的数量设置为零。

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

4 个答案:

答案 0 :(得分:3)

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

我猜这可能会发生零超​​时,因为它会检查并立即返回。此外,如果您阅读PHP manual about stream-select,您将看到有关使用零超时的警告:

  

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

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

  

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

答案 1 :(得分:2)

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”语句的第三部分仅用于演示。

答案 2 :(得分:0)

http://www.php.net/stream_select

  

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

<?php $e = NULL; stream_select($r, $w, $e, 0); ?>

答案 3 :(得分: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);
     }
  }

关于那里可能有其他问题的问题,我对stream_select的$tSec参数被忽略,并且在闲置60秒后,“ stream”将超时并产生EOF。

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

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

然后,即使底层流上没有任何活动超过60秒,我也得到了想要的结果。

我觉得这可能是一个错误,因为我不希望底层流不活动60秒后再看到EOF,并且我不想插入任意大的值来避免超时,如果我进程空闲了一段时间。

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