Ash Smith
Ash Smith

Reputation: 192

PHP setting socket timeout not working?

I am trying to set a timeout on my php function below to avoid the page load taking a while, but I need to send a tcp message over to an ip and port via php on page load, how can I set a timeout incase the ip and port is unreachable?

I have tried using the socket_set_option method below but unfortinately it will takes up to 30 seconds, sometimes longer.

I use this in a laravel 5.2 project

public static function send($command, $data = '')
{
    $MUSdata = $command . chr(1) . $data;
    $socket = \socket_create(AF_INET, SOCK_STREAM, getprotobyname('tcp'));

    $connect_timeval = array(
        "sec"=>0,
        "usec" => 100
    );

    \socket_set_option(
        $socket,
        SOL_SOCKET,
        SO_SNDTIMEO,
        $connect_timeval
    );

    \socket_connect($socket, Config::get('frontend.client_host_ip'), Config::get('frontend.mus_host_port'));
    \socket_send($socket, $MUSdata, strlen($MUSdata), MSG_DONTROUTE);     
    \socket_close($socket);
}

Upvotes: 2

Views: 2142

Answers (1)

t.m.adam
t.m.adam

Reputation: 15376

I wrote a connect_with_timeout function based on Brian's comment:

Unfortunately, SO_SNDTIMEO does not affect the connection timeout; only write operations after the socket is connected. You will need to put the socket in nonblocking mode, write your own timeout loop for the connect (which will return EAGAIN until the socket connects), and then put the socket back into blocking mode.

The function returns true if the socket connects in time, else false. $timeout is the timeout in seconds, $con_per_sec is the number of connection attempts per second.

function connect_with_timeout($soc, $host, $port, $timeout = 10) {
    $con_per_sec = 100;
    socket_set_nonblock($soc);
    for($i=0; $i<($timeout * $con_per_sec); $i++) { 
        @socket_connect($soc, $host, $port);
        if(socket_last_error($soc) == SOCKET_EISCONN) { 
            break;
        }
        usleep(1000000 / $con_per_sec);
    }
    socket_set_block($soc);
    return socket_last_error($soc) == SOCKET_EISCONN;
}

Tested on Windows and Linux, PHP 5.x

Upvotes: 3

Related Questions