【问题标题】:PHP setting socket timeout not working?PHP设置套接字超时不起作用?
【发布时间】:2017-05-08 18:07:44
【问题描述】:

我正在尝试在下面的 php 函数上设置超时以避免页面加载需要一段时间,但是我需要在页面加载时通过 php 将 tcp 消息发送到 ip 和端口,我该如何设置超时如果ip和端口不可达?

我尝试过使用下面的 socket_set_option 方法,但不幸的是它最多需要 30 秒,有时甚至更长。

我在 laravel 5.2 项目中使用它

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);
}

【问题讨论】:

  • 很遗憾,SO_SNDTIMEO 不影响连接超时;仅在套接字连接后进行写操作。您需要将套接字置于非阻塞模式,为连接编写自己的超时循环(它将返回 EAGAIN 直到套接字连接),然后将套接字重新置于阻塞模式。我会将此作为答案发布,但我不确定 PHP 是否支持。

标签: php sockets


【解决方案1】:

我根据布赖恩的comment写了一个connect_with_timeout函数:

很遗憾,SO_SNDTIMEO 不影响连接超时;仅在套接字连接后进行写操作。您需要将套接字置于非阻塞模式,为连接编写自己的超时循环(在套接字连接之前将返回 EAGAIN),然后将套接字重新置于阻塞模式。

如果套接字及时连接,该函数返回true,否则返回false。 $timeout 是以秒为单位的超时,$con_per_sec 是每秒连接尝试的次数。

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;
}

在 Windows 和 Linux,PHP 5.x 上测试

【讨论】:

  • 嗨@t.m.adam,如果您有任何解决方案,您是否介意给this post 一个机会。谢谢。
猜你喜欢
  • 2019-07-22
  • 2014-01-13
  • 2018-07-20
  • 2011-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-20
  • 2013-05-29
相关资源
最近更新 更多