Проверка состояния для сотен IP-адресов

Интересно, как сделать проверку статуса, проверив около 500 адресов за несколько минут? (он будет проверять определенный порт, если его прослушивание).

Но я забочусь о производительности … поэтому я не знаю, можно ли это сделать с PHP. Жду ваших предложений.

Также, пожалуйста, дайте мне несколько примеров, если вы считаете, что лучшим способом для этой вещи будет PHP или C #.

Ofc. Я имел в виду TCP-соединение, но не http, так как мне нужно проверить открытый порт, например: 11740

Редактировать:

Добавлена ​​третья награда за этот вопрос! Пожалуйста, напишите несколько лучших ответов, чем те, которые уже были опубликованы.

Лучшим способом для этого было бы nmap , как упоминалось в других ответах.

Вы хотите запустить его следующим образом ( -PN не пинговать, -sP означает пропустить сканирование порта и просто проверить, если хост поднят, -PS80 означает проверить порт 80, -n не делать обратного DNS-поиск, -oG - выводится в машиночитаемом формате, а остальные аргументы – это IP-адреса или имена хостов):

 nmap -PN -sP -PS80 -n -oG - --send-ip IP1 IP2 ... 

И это будет выглядеть так:

 $ nmap -n -PN -sP -PS80 -oG - 209.85.147.104 87.248.122.122 4.4.4.4 # Nmap 5.21 scan initiated Tue Feb 21 01:07:20 2012 as: nmap -n -PN -sP -PS80 -oG - 209.85.147.104 87.248.122.122 4.4.4.4 Host: 209.85.147.104 () Status: Up Host: 87.248.122.122 () Status: Up Host: 4.4.4.4 () Status: Down # Nmap done at Tue Feb 21 01:07:21 2012 -- 3 IP addresses (2 hosts up) scanned in 0.95 seconds 

Вы можете запустить и проанализировать это с PHP без проблем. Я не очень опытен в PHP и не тестировал это, но вот пример кода:

 <?php $output = shell_exec('nmap -n -PN -sP -PS80 -oG - --send-ip ' . implode(" ", $ips)); $result = array(); foreach(preg_split("/\r?\n/", $output) as $line) { if (!(substr($line, 0, 1) === "#")) { $info = preg_split("[\t ]", $line); $result[$info[2]] = ($info[5] === "Up"); } } ?> 

Имейте в виду, что писать PHP-код или код C # или что-то еще, что делает это не очень важно, просто nmap очень хорошо nmap в том, что он делает, и чрезвычайно универсален, что писать код, который делает это, изобретает колесо. Если вы решите пойти по этому маршруту, убедитесь, что вы сделали свой код асинхронным, иначе один медленный сервер замедлит всю вашу развертку.

Это очень удобно в PHP, и вы можете проверить 500 IP за несколько секунд. Используйте mutli-curl для отправки множества запросов одновременно (т.е. 100 или все 500). Это займет всего до тех пор, пока самый медленный IP ответит. Но вы можете установить разумный тайм-аут соединения завихрений на несколько секунд. Как я помню, таймаут сети по умолчанию составляет 2 минуты. http://php.net/manual/en/function.curl-multi-exec.php

Обратите внимание, что я не говорю, что PHP – ваш лучший выбор для чего-то подобного. Но это можно сделать довольно быстро и легко в PHP.

Вот пример полного кода. Я тестировал его с помощью реальных URL-адресов, и все это сработало. Массив $ results будет содержать почти все статистические данные, которые вы можете получить из запроса на завивание. В вашем случае, поскольку вам просто нужно, чтобы порт был «открытым», вы делаете запрос HEAD, устанавливая CURLOPT_NOBODY в true.

 $urls = array( 'http://url1.com'=>'8080', 'http://url2'=>'80', ); $mh = curl_multi_init(); $url_count = count($urls); $i = 0; foreach ($urls as $url=>$port) { $ch[$i] = curl_init(); curl_setopt($ch[$i], CURLOPT_RETURNTRANSFER, true); curl_setopt($ch[$i], CURLOPT_NOBODY, true); curl_setopt($ch[$i], CURLOPT_URL, $url); curl_setopt($ch[$i], CURLOPT_PORT, $port); curl_multi_add_handle($mh, $ch[$i]); $i++; } $running = null; do { $status = curl_multi_exec($mh,$running); $info = curl_multi_info_read($mh); } while ($status == CURLM_CALL_MULTI_PERFORM || $running); $results= array(); for($i = 0; $i < $url_count; $i++) { $results[$i] = curl_getinfo($ch[$i]); // append port number request to URL $results[$i]['url'] .= ':'.$urls[$results[$i]['url']]; if ($results[$i]['http_code']==200) { echo $results[$i]['url']. " is ok\n"; } else { echo $results[$i]['url']. " is not ok\n"; } curl_multi_remove_handle($mh, $ch[$i]); } curl_multi_close($mh); print_r($results); 

Лучше всего использовать специализированный сканер портов, такой как nmap . Я не знаю параметров командной строки с верхней части головы, но должно быть возможно выводить файл результатов и просто анализировать его с PHP.

Вот как это сделать очень быстро в PHP, используя расширение сокетов , установив все сокеты на блокировку. С чисто сетевой точки зрения это наиболее эффективный способ, поскольку это просто проверяет TCP-соединение и не обменивает никаких реальных данных. Протестировано на PHP / 5.2.17-Win32.

 <?php // An array of hosts to check $addresses = array( '192.168.40.40', '192.168.5.150', '192.168.5.152', 'google.com', '192.168.5.155', '192.168.5.20' ); // The TCP port to test $testport = 80; // The length of time in seconds to allow host to respond $waitTimeout = 5; // Loop addresses and create a socket for each $socks = array(); foreach ($addresses as $address) { if (!$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) { echo "Could not create socket for $address\n"; continue; } else echo "Created socket for $address\n"; socket_set_nonblock($sock); // Suppress the error here, it will always throw a warning because the // socket is in non blocking mode @socket_connect($sock, $address, $testport); $socks[$address] = $sock; } // Sleep to allow sockets to respond // In theory you could just pass $waitTimeout to socket_select() but this can // be buggy with non blocking sockets sleep($waitTimeout); // Check the sockets that have connected $w = $socks; $r = $e = NULL; $count = socket_select($r, $w, $e, 0); echo "$count sockets connected successfully\n"; // Loop connected sockets and retrieve the addresses that connected foreach ($w as $sock) { $address = array_search($sock, $socks); echo "$address connected successfully\n"; @socket_close($sock); } /* Output something like: Created socket for 192.168.40.40 Created socket for 192.168.5.150 Created socket for 192.168.5.152 Created socket for google.com Created socket for 192.168.5.155 Created socket for 192.168.5.20 4 sockets connected successfully 192.168.40.40 connected successfully 192.168.5.150 connected successfully google.com connected successfully 192.168.5.20 connected successfully */ 

Как упоминалось kz26, nmap из командной строки будет вашим лучшим вариантом. С помощью функций PHP, таких как system, exec, shell_exec и т. Д. , Можно получить результаты для обработки.

Это руководство поможет вам начать работу http://www.cyberciti.biz/tips/linux-scanning-network-for-open-ports.html

C # будет лучшим вариантом, так как вы можете использовать потоки для ускорения процесса.

В PHP вы можете по существу проверить, открыт ли TCP-порт с помощью fsockopen () .

 $host = 'example.com'; $port = 80; $timeout = 30; $fp = @fsockopen($host, $port, $errno, $errstr, $timeout); if (!$fp) { echo "Port $port appears to be closed on $host Reason: $errno: $errstr.\n"; } else { echo "Port $port is open on $host\n"; fclose($fp); } 

Как сказал kz26, вы также можете получить что-то вроде nmap, чтобы проверить порты на кучке хостов и использовать php для вызова и обработки результатов.

PHP должен уметь проверять 500 ips за довольно короткое время, но это действительно зависит от вашего интернет-соединения и других спецификаций. Другие инструменты, написанные на более низких языках, будут немного быстрее, но я думаю, что php хорош для работы. Вы должны просто установить лимит выполнения php на подходящее значение, прежде чем пытаться

Их ключевое слово в этом не блокирует. Вы хотите иметь определенный обратный вызов, когда попытка будет успешной и сможет выполнять больше вызовов за это время.

Некоторые функции, такие как сокеты из ответа DaveRandom, позволяют использовать неблокирующий режим в обычных установках php. Вы также можете использовать разные языки программирования, такие как node.js, чтобы сделать это очень эффективно, потому что они предназначены для неблокирования.

Самый эффективный способ сделать это – использовать сырые сокеты , однако для этого требуются административные привилегии и некоторая кодировка. Вы выбираете локальный порт в качестве источника, отправляете SYN-пакет на порт 80 каждого целевого адреса и собираете возвращаемые пакеты в исходном порту. Если у них есть флаг ACK, порт открыт для соединений. Если они имеют RST или они не возвращаются, порт не открывается / хост мертв.

Очевидно, вам нужно будет вручную подождать, когда будет выбран ваш «тайм-аут», поскольку этот метод распространяется на сетевой стек OS. Это также требует, чтобы вы строили заголовки TCP и IP вручную, и я сомневаюсь, что это можно сделать с PHP. Это, безусловно, можно сделать на C, и я считаю, что C # также поддерживает сырые сокеты (не сделал это сам на C #).

Это очень быстро и не загрязняет систему путём открытых соединений или потоков.

Лучшее, что вы можете сделать, это запустить несколько потоков (вы определяете число, вероятно, более 10 и менее 100). Выполнение сканирования на разных потоках ускорит проверку. Я не уверен, что вы можете делать многопоточность в php. Если нет, то c # будет лучше.