如何快速扫描局域网内所有IP的某一个端口是否开启 本帖最后由 coldanimal 于 2011-05-24 04:38:34 编辑 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 还从没涉足java网络应用方面的实际开发,一直停留在Demo阶段;不过你的代码我倒是有几点看法:第一是线程池是个单线程池,如果CPU是多核或连接过程中某个处于阻塞状态到超时,CPU资源利用率很低;第二是建立套接字是费时的,在call方法中连续创建两个Socket,却并没有调用connect()来连接服务器;第三是System.out.println是打印流,流是耗资源的,return服务器的IP+个"Timeout,failure"或"Success"就可以了,想看再去调用; 不动手无说服力(并不说我是个高手,只是想说怎么这么多人不去思考动手呢)我测试的一个示例也就200多微妙(双核CPU):import java.io.IOException;import java.net.InetAddress;import java.net.InetSocketAddress;import java.net.Socket;import java.net.UnknownHostException;import java.util.Collection;import java.util.LinkedList;import java.util.concurrent.Callable;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit;public class JPortScanner1 { public static void main(String[] args) throws InterruptedException, UnknownHostException { String ipHead; int lastPoint; String IP = InetAddress.getLocalHost().getHostAddress(); lastPoint = IP.lastIndexOf('.'); ipHead = IP.substring(0, ++lastPoint); ExecutorService executor = Executors.newCachedThreadPool(); Collection<Callable<String>> list = new LinkedList<Callable<String>>(); long start = System.currentTimeMillis(); for (int tail = 1; tail < 255; tail++) { list.add(new Task(ipHead, tail, 8081)); } executor.invokeAll(list); executor.shutdown(); long end = System.currentTimeMillis(); System.out.println("All time: " + (end - start) + " milliseconds"); }}class Task implements Callable<String> { String ipHead; int ipTail; int port; public Task(String ipHead, int ipTail, int port) { this.ipHead = ipHead; this.ipTail = ipTail; this.port = port; System.out.println(ipHead + ipTail + ":" + port); } public String call(){ Socket connect = new Socket(); try { connect.connect(new InetSocketAddress(ipHead + ipTail, port), 100); while(true){ if(connect.isConnected()){ //System.out.println(ipHead + ipTail + ":" + port + " success"); break; } } connect.close(); } catch (IOException e) { //System.out.println(ipHead + ipTail + ":" + port + " failure"); } return null; }} 那行 executor.invokeAll(list);应该为executor.invokeAll(list, 200L, TimeUnit.MILLISECONDS);把connect.connect(new InetSocketAddress(ipHead + ipTail, port), 100);放入while(true)中; 我表示:代码有效,但需要修改,connect.connect(new InetSocketAddress(ipHead + ipTail, port), 100);我的无线局域网,4台机子,测试80端口(都开通),修改前只能找到自己,将100修改为1000,后,可以找到其它几个机子的80端口。 我测试是在一个局域网段,在查看我本机的一些监听端口时8081是开启的,所以猜想其他人的机子也许会同样的监听此端口,当然也并不是所得IP地址是有效的,有效IP也不一定会开启8081这个端口。再者,我也是只是稍微修改了你原来的代码,并没有什么不能理解的地方;如果你要确认某台服务器是否开启某个端口,你可以用命令telnet直接测试下。测试代码的话,你直接的把connect.connect(new InetSocketAddress(ipHead + ipTail, port), 100);修改为 connect.connect(new InetSocketAddress("sun.java.com", 80), 100);一个测试结果如下(xxx是我手动加的...):xxx.xxx.xxx.22:8081 successxxx.xxx.xxx.33:8081 successxxx.xxx.xxx.133:8081 successxxx.xxx.xxx.127:8081 successxxx.xxx.xxx.44:8081 successxxx.xxx.xxx.46:8081 successxxx.xxx.xxx.48:8081 successxxx.xxx.xxx.56:8081 successxxx.xxx.xxx.62:8081 successxxx.xxx.xxx.66:8081 successxxx.xxx.xxx.64:8081 successActual executing Times : 625 millsecondsAll threads executing times : 131840 millseconds测试connect.connect(new InetSocketAddress("sun.java.com", 80), 100);结果:sun.java.com : 80 successsun.java.com : 80 successsun.java.com : 80 successsun.java.com : 80 successsun.java.com : 80 successsun.java.com : 80 successsun.java.com : 80 successsun.java.com : 80 successsun.java.com : 80 successsun.java.com : 80 successActual executing Times : 344 millsecondsAll threads executing times : 44085 millseconds修改后的代码:import java.io.IOException;import java.net.InetAddress;import java.net.InetSocketAddress;import java.net.Socket;import java.net.UnknownHostException;import java.util.Collection;import java.util.LinkedList;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;import java.util.concurrent.TimeUnit;public class JPortScanner1 { public static void main(String[] args) throws InterruptedException, UnknownHostException, ExecutionException { String ipHead; int lastPoint; String IP = InetAddress.getLocalHost().getHostAddress(); lastPoint = IP.lastIndexOf('.'); ipHead = IP.substring(0, ++lastPoint); ExecutorService executor = Executors.newCachedThreadPool(); Collection<Callable<Long>> list = new LinkedList<Callable<Long>>(); Collection<Future<Long>> taskList = null; for (int tail = 1; tail < 255; tail++) { list.add(new Task(ipHead, tail, 8081)); } //executor.invokeAll(list, 1000L, TimeUnit.MILLISECONDS); long start = System.currentTimeMillis(); taskList = executor.invokeAll(list); executor.shutdown(); long end = System.currentTimeMillis(); System.out.println("Actual executing Times : " + (end - start) + " millseconds"); long times = 0L; for(Future<Long> task : taskList){ times += task.get(); } System.out.println("All threads executing times : " + times + " millseconds"); }}class Task implements Callable<Long> { String ipHead; int ipTail; int port; public Task(String ipHead, int ipTail, int port) { this.ipHead = ipHead; this.ipTail = ipTail; this.port = port; //System.out.println(ipHead + ipTail + ":" + port); } public Long call(){ long start = System.currentTimeMillis(); Socket connect = new Socket(); try { //connect.connect(new InetSocketAddress(ipHead + ipTail, port), 100); connect.connect(new InetSocketAddress("sun.java.com", 80), 100); if(connect.isConnected()){ //System.out.println(ipHead + ipTail + ":" + port + " success"); System.out.println("sun.java.com : 80 success"); } connect.close(); } catch (IOException e) { //System.out.println(ipHead + ipTail + ":" + port + " failure"); try { connect.close(); } catch (IOException e1) { } } long end = System.currentTimeMillis(); return (end - start); }} 这个估计与防火墙有关系,如果telenet xxx.xxx.xxx.xxx 80 不能执行,那就是此计算机开启了 80端口也不行。或许你的局域网真没有机子开启你想找的端口。所以找不到,楼主可以先弄两个确实开启指定端口的计算机测试一下。 我的局域网内1-254内一共大概有200台机器 但是用你的方法只能找到大概50台 另外的150台无法找到而且每次找到的机器还不太一样 但是基本都是ip从xxx.xxx.xxx.1 - xxx.xxx.xxx.100之内的50台 后面的就一直不能找到。 是不是可以把连接超时设置长一点:connect.connect(new InetSocketAddress(ipHead + ipTail, port), 100000); 线程池一下子搞255个线程本来就是有问题的 虽然CPU是没有问题 UDP? 怎么能保证对方收到你的信息 给你回信呢?TCP这种方式 好象只能一个一个连接测试,公司也有类似的需求 也没想到好办法,而且这种方式不但慢 占用资源还高。 Executors.newCachedThreadPool();创建的实际是个ThreadPoolExecutor,这里我可以肯定的说不会有255个线程;其实你可以直接的new ThreadPoolExecutor来指定最大线程数:ThreadPoolExecutor(4, 8, 1000, TimeUnit.MILLISECONDS, new BlockingQueue<Runnable>());至于说能不能上网,那是网络管理设置的问题了;再说现在测试的结果也不保证下次测试是一样的,谁知道接下来会发生什么事情;也许服务器本身就是个单线程响应 或 现在很忙无法响应... 50个线程没什么问题,但是50个tcp连接占用的资源就比较大了。 你打开一个ie,多打开几个不同的站点,可能就是20几个连接,QQ也不会少,要是P2P这种下载工具,就更不用说了。所以我觉得50个连接也不会太大。到少我所引用的代码在我这里测试很顺畅。当然我的局域网机子比较少。还有一个问题,一个局域网不可能每个机子都开启你所指定的端口,所以连接都不会建立,也就没有更多资源问题了。只是尝试建立连接的时间等待消耗。 其实应该和程序编写无关。楼主你现在是想要用UDP协议来测试还是TCP协议来测试呢?若你要用UDP基本可以群发给各个主机去测试;但在目的机器上必须要有客户端程序进行接收和回复信息。但你用TCP协议不可能快的;因为TCP通信协议就会复杂以及一些安全考虑(半连接处理和限制)。优点就是不需要在目的机器上安装测试程序。若你觉得多线程去发送信息的效果不理想,TCP协议群发效果也不会有太大提升。 是的 应该是UDP 用broadcast来实现 我写完把代码放出来 再结贴。 另外 TCPIP也是可以的 唯一的问题就是timeout的问题 扫描的时间太TM长了34楼很有道理 传统的TCP链接扫描是最傻一种, 而且消耗CPU资源,相应的时间还跟网络带宽资源有一定的关系。Java没有提供基于IP层的编程接口,无法实现TCP半开/半闭扫描,前面有提到NmapNmap提供了非常全的TCP扫描方式,基础指纹栈识别技术,通过TCP扫描来识别操作系统,进而发现系统漏洞,为下一步入侵系统探路。 组播通过UDP试验 无法查到TCP端口占用信息占个位置 表示关注 OYE.. 你的代码可以不用线程 还有优化的余地 比如用NIO去做 代码回头放送.... package net;import java.io.IOException;import java.net.InetAddress;import java.net.InetSocketAddress;import java.net.SocketAddress;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.SocketChannel;import java.util.Iterator;import java.util.Set;public class JPortScannerByNIO { public static void main(String[] args) throws IOException { int port = 80; int retry = 10;// 重试次数 String ip = InetAddress.getLocalHost().getHostAddress(); String ipHead = ip.substring(0, ip.lastIndexOf('.') + 1); Selector selector = Selector.open(); for (int tail = 60; tail < 65; tail++) { SocketChannel channel = SocketChannel.open(); SocketAddress address = new InetSocketAddress(ipHead + tail, port); channel.configureBlocking(false); channel.connect(address); channel.register(selector, SelectionKey.OP_CONNECT, address);// 这里你也可以用输入或者输出 } while (retry-- > 0) { // selector.select(1000 * 5);这里可以设置超时时间 selector.select(); Set<SelectionKey> keys = selector.selectedKeys(); for (Iterator<SelectionKey> it = keys.iterator(); it.hasNext();) { SelectionKey key = it.next(); it.remove(); if (key.isConnectable()) { System.err.println(key.attachment()); key.cancel(); } } } }}大概意思.. 我是看过 2个问题1. 语言的问题 我需要跨平台解决方案 NMAP不是java搞的2. NMAP有很多的依赖 对于一个商业软件来说 这种依赖很要命 扫描端口是手段 检测到同一network内的机器是目的所以把所有机器装上broadcast就可以了 代码就不放了 简单得很TCPIP确实做不到 快速的扫描 表示关注,如果csdn里有这样的气氛,这样的好帖就好了! 求教:java模拟文件输入 cgi是干什么的?什么时候必须用? 对话框嵌入问题 关于集合类的问题,难。 如何生成jar文件?谢谢 急救!急救!急救! 简单问题求助,如何得知Applet已经失去焦点,如IE最小化时 命令行环境下,一定要在进入源代码文件的目录后才能使用javac吗? 提问:关于JAVA处理网络音频传输的问题???? 关于代码的 java Runtime.exec(); Java写的小程序,求助设置保存的问题。
第一是线程池是个单线程池,如果CPU是多核或连接过程中某个处于阻塞状态到超时,CPU资源利用率很低;
第二是建立套接字是费时的,在call方法中连续创建两个Socket,却并没有调用connect()来连接服务器;
第三是System.out.println是打印流,流是耗资源的,return服务器的IP+个"Timeout,failure"或"Success"就可以了,想看再去调用;
我测试的一个示例也就200多微妙(双核CPU):import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Collection;
import java.util.LinkedList;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;public class JPortScanner1 { public static void main(String[] args) throws InterruptedException, UnknownHostException {
String ipHead;
int lastPoint;
String IP = InetAddress.getLocalHost().getHostAddress(); lastPoint = IP.lastIndexOf('.'); ipHead = IP.substring(0, ++lastPoint); ExecutorService executor = Executors.newCachedThreadPool();
Collection<Callable<String>> list = new LinkedList<Callable<String>>();
long start = System.currentTimeMillis();
for (int tail = 1; tail < 255; tail++) {
list.add(new Task(ipHead, tail, 8081));
}
executor.invokeAll(list);
executor.shutdown();
long end = System.currentTimeMillis();
System.out.println("All time: " + (end - start) + " milliseconds");
}}class Task implements Callable<String> {
String ipHead;
int ipTail;
int port; public Task(String ipHead, int ipTail, int port) {
this.ipHead = ipHead;
this.ipTail = ipTail;
this.port = port;
System.out.println(ipHead + ipTail + ":" + port);
} public String call(){
Socket connect = new Socket();
try {
connect.connect(new InetSocketAddress(ipHead + ipTail, port), 100);
while(true){
if(connect.isConnected()){
//System.out.println(ipHead + ipTail + ":" + port + " success");
break;
}
}
connect.close();
} catch (IOException e) {
//System.out.println(ipHead + ipTail + ":" + port + " failure");
}
return null;
}
}
executor.invokeAll(list, 200L, TimeUnit.MILLISECONDS);
把connect.connect(new InetSocketAddress(ipHead + ipTail, port), 100);放入while(true)中;
我表示:代码有效,但需要修改,
connect.connect(new InetSocketAddress(ipHead + ipTail, port), 100);
我的无线局域网,4台机子,测试80端口(都开通),修改前只能找到自己,将100修改为1000,后,可以找到其它几个机子的80端口。
connect.connect(new InetSocketAddress(ipHead + ipTail, port), 100);
修改为 connect.connect(new InetSocketAddress("sun.java.com", 80), 100);一个测试结果如下(xxx是我手动加的...):xxx.xxx.xxx.22:8081 success
xxx.xxx.xxx.33:8081 success
xxx.xxx.xxx.133:8081 success
xxx.xxx.xxx.127:8081 success
xxx.xxx.xxx.44:8081 success
xxx.xxx.xxx.46:8081 success
xxx.xxx.xxx.48:8081 success
xxx.xxx.xxx.56:8081 success
xxx.xxx.xxx.62:8081 success
xxx.xxx.xxx.66:8081 success
xxx.xxx.xxx.64:8081 success
Actual executing Times : 625 millseconds
All threads executing times : 131840 millseconds
测试connect.connect(new InetSocketAddress("sun.java.com", 80), 100);结果:sun.java.com : 80 success
sun.java.com : 80 success
sun.java.com : 80 success
sun.java.com : 80 success
sun.java.com : 80 success
sun.java.com : 80 success
sun.java.com : 80 success
sun.java.com : 80 success
sun.java.com : 80 success
sun.java.com : 80 success
Actual executing Times : 344 millseconds
All threads executing times : 44085 millseconds
修改后的代码:import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Collection;
import java.util.LinkedList;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;public class JPortScanner1 { public static void main(String[] args) throws InterruptedException, UnknownHostException, ExecutionException {
String ipHead;
int lastPoint;
String IP = InetAddress.getLocalHost().getHostAddress(); lastPoint = IP.lastIndexOf('.'); ipHead = IP.substring(0, ++lastPoint); ExecutorService executor = Executors.newCachedThreadPool();
Collection<Callable<Long>> list = new LinkedList<Callable<Long>>();
Collection<Future<Long>> taskList = null;
for (int tail = 1; tail < 255; tail++) {
list.add(new Task(ipHead, tail, 8081));
}
//executor.invokeAll(list, 1000L, TimeUnit.MILLISECONDS);
long start = System.currentTimeMillis();
taskList = executor.invokeAll(list);
executor.shutdown();
long end = System.currentTimeMillis();
System.out.println("Actual executing Times : " + (end - start) + " millseconds");
long times = 0L;
for(Future<Long> task : taskList){
times += task.get();
}
System.out.println("All threads executing times : " + times + " millseconds");
}}class Task implements Callable<Long> {
String ipHead;
int ipTail;
int port; public Task(String ipHead, int ipTail, int port) {
this.ipHead = ipHead;
this.ipTail = ipTail;
this.port = port;
//System.out.println(ipHead + ipTail + ":" + port);
} public Long call(){
long start = System.currentTimeMillis();
Socket connect = new Socket();
try {
//connect.connect(new InetSocketAddress(ipHead + ipTail, port), 100);
connect.connect(new InetSocketAddress("sun.java.com", 80), 100);
if(connect.isConnected()){
//System.out.println(ipHead + ipTail + ":" + port + " success");
System.out.println("sun.java.com : 80 success");
}
connect.close();
} catch (IOException e) {
//System.out.println(ipHead + ipTail + ":" + port + " failure");
try {
connect.close();
} catch (IOException e1) {
}
}
long end = System.currentTimeMillis();
return (end - start);
}
}
我的局域网内1-254内一共大概有200台机器 但是用你的方法只能找到大概50台 另外的150台无法找到而且每次找到的机器还不太一样 但是基本都是ip从xxx.xxx.xxx.1 - xxx.xxx.xxx.100之内的50台 后面的就一直不能找到。
是不是可以把连接超时设置长一点:
connect.connect(new InetSocketAddress(ipHead + ipTail, port), 100000);
线程池一下子搞255个线程本来就是有问题的 虽然CPU是没有问题
TCP这种方式 好象只能一个一个连接测试,公司也有类似的需求 也没想到好办法,而且这种方式不但慢 占用资源还高。
其实你可以直接的new ThreadPoolExecutor来指定最大线程数:
ThreadPoolExecutor(4, 8, 1000, TimeUnit.MILLISECONDS, new BlockingQueue<Runnable>());至于说能不能上网,那是网络管理设置的问题了;再说现在测试的结果也不保证下次测试是一样的,谁知道接下来会发生什么事情;
也许服务器本身就是个单线程响应 或 现在很忙无法响应...
你打开一个ie,多打开几个不同的站点,可能就是20几个连接,QQ也不会少,要是P2P这种下载工具,就更不用说了。所以我觉得50个连接也不会太大。到少我所引用的代码在我这里测试很顺畅。当然我的局域网机子比较少。还有一个问题,一个局域网不可能每个机子都开启你所指定的端口,所以连接都不会建立,也就没有更多资源问题了。只是尝试建立连接的时间等待消耗。
若你要用UDP基本可以群发给各个主机去测试;但在目的机器上必须要有客户端程序进行接收和回复信息。
但你用TCP协议不可能快的;因为TCP通信协议就会复杂以及一些安全考虑(半连接处理和限制)。优点就是不需要在目的机器上安装测试程序。若你觉得多线程去发送信息的效果不理想,TCP协议群发效果也不会有太大提升。
是的 应该是UDP 用broadcast来实现 我写完把代码放出来 再结贴。
Java没有提供基于IP层的编程接口,无法实现TCP半开/半闭扫描,前面有提到NmapNmap提供了非常全的TCP扫描方式,基础指纹栈识别技术,通过TCP扫描来识别操作系统,进而发现
系统漏洞,为下一步入侵系统探路。
组播通过UDP试验 无法查到TCP端口占用信息占个位置 表示关注 OYE..
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;public class JPortScannerByNIO {
public static void main(String[] args) throws IOException {
int port = 80;
int retry = 10;// 重试次数
String ip = InetAddress.getLocalHost().getHostAddress();
String ipHead = ip.substring(0, ip.lastIndexOf('.') + 1);
Selector selector = Selector.open(); for (int tail = 60; tail < 65; tail++) {
SocketChannel channel = SocketChannel.open(); SocketAddress address = new InetSocketAddress(ipHead + tail, port); channel.configureBlocking(false);
channel.connect(address);
channel.register(selector, SelectionKey.OP_CONNECT, address);// 这里你也可以用输入或者输出
}
while (retry-- > 0) {
// selector.select(1000 * 5);这里可以设置超时时间
selector.select();
Set<SelectionKey> keys = selector.selectedKeys(); for (Iterator<SelectionKey> it = keys.iterator(); it.hasNext();) {
SelectionKey key = it.next();
it.remove(); if (key.isConnectable()) {
System.err.println(key.attachment());
key.cancel();
}
}
}
}
}大概意思..
我是看过 2个问题
1. 语言的问题 我需要跨平台解决方案 NMAP不是java搞的
2. NMAP有很多的依赖 对于一个商业软件来说 这种依赖很要命