Я использую сокеты для отправки данных на сервер, который может не отвечать. Поэтому я пытаюсь определить тайм-аут, используя это решение в SO.
Сделать PHP socket_connect таймаут
socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, array('sec' => 1, 'usec' => 0)); socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, array('sec' => 1, 'usec' => 0));
Это работает, когда соединение выполняется, и сервер слишком долго реагирует. Но когда он не может создать соединение socket_connect($socket, $addr, $port);
тайм-аут составляет около 20 секунд.
Почему происходит этот 20-секундный тайм-аут и как я могу заставить создание соединения таймаутом через 1 секунду?
Вы можете сделать это, переключившись на неблокирующий сокет, зацикливая до тех пор, пока не будет достигнуто соединение или не будет достигнут тайм-аут, а затем снова вернемся к блокировке.
// an unreachable address $host = '10.0.0.1'; $port = 50000; $timeout = 2; $sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); // switch to non-blocking socket_set_nonblock($sock); // store the current time $time = time(); // loop until a connection is gained or timeout reached while (!@socket_connect($sock, $host, $port)) { $err = socket_last_error($sock); // success! if($err === 56) { print('connected ok'); break; } // if timeout reaches then call exit(); if ((time() - $time) >= $timeout) { socket_close($sock); print('timeout reached!'); exit(); } // sleep for a bit usleep(250000); } // re-block the socket if needed socket_set_block($sock);
edit: см. @letiagoalves ответ для более аккуратного решения, если вы используете сокеты, созданные с помощью fsockopen () или stream_socket_client ()
Я изменил механизм связи сокета, чтобы вместо этого использовать функцию stream_socket_client ($remote_socket, &$errno, &$errstr, $timeout)
. Эта функция позволяет определить тайм-аут соединения в отличие от socket_connect ($socket, $address, $port)
которого нет.
Чтобы заставить таймаут использовать socket_connect
см. Ответ @bigtallbill.
Параметры SO_RCVTIMEO / SO_SNDTIMEO не работают для socket_connect на некоторых платформах, но только для socket_recv / socket_send. Я вижу, что это работает на Ubuntu, но не на Mac OSX.