Php - fgets() reading with socket, still not worki

2019-09-02 04:18发布

问题:

I've spent a lot of time on this fgets() problems without any success until now. I'm receiving data from different sources through a HTTP socket. It worked fine until now that I have a lot more different sources.

My goal is just to get rid of the execution timeout of php, just know that it timed out after 15 seconds but go on with the next source.

Here is my small piece of code:

//This is just from php.net, found out that it works pretty good
$time = time();
while (!($temp = fsockopen($host, $port, $errNo, $errMessage, $timeout)))
{
    if ((time() - $time) >= $timeout)
    {
        socket_close($temp);
        return false;
    }
    sleep(1);
}

    //If PHP returns an error
 if (!($temp)) {
    echo 'Socket could not be opened.<br/>';
    return false;
}

$return = "";

if (!fwrite($temp, $out)) {
    print_r(error_get_last());
    return false;
}

    //Timeout set to 15 seconds
    stream_set_blocking($temp, 0);
    $start = time();

    while ((time() < ($start + 15))) {

        //(Last lines always finishes like this)
        if (substr(trim($return),-9) == '"id":"1"}') {
            break;
        } else {
            $return .= fgets($temp, 512);
        }
    }
    fclose($temp);

After some testing I found out that a non-blocking socket gives way better results for this code, however it is still blocking after data has been received for 4 sources. (I tried to change the order so it is not source-dependent)

I tried to use stream_set_timeout($temp) and check the state of the flag in the loop but it doesn't change a thing.

EDIT: I forgot to mention it, but the script is stopping (PHP execution timeout of 30 seconds) at the line with fgets().

Any clues?

Cheers!

回答1:

The documentation of the length parameter to fgets():

Reading ends when length - 1 bytes have been read, or a newline (which is included in the return value), or an EOF (whichever comes first). If no length is specified, it will keep reading from the stream until it reaches the end of the line.

None of these conditions will be met in your case, which will let the script wait indefinitely on input.

To make use of the socket timeout set by stream_set_timeout() you can use fread() instead of fgets(), which will honor the set timeout. The only difference with fgets() is that fread() doesn't fetch a line at a time, but the whole length number of bytes.



回答2:

Thanks for your held everyone,

In the end, the main reason that it is not working properly is that the answer takes a bit longer to arrive than it used to take.

The reason why it was struck on fgets sometimes and sometimes not is still unclear however, but I solved it the following way: - read the header - get the Content-length of the header - wait a specified amount of time (as this is the data part that takes some time to be sent by the remote server) - and then fgets($handle, $content_lenght -1)

What I still don't understand is why I have to wait, normally a fgets() if the socket is in blocking mode, should wait and read until an EOF (or a defined length) as you said, but there is ALWAYS a EOF at the end of the data line in my case, and anyway I am specifying the length...

And it takes maximum 10 seconds to get the data from a server on the other side of the world connected in 3G (can't do worse), so I still don't see why the 30 seconds exec is reached...

Anyway, at least it works, not perfectly but it works.

Cheers