PHP: socket_write freezes when a client disconnects while writing

While I receive data in my iOS application (some data is received, but not all), I intentionally terminate the application and socket_writefreezes on the server. Here is the relevant code:

error_log("start write");
$sent = socket_write($client, $string, $length);
error_log("end write");

I get a message "start write"in my error log, but it just keeps hanging until I restart the php program.

I tried to set a timeout, but then I tried to download a large file, and it looks like it was disconnected before the download completed. I thought that the timeout is a period of inactivity, and not the total time for which the client is connected. In any case, any help is appreciated. I assumed that it socket_writewill return if the socket is disconnected, but I am mistaken or the code. Thanks for any help.

EDIT

Basically, I need to know when the client disconnected. It looks like fwrite, socket_send, and socket_write all freeze when the client disables mid-write and lock mode. If I turn off the lock mode, my code is as follows:

function send_data($client, $string)
{
    $length = strlen($string);
    socket_set_nonblock($client);
    while(true)
    {
        $sent = socket_write($client, $string, $length);
        //OR - $sent = socket_send($client, $string, $length, 0);

        if($sent === FALSE)
        {
            error_log("false");
            return;
        }
        if($sent < $length)
        {
                $string = substr($string, $sent);
                $length -= $sent;
        }
        else
            return;  
    }
}

The problem is that $sent === FALSEwhen the client disconnects, and also when they are temporarily unavailable, which turned out to be after sending the first few bytes, thus not sending a whole line.

+4
source share
3 answers

You should use socket_select()to determine if a socket is ready for recording; so you only need to write something when the other side is ready to receive.

You still need to check how many bytes were transmitted, and reduce the message accordingly.

For instance:

function send_data($client, $string)
{
    socket_set_nonblock($client);

    while ($string != '') {
        $write = [$client]; $read = $except = null;
        // set timeout to 1s
        $n = socket_select($read, $write, $except, 1);
        if ($n === false) {
            return;
        } elseif ($n > 0) {
            $length = strlen($string);
            $sent = socket_write($client, $string, $length);
            if ($sent === false || $sent == $length) {
                return;
            } else /* $sent < $length */ {
                $string = substr($string, $sent);
            }
        }
    }
}
+1

, $sent === FALSE, , , , , .

socket_last_error() EAGAIN/EWOULDBLOCK.

11 35, , .

EDIT: PHP constants .

SOCKET_EWOULDBLOCK. Linux, Windows.

socket_write ( "start write", "end" " 10 - 30 .

, socket_write.

TCP . -, .

SO_SNDTIMEO.

+2

My solution is to use socket_selectwith a timeout of 3 seconds. I think that with respect to a computer, “temporarily unavailable” and “disconnected” are synonyms.

0
source

All Articles