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

时间:2012-01-21 21:27:31

标签: php status

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

但是我关心性能......所以我不知道是否可以用PHP完成。等待你的建议。

另外请给我一些例子,如果你认为这个东西的最佳方式是PHP或C#。

OFC。我的意思是TCP连接,但不是http,因为我需要检查开放端口,例如: 11740

编辑:

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

10 个答案:

答案 0 :(得分:30)

这在PHP中是非常可行的,您可以在几秒钟内检查500 IP。使用mutli-curl一次发送许多请求(即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);

答案 1 :(得分:14)

您最好的选择可能是使用像nmap这样的专用端口扫描程序。我不知道我头顶的命令行选项,但应该可以输出结果文件,只需从PHP解析它。

答案 2 :(得分:8)

通过将所有套接字设置为非阻塞,可以使用sockets扩展在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

*/

答案 3 :(得分:5)

最好的方法是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非常擅长它的功能,而且功能非常多,编写代码可以这是重新发明轮子。如果您决定走这条路线,请确保您的代码异步,否则一台慢速服务器会减慢您的整个扫描速度。

答案 4 :(得分:4)

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

本指南可帮助您开始使用http://www.cyberciti.biz/tips/linux-scanning-network-for-open-ports.html

答案 5 :(得分:2)

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来调用它并处理结果。

答案 6 :(得分:1)

PHP应该可以在相当短的时间内检查500 ips,但这实际上取决于您的互联网连接和其他规格。用较低语言编写的其他工具会快一点,但我认为php对这项工作有好处。在尝试

之前,您必须将php执行限制设置为合适的值

答案 7 :(得分:1)

这里的关键字是非阻塞的。当尝试成功并且能够在此期间运行更多呼叫时,您可能希望进行某次回调。

DaveRandom的答案中的套接字等功能允许非阻塞模式在常规php安装中执行此操作。您还可以使用不同的编程语言(如node.js)来非常有效地执行此操作,因为它们设计为非阻塞。

答案 8 :(得分:1)

迄今为止最有效的方法是使用原始套接字,但这需要管理权限和一些样板编码。选择本地端口作为源,将SYN报文发送到每个目标地址的端口80,并在源端口上收集返回报文。如果它们有ACK标志,则端口打开以进行连接。如果他们有RST或他们没有返回,端口没有打开/主机已经死了。

显然,您需要手动等待所选择的“超时”,因为此方法绕过OS网络堆栈。这也需要您手动构建TCP和IP头,但我怀疑它可以通过PHP完成。它当然可以在C中完成,我相信C#也支持原始套接字(我自己没有在C#中完成)。

这是极快,并且不会通过一堆打开的连接或线程污染系统。

答案 9 :(得分:0)

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