gpt4 book ai didi

java - 使用 Java 扫描端口的最快方法

转载 作者:IT老高 更新时间:2023-10-28 21:07:15 25 4
gpt4 key购买 nike

我做了一个非常简单的端口扫描器,但是它运行得太慢了,所以我正在寻找一种方法让它扫描得更快。这是我的代码:

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 需要太多时间。有没有其他方法可以在不到 5 分钟的时间内从 0 扫描到 65535?

最佳答案

如果 65536 个端口中的每一个都需要 200 毫秒(在最坏的情况下,防火墙会阻止一切,从而使每个端口都达到超时),那么数学很简单:你需要 13k 秒,或者大约三个半小时。

您有 2 个(非排他性的)选项可以加快速度:

  • 缩短超时时间
  • 并行化您的代码

由于操作是受 I/O 限制的(与 CPU 限制相反——也就是说,您花时间等待 I/O,而不是等待完成一些庞大的计算),您可以使用很多很多线程。尝试从 20 开始。他们会在其中划分 3 个半小时,因此最长预计时间约为 10 分钟。请记住,这会给另一边施加压力,即被扫描的主机将看到具有“不合理”或“奇怪”模式的巨大网络 Activity ,从而使扫描极易被检测到。

最简单的方法(即更改最少)是使用 ExecutorService 和 Future 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
}

然后,更改 BooleanScanResult在第一个片段中,并返回 new ScanResult(port, true)new ScanResult(port, false)而不仅仅是truefalse

编辑:实际上,我只是注意到:在这种特殊情况下,您不需要 ScanResult 类来保存结果+端口,并且仍然知道哪个端口是打开的。由于您将 future 添加到 有序List,然后您按照添加它们的相同顺序处理它们,你可以有一个计数器,你会在每次迭代时递增,以知道你正在处理哪个端口。但是,嘿,这只是为了完整和准确。 永远不要尝试这样做,这太可怕了,我很惭愧我想到了这个...... 使用 ScanResult 对象更干净,代码是更易于阅读和维护,并允许您稍后使用 CompletionService改进扫描仪。

关于java - 使用 Java 扫描端口的最快方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11547082/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com