PHP fsockopen() мучительно медленный

Я использую fsockopen() для вызова ряда соединений в списке, чтобы увидеть онлайн-статус различных ip/host и портов...

<?php
$socket = @fsockopen($row[2], $row[3], $errnum, $errstr, 1);
if ($errnum >= 1) { $status = 'offline'; } else { $status = 'online';}
fclose($socket);

если работает, я не жалуюсь на это, но у меня есть примерно 15 ip/портов, которые я получаю в списке (команда php for() ..). Мне было интересно, есть ли лучший способ сделать это? Этот путь ОЧЕНЬ медленный!?! Серверу требуется около 1-2 минут, чтобы вернуться с ответом для всех из них.

Обновлять:

<?php
$socket = @fsockopen("lounge.local", "80", $errnum, $errstr, 30);
if ($errnum >= 1) { $status = 'offline'; } else { $status = 'online'; }
?>

Он будет отображаться в списке: «ReadyNAS AFP readynas.local: 548 онлайн».

Я не знаю, что еще я могу вам сказать? Загрузка коллекции результатов занимает целую вечность...


person Phillip    schedule 06.03.2011    source источник
comment
Спасибо за сокращение вашего примера кода. Однако, пожалуйста, рассмотрите возможность предоставления полного примера скрипта (который сканирует stackoverflow.com или example.com или около того). Проблема почти наверняка не в выложенном вами отрывке. Также обратите внимание, что вы не должны вызывать fclose, если $socket === false.   -  person phihag    schedule 06.03.2011
comment
Спасибо, я удалил его после загрузки этого фрагмента. Обновлен с полным образцом сценария   -  person Phillip    schedule 06.03.2011
comment
Если кому интересно. Я использовал fsockopen("localhost"), и это было ужасно медленно (~ 1010 мс). с fsockopen("127.0.0.1") это было намного быстрее (~ 11 мс).   -  person Piotr    schedule 23.07.2014


Ответы (7)


Из моего собственного опыта:

Этот код:

$sock=fsockopen('www.site.com', 80);

медленнее по сравнению с:

$sock=fsockopen(gethostbyname('www.site.com'), 80);

Протестировано в PHP 5.4. Если одновременно выполнять много подключений, можно сохранить результат разрешения хоста и повторно использовать его, чтобы еще больше сократить время выполнения скрипта, например:

function myfunc_getIP($host) {
   if (isset($GLOBALS['my_cache'][$host])) {
      return $GLOBALS['my_cache'][$host];
   }

   return $GLOBALS['my_cache'][$host]=gethostbyname($host);
}

$sock=fsockopen(myfunc_getIP('www.site.com'), 80);
person mike    schedule 21.08.2012

Если вы планируете «пинговать» какой-то URL, я бы посоветовал делать это с помощью curl, почему? вы можете использовать curl для параллельной отправки пингов, посмотрите на это -> http://www.php.net/manual/en/function.curl-multi-init.php. В предыдущем проекте предполагалось передавать данные в реальном времени на наш сервер, мы использовали пинг хостов, чтобы узнать, живы они или нет, и Curl был единственным вариантом, который нам помог. Это совет, возможно, это не правильное решение вашей проблемы.

person Kumar    schedule 06.03.2011
comment
пытаюсь сделать это, и это оказывается сложной задачей... Я свяжусь с вами, если я все еще потерян :) - person Phillip; 06.03.2011

Вы сравнивали результаты fsockopen(servername) и fsockopen(ip-address)? Если параметр тайм-аута ничего не меняет, проблема может быть в вашем сервере имен. Если fsockopen с IP-адресом работает быстрее, вам придется исправить свой сервер имен или добавить домены в файл /etc/hosts.

person jmz    schedule 06.03.2011
comment
Посмотрю на это - спасибо! он просто работает с моего сервера Mac Mini XAMPP... :) - person Phillip; 06.03.2011

Я бы рекомендовал сделать это немного по-другому. Поместите эти хосты в таблицу в базе данных примерно так:

++++++++++++++++++++++++++++++++++++
| host | port | status | timestamp |
++++++++++++++++++++++++++++++++++++

И переместите часть проверки состояния в скрипт cron, который вы запускаете каждые 5 минут или так часто, как хотите. Этот скрипт проверит хост: порт и обновит статус и временную метку для каждой записи, а на вашей странице вы просто выполните запрос к БД и покажете хост, его статус и время последней проверки (что-то вроде: 1 минута назад и т. д.). ) Таким образом, ваша страница будет загружаться быстро.

person daniels    schedule 06.03.2011
comment
Я не буду заходить на эту страницу так часто (чтобы увидеть статус), поэтому я не хочу больше нагружать сервер, если в этом нет необходимости. Но я почитаю «cron» и посмотрите, действительно ли это сэкономит время... Спасибо за ваш вклад! - person Phillip; 06.03.2011

Последний параметр fsockopen() — это время ожидания, установите для него низкое значение, чтобы скрипт выполнялся быстрее, например:

fsockopen('192.168.1.93', 80, $errNo, $errStr, 0.01)
person Robin    schedule 06.03.2011
comment
Спасибо, однако это также не ускорило работу скрипта... Я ценю вашу помощь. - person Phillip; 06.03.2011

Согласно руководству по php, существует параметр тайм-аута. Попробуйте установить меньшее значение.

Изменить: чтобы добавить к ответу Дэниела, nmap может быть лучшим инструментом для использования. Настройте его с заданием cron для сканирования и обновления ваших записей каждые X минут. Что-то вроде

$ for ip in $(seq 6 8); 
do 
     port_open=$(nmap -oG - -p 80 10.1.0.$ip|grep open|wc -l); 
     echo "10.1.0.$ip:$port_open"; 
done

10.1.0.6:1
10.1.0.7:1
10.1.0.8:0
person Lmwangi    schedule 06.03.2011
comment
изначально он был установлен на 1, ничего не делал, поэтому я вернул его на значение по умолчанию 30... - person Phillip; 06.03.2011
comment
Хм, для этого может потребоваться дополнительная отладка. Если возможно, посмотрите поток tcp с помощью tcpdump/wireshark, чтобы увидеть, что делает fsockopen. Пытается повторно отправить? Удаленный хост не отвечает? Есть ли брандмауэр, бросающий гаечный ключ в работу? - person Lmwangi; 06.03.2011

У меня была проблема, когда запросы fsockopen были медленными, но wget был очень быстрым. В моем случае это происходило из-за того, что имя хоста имело адреса как ipv4, так и ipv6, но ipv6 не работал. Таким образом, для каждого запроса ipv6 требовалось около 20 секунд для тайм-аута.

person Rares P    schedule 04.07.2013