issue with stream_select() in PHP

萝らか妹 提交于 2020-02-02 09:41:08

问题


I am using stream_select() but it returns 0 number of descriptors after few seconds and my function while there is still data to be read.

An unusual thing though is that if you set the time out as 0 then I always get the number of descriptors as zero.

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

回答1:


stream_select() must be used in a loop

The stream_select() function basically just polls the stream selectors you provided in the first three arguments, which means it will wait until one of the following events occur:

  • some data arrives
  • or reaches timeout (set with $tv_sec and $tv_usec) without getting any data.

So recieving 0 as a return value is perfectly normal, it means there was no new data in the current polling cycle.

I'd suggest to put the function in a loop something like this:

$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);

Please note that in this example, the script totally ignores everything aside from the input stream. Also, the third section of the "if" statement is completely optional.




回答2:


Does it return the number 0 or a FALSE boolean? FALSE means there was some error but zero could be just because of timeout or nothing interesting has happen with the streams and you should do a new select etc.

I would guess this could happen with a zero timeout as it will check and return immediately. Also if you read the PHP manual about stream-select you will see this warning about using zero timeout:

Using a timeout value of 0 allows you to instantaneously poll the status of the streams, however, it is NOT a good idea to use a 0 timeout value in a loop as it will cause your script to consume too much CPU time.

If this is a TCP stream and you want to check for connection close you should check the return value from fread etc to determine if the other peer has closed the conneciton. About the read streams array argument:

The streams listed in the read array will be watched to see if characters become available for reading (more precisely, to see if a read will not block - in particular, a stream resource is also ready on end-of-file, in which case an fread() will return a zero length string).




回答3:


http://www.php.net/stream_select

Due to a limitation in the current Zend Engine it is not possible to pass a constant modifier like NULL directly as a parameter to a function which expects this parameter to be passed by reference. Instead use a temporary variable or an expression with the leftmost member being a temporary variable:

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



回答4:


I have a similar issue which is caused by the underlying socket timeout.

Eg. I create some streams

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

Then fork, and use a block such as the following

  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);
     }
  }

Glossing over what other things might be wrong there, my $tSec argument to stream_select is ignored, and the "stream" will timeout after 60 seconds of inactivity and produce an EOF.

If I add the following after creating the streams

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

Then I get the result I desire, even if there's no activity on the underlying stream for longer than 60 seconds.

I feel that this might be a bug, because I don't want that EOF after 60 seconds of inactivity on the underlying stream, and I don't want to plug in some arbitrarily large value to avoid hitting the timeout if my processes are idle for some time.

In addition, even if the 60 second timeout remains, I think it should just timeout on my stream_select() call and my loop should be able to continue.



来源:https://stackoverflow.com/questions/11799252/issue-with-stream-select-in-php

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!