我想知道如何制作状态检查器,在几分钟内检查大约500个地址? (它会检查某个端口是否正在收听)。
但是我关心性能......所以我不知道是否可以用PHP完成。等待你的建议。
另外请给我一些例子,如果你认为这个东西的最佳方式是PHP或C#。
OFC。我的意思是TCP连接,但不是http,因为我需要检查开放端口,例如: 11740
编辑:
为这个问题增加了第三笔赏金!请发布一些比已发布的答案更好的答案。
答案 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#会更好。