2017-05-08 27 views
1

我想設置一個超時在我的PHP函數下面,以避免頁面加載需要一段時間,但我需要發送一個TCP消息通過PHP的頁面加載一個IP和端口,如何設置一個超時事件該IP和端口無法訪問?PHP設置套接字超時不起作用?

我已經嘗試使用下面的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); 
} 
+1

不幸的是,'SO_SNDTIMEO'不影響連接超時;只有在套接字連接後才執行寫入操作。您需要將套接字置於非阻塞模式,爲連接編寫自己的超時循環(這將返回EAGAIN,直到套接字連接),然後將套接字重新置於阻塞模式。我會發布這個答案,但我不確定如果PHP支持的話。 –

回答

0

不幸的是用這個,SO_SNDTIMEO不影響連接超時;只有在套接字連接後才執行寫入操作。您需要將套接字置於非阻塞模式,爲連接編寫自己的超時循環(這將返回EAGAIN,直到套接字連接),然後將套接字重新置於阻塞模式。

基於@Lotharyx的評論,我寫了一個小的connect_with_timeout函數。
如果套接字及時連接,則函數返回true,否則返回false。 $timeout是以秒爲單位的超時時間,$con_per_sec是每秒連接嘗試的次數。
測試在Windows和Linux,PHP的5.5.x

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