数百个IP地址的状态检查器


Status checker for hundreds IP addresses

我想知道如何制作一个状态检查器,在几分钟内检查大约500个地址?(如果正在侦听,它将检查某个端口)。

但我关心表演。。。所以我不知道是否可以用PHP来完成。正在等待你们的建议。

另外,如果你认为最好的方法是PHP或C#,请给我一些例子。

Ofc。我指的是TCP连接,而不是http,因为我需要检查打开的端口,例如:11740

编辑:

为这个问题增加了第三个奖励!请发布一些比已经发布的答案更好的答案。

这在PHP中非常可行,您可以在几秒钟内检查500个IP。使用mutli-ccurl一次发送许多请求(即100个或全部500个)。它只需要最慢IP的响应时间。但您可能需要设置一个合理的卷曲连接超时数秒。我记得默认的网络超时是2分钟。http://php.net/manual/en/function.curl-multi-exec.php

请注意,我并不是说PHP是您最好的选择。但是在PHP中可以很快很容易地完成。

这是一个完整的代码示例。我用真实的URL测试了它,一切都成功了。$results数组将包含您可以从curl请求中获得的几乎所有统计信息。在您的情况下,由于您只关心端口是否"打开",因此通过将CURLOPT_NOBODY设置为true来执行HEAD请求。

$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.217-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
*/

如其他答案中所述,最好的方法是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代码或C#代码或其他能做到这一点的代码并不是什么大不了的事,只是nmap非常擅长它所做的事情,而且用途非常广泛,所以编写这样的代码就是重新发明轮子。如果你决定走这条路,请确保你的代码是异步的,否则一个慢服务器会减慢你的整个扫描速度。

如kz26所述,从命令行nmap将是您的最佳选择。使用system、exec、shell_exec等PHP函数捕获结果进行处理。

本指南应能帮助您入门http://www.cyberciti.biz/tips/linux-scanning-network-for-open-ports.html

C#将是一个更好的选择,因为您可以使用线程来加快进程。

在PHP中,您可以通过使用fsockopen()来检查TCP端口是否打开。

$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个ip,但这实际上取决于您的互联网连接和其他规格。其他用低级语言编写的工具会更快一点,但我认为php很适合这项工作。在尝试之前,您必须将php执行限制设置为合适的值

They关键字是非阻塞的。当尝试成功时,您希望有一个特定的回调,并在此期间能够运行更多的调用。

DaveRandom答案中的一些函数(如套接字)允许在常规php安装中使用非阻塞模式来实现这一点。您还可以使用不同的编程语言(如node.js)来非常有效地实现这一点,因为它们被设计为非阻塞的。

到目前为止,最有效的方法是使用原始套接字,但这需要管理权限和一些样板编码。您选择一个本地端口作为源,向每个目标地址的端口80发送一个SYN数据包,并在源端口上收集返回数据包。如果它们有ACK标志,则该端口将为连接打开。如果它们有RST或没有返回,则表示端口未打开/主机已关闭。

显然,您需要手动等待您选择的任何"超时",因为这种方法在操作系统网络堆栈中运行。不过,这还需要手动构建TCP和IP标头,我怀疑这是否可以从PHP中完成。这当然可以在C中完成,我相信C#也支持原始套接字(我自己还没有在C#中完成)。

这是非常快,并且不会用一堆打开的连接或线程污染系统。

你能做的最好的事情就是启动多个线程(你决定数量;可能超过10个,小于100个)。在不同的线程上进行扫描将加快检查速度。我不确定你是否可以在php中进行多线程处理。如果不是,那么c#会更好。