Home » Networking » Net_Socket » Bug #1427
Net_Socket::eof() hangs due to use of feof()
Details
| Submitted | 2004-05-17 18:39 UTC |
|---|---|
| From | tomsommer at php dot net |
| Status | Bogus |
| Package | Net_Socket |
| PHP Version | 4.3.6 |
| OS | Linux Fedora Core 1 |
| Roadmaps | (Not assigned) |
Comments
[2004-05-17 18:39 UTC] tomsommer at php dot net
Description:
------------
As commented on in the php manual, the feof() php function is exteremly slow when using blocking sockets.
I discovered this annoyance while playing with Net_IMAP and traced the problem to Net_Socket::eof().
I found this workaround to the eof() function withing Net_Socket:
function eof()
{
if ($this->isBlocking()) {
$status = $this->getStatus();
return $status['eof'];
}
return (is_resource($this->fp) && feof($this->fp));
}
Which seems to do the trick
[2004-07-20 15:31 UTC] php at alterego dot dp dot ua
Here is what that comment in the PHP manual says:
> I found feof() to be a slow function when using
> a non-blocking connection. The function
> stream_get_meta_data() returns much quicker
> and has a return field 'eof'.
As you can see, it says 'non-blocking', as opposed to 'blocking' in this bug report. So what exactly were you fixing?
There is also a hidden danger in this fix. get_socket_status (which is deprecated alias to stream_get_meta_data) official documentation says:
> Note that for socket streams eof member can be TRUE
> even when unread_bytes is non-zero. To determine if
> there is more data to be read, use feof() instead of
> reading this item.
I've never ran into such situation, but I just believe it can happen. In such case eof will return true, while still there's data in the buffer. So at the very least check should be extended:
return $status['eof'] && ($status['unread_bytes'] == 0);
As it became very interesting, I made further investigation and traced down feof() behavior in the PHP sources. It showed that feof() logic is exactly the same as in this proposed fix with a small, but significant difference: when there is no data in the buffer and stream->eof was not set by another stream function before, it calls _php_network_is_stream_alive() function to find out if the socket is still alive. That function starts with an interesting comment:
/* logic: if the select call indicates that there is data to
* be read, but a read returns 0 bytes of data, then the socket
* has been closed.
*/
And then goes select call with timeout set to zero (no timeout, wait forever). So it really doesn't matter whether the socket is blocking or not: you'll block here. And that's why foef() function can be extremely slow, regardless of the type of the socket.
Conclusion: the bug was not related to this PEAR package. Having fixed it broke PHP's standard feof() functionality (which is strongly expected from this wrapper class), which could lead to unpredictable results with another projects, although fixes an issue with Net_IMAP.
I'd suggest reverting to old function logic. If some kind of workaround is needed, another method (something like oefCheckHalfway) can be defined and used where appropriate. If Net_IMAP works better without strong eof check, that should be reported and fixed with that package.