PHP - fsockopen() истекает время ожидания вместо возврата false?


Я пытаюсь использовать fsockopen(), чтобы проверить, работает ли сервер Selenium. Когда сервер работает, константа должна быть установлена. Когда это не так, константа не установлена. Это делается с помощью следующего кода:

if(!defined('TEST_SELENIUM')){
    $fp = @fsockopen('localhost', 4444);
    if ($fp !== false) {
        define('TEST_SELENIUM', true);
        fclose($fp);
    }
}

Проблема возникает, когда сервер не запущен (в Windows 7). Вместо того, чтобы fsockopen() возвращал false при обнаружении закрытого порта, он останавливался при попытке установить связь с портом. Когда сервер запущен, он быстро отображается с помощью netstat. Когда сервер отключен netstat ничего не возвращает с порта 4444. Из моего понимания fsockopen(), это должно немедленно вернуть false. Но опять же, он просто останавливается, пытаясь связаться с портом. Я не хочу добавлять здесь тайм-аут, так как в приложении не указано, что должна быть какая-либо остановка. Кроме того, я должен отметить, что это, похоже, работает так, как я ожидал бы от Linux. Однако здесь, в Windows 7, он терпит неудачу. Кто-нибудь может сказать мне, что я делаю не так? Благодарю тебя много!

Author: golmschenk, 2012-08-16

1 answers

Вы не можете сделать это без добавления тайм-аута. Это не имеет ничего общего с реализациями PHP - именно так должно работать соединение TCP-сокета.

Поскольку TCP использует подтверждения (ACK) для гарантии доставки и заказа пакетов, когда вы инициируете TCP-соединение, клиент отправляет пакет SYN и ожидает возвращенный пакет SYN/ACK. Клиент будет продолжать ждать этого возвращенного пакета до тех пор, пока он либо не будет получен, либо клиент не решит, что он ожидает достаточно долго и сдается - это аргумент тайм-аута, который fsockopen() принимает.

Когда вы запускаете netstat, он просматривает приложения, привязанные к стеку TCP на локальном компьютере - это означает, что он может определить, используется ли порт , не пытаясь подключиться к нему . В результате он может мгновенно сообщить, используется сокет или нет.

Реально здесь у вас есть два варианта.

  • Укажите время ожидания. Имей в виду что аргумент времени ожидания может быть плавающим (и, следовательно, может быть меньше 1 секунды), поэтому, если вы проверяете локальную машину, вы можете установить это значение крайне низким. Просто играя с тестированием на своей машине с Windows XP, я обнаружил, что могу установить для нее значение 0.001 (1 мс), и она успешно подключается к запущенным службам и возвращает FALSE для несвязанных портов. Это время ожидания 1 мс также работает для других машин в моей (по общему признанию, относительно тихой и полностью гигабитной) локальной сети. YMMV, но 5 мс (0.005) должно быть больше чем достаточно в высокоскоростной сети.
    Например, эта строка хорошо работает для меня и заставит скрипт ждать максимум 1 мс:
define('TEST_SELENIUM', (bool) @fsockopen('localhost', 4444, $en, $es, 0.001));
  • shell_exec('netstat'); и проанализируйте выходные данные. Это, безусловно, сработало бы только в том случае, если бы вы проверяли локальную машину, и, скорее всего, не было бы быстрее, чем подход с таймаутом 1 мс. Он также не очень переносим, так как утилита netstat в различных операционных системах может выдавать очень немного разные выходные данные - разный порядок столбцов, различные символы-разделители и т. Д. и т. Д.

Также стоит отметить, что если стек TCP настроен на активное отклонение пакетов, отправляемых на несвязанные порты (путем возврата ПЕРВОГО пакета), то fsockopen() немедленно завершится ошибкой. Вероятно, поэтому вы говорите this appears to work the way I would expect it should on Linux - экземпляр Linux, на котором вы его тестировали, был настроен таким образом. Вероятно, существует какой-то параметр реестра, который позволил бы вам настроить Windows на такое поведение, хотя я не думаю, что знайте, что это такое - ребята из суперпользователя могут вам в этом помочь.

 3
Author: DaveRandom, 2012-08-23 13:02:16