我做了一个非常简单的端口扫描器,但是它运行得太慢了,所以我正在寻找一种方法让它扫描得更快。这是我的代码:
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?
原文由 Rohit Malish 发布,翻译遵循 CC BY-SA 4.0 许可协议
如果 65536 个端口中的每一个都需要 200 毫秒(在最坏的情况下,防火墙会阻止所有内容,从而使您对每个端口都超时),数学很简单:您需要 13k 秒,或大约 3 小时,并且一半。
您有 2 个(非排他性的)选项可以使其更快:
由于该操作受 I/O 限制(与受 CPU 限制相反——也就是说,您花时间等待 I/O,而不是等待完成一些巨大的计算), 您可以使用很多很多线程。尝试从 20 开始。他们会将 3 个半小时平均分配给他们, 因此最长预计时间约为 10 分钟。请记住,这会给另一端带来压力,即被扫描的主机将看到具有“不合理”或“奇怪”模式的巨大网络活动,从而使扫描非常容易被发现。
最简单的方法(即,更改最少)是使用 ExecutorService 和 Future API:
然后,您可以执行以下操作:
如果您需要知道 _哪些端口是打开的_(而不仅仅是 _多少_,如上例所示),您需要将函数的返回类型更改为
Future<SomethingElse>
,其中SomethingElse
将保留端口和扫描结果,例如:Then, change
Boolean
toScanResult
in the first snippet, and returnnew ScanResult(port, true)
ornew ScanResult(port, false)
instead of justtrue
或false
编辑:实际上,我只是注意到:在这种特殊情况下,您不需要 ScanResult 类来保存结果 + 端口,并且仍然知道哪个端口是打开的。由于您将期货添加到 List 中,这是 有序 的,并且稍后,您 按照添加它们的相同顺序处理它们,您可以有一个计数器,您可以在每次迭代中增加它以了解您正在处理哪个端口.但是,嘿,这只是为了完整和精确。 永远不要尝试这样做,这太可怕了,我很惭愧我想到了这个…… 使用 ScanResult 对象更清晰,代码更容易阅读和维护,并且允许你稍后,例如,使用
CompletionService
来改进扫描仪。