2

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);
}
1
  • 1
    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. I'd post this as an answer but I'm not sure offhand if PHP supports that. Commented May 8, 2017 at 18:14

1 Answer 1

3

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

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

1 Comment

Hi @t.m.adam, would you mind giving this post a go in case there is any solution to your mind. Thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.