Подтвердить что ты не робот

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

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

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

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

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

Edit:

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

4b9b3361

Ответ 1

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

Вы хотите запустить его следующим образом (-PN не выполняет ping, -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-код или код С# или что-то другое, что делает это не очень важно, просто nmap очень хорошо разбирается в том, что он делает, и чрезвычайно универсален, что писать код, который делает это изобретать колесо. Если вы решите пойти по этому маршруту, убедитесь, что вы сделали свой код асинхронным, иначе один медленный сервер замедлит всю вашу развертку.

Ответ 2

Это очень удобно в 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);

Ответ 3

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

Ответ 4

Вот как это сделать очень быстро в PHP, используя расширение sockets, установив все сокеты на блокировку. С чисто сетевой точки зрения это наиболее эффективный способ, поскольку это просто проверяет 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

*/

Ответ 5

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

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

Ответ 6

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

В 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 для его вызова и обработки результатов.

Ответ 7

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

Ответ 8

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

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

Ответ 9

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

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

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

Ответ 10

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