我做了很简单的端口扫描器,但它运行速度太慢,所以我在寻找方法,使之更快地扫描。 这里是我的代码:
public boolean portIsOpen(String ip, int port, int timeout) {
try {
Socket socket = new Socket();
socket.connect(new InetSocketAddress(ip, port), timeout);
socket.close();
return true;
} catch (Exception ex) {
return false;
}
}
这里的代码测试,如果特定端口上的特定IP开放。 对于超时我用的200最小值,因为当我去降低它没有足够的时间来测试该端口。 那么它运作良好,但需要太多的扫描从0到65535是否有也许可以从0到65535不到5分钟扫描任何其他方式?
如果你需要200毫秒为每个65536个端口(在最坏的情况下,防火墙阻止了一切,从而使你打你的每一个端口超时),在数学很简单:你需要13K秒,或者约3小时一半。
你有2个(非独家)选项,使其更快:
由于该操作是I /界O(对比势必CPU -也就是说,你花时间等待I / O,而不是为一些巨大的计算来完成), 您可以用很多很多的线程 。 尝试用20起他们将分成3个半小时当中, 所以预期的最大时间约为10分钟 。 请记住,这将施压的另一面,即扫描主机会看到“不合理”或“奇怪”的模式庞大的网络活动,使得扫描非常容易察觉。
最简单的方法(即以最小的变化)是使用ExecutorService的和未来的API:
public static Future<Boolean> portIsOpen(final ExecutorService es, final String ip, final int port, final int timeout) {
return es.submit(new Callable<Boolean>() {
@Override public Boolean call() {
try {
Socket socket = new Socket();
socket.connect(new InetSocketAddress(ip, port), timeout);
socket.close();
return true;
} catch (Exception ex) {
return false;
}
}
});
}
然后,你可以这样做:
public static void main(final String... args) {
final ExecutorService es = Executors.newFixedThreadPool(20);
final String ip = "127.0.0.1";
final int timeout = 200;
final List<Future<Boolean>> futures = new ArrayList<>();
for (int port = 1; port <= 65535; port++) {
futures.add(portIsOpen(es, ip, port, timeout));
}
es.shutdown();
int openPorts = 0;
for (final Future<Boolean> f : futures) {
if (f.get()) {
openPorts++;
}
}
System.out.println("There are " + openPorts + " open ports on host " + ip + " (probed with a timeout of " + timeout + "ms)");
}
如果您需要知道哪些端口是开放的 (而不是有多少 ,如上面的例子),你需要改变功能的返回类型Future<SomethingElse>
其中SomethingElse
将持有端口和结果扫描的,是这样的:
public final class ScanResult {
private final int port;
private final boolean isOpen;
// constructor
// getters
}
然后,更改Boolean
到ScanResult
在第一个片段,并返回new ScanResult(port, true)
或new ScanResult(port, false)
,而不是仅仅的true
或false
编辑:其实,我只注意到:在这种特殊情况下,你不需要ScanResult类来保存结果+端口,并且还知道哪些端口是开放的。 既然你添加期货清单 ,该清单是有序的 ,并且,以后,你在你加入他们的相同顺序处理它们 ,你可以有你想要增加在每次迭代知道你正在处理哪个端口计数器。 但是,嘿,这只是为了完整和明确。 千万不要尝试这样做,这太可怕了,我主要是惭愧,我想过这个... 使用ScanResult对象是干净多了 ,代码的方式更容易阅读和维护,并允许你,以后,例如,使用CompletionService
来提高扫描仪。
除了并行扫描时,可以使用更先进的端口扫描技术,像的那些(TCP SYN和TCP FIN扫描)这里解释: http://nmap.org/nmap_doc.html 。 实现的VB代码可以在这里找到: http://h.ackack.net/spoon-worlds-fastest-port-scanner.html
为了使用这些技术,但是,您需要使用原始TCP / IP套接字。 您应该使用RockSaw库这一点。
代码示例由“布鲁诺雷斯”的启发
class PortScanner {
public static void main(final String... args) throws InterruptedException, ExecutionException {
final ExecutorService es = Executors.newFixedThreadPool(20);
final String ip = "127.0.0.1";
final int timeout = 200;
final List<Future<ScanResult>> futures = new ArrayList<>();
for (int port = 1; port <= 65535; port++) {
// for (int port = 1; port <= 80; port++) {
futures.add(portIsOpen(es, ip, port, timeout));
}
es.awaitTermination(200L, TimeUnit.MILLISECONDS);
int openPorts = 0;
for (final Future<ScanResult> f : futures) {
if (f.get().isOpen()) {
openPorts++;
System.out.println(f.get().getPort());
}
}
System.out.println("There are " + openPorts + " open ports on host " + ip + " (probed with a timeout of "
+ timeout + "ms)");
}
public static Future<ScanResult> portIsOpen(final ExecutorService es, final String ip, final int port,
final int timeout) {
return es.submit(new Callable<ScanResult>() {
@Override
public ScanResult call() {
try {
Socket socket = new Socket();
socket.connect(new InetSocketAddress(ip, port), timeout);
socket.close();
return new ScanResult(port, true);
} catch (Exception ex) {
return new ScanResult(port, false);
}
}
});
}
public static class ScanResult {
private int port;
private boolean isOpen;
public ScanResult(int port, boolean isOpen) {
super();
this.port = port;
this.isOpen = isOpen;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public boolean isOpen() {
return isOpen;
}
public void setOpen(boolean isOpen) {
this.isOpen = isOpen;
}
}
}
为Android试试这个真棒图书馆
https://github.com/stealthcopter/AndroidNetworkTools
如果你决定使用Nmap的选项,并希望继续使用Java,你应该看看Nmap4j SourceForge.net上(http://nmap4j.sourceforge.net)。 这是一个简单的API,可以让你的Nmap集成到Java应用程序。
--Jon
我写我自己的异步端口扫描工具Java服务,可以通过TCP-SYN扫描扫描端口像Nmap的一样。 它还支持IMCP平的扫描,并且可以具有非常高的吞吐量工作(这取决于网络能够维持):
https://github.com/subes/invesdwin-webproxy
内部它使用Java绑定PCAP并通过JMS / AMQP公开其服务。 虽然你也可以在你的应用程序直接使用它,如果你不介意它具有root权限。