2

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

4 Answers 4

4

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.

Sign up to request clarification or add additional context in comments.

Comments

3

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).

Comments

0

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

1 Comment

without any additional info, I'd suggest to run the script with strace and check what's the return value of the underlying select syscall
0

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.

1 Comment

Further reading of the tv_sec argument to stream_select (php.net/manual/en/function.stream-select.php) shows that when it's "null", the only way for the function to return is for an event to happen on one the streams. If PHP isn't going to hang indefinitely, this means the timeout value needs to be one such event, so I should not be surprised by this behaviour. I will try passing a value in tv_sec to see if it means I can remove the call to stream_set_timeout...

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.