使用Java扫描端口的最快方法 [英] Fastest way to scan ports with Java

查看:343
本文介绍了使用Java扫描端口的最快方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我制作了非常简单的端口扫描程序,但运行速度太慢,所以我正在寻找方法让它扫描得更快。这是我的代码:

I made very simple port scanner, but it runs too slow, so I'm looking for way to make it scan faster. Here is my code:

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?

this code here test if specific port is open on specific ip. For timeout I use minimum value of 200 because when I go lower it doesnt have enough time to test the port. Well It works well, but takes too much to scan from 0 to 65535. Is there any other way that could maybe scan from 0 to 65535 in less than 5 minutes?

推荐答案

如果65536端口中的每一个都需要200ms(在最坏的情况下,防火墙会阻止所有端口,从而使您在每个端口都达到超时),数学非常简单:你需要13k秒,或大约3个半小时。

If you need 200ms for each of the 65536 ports (in the worst case, a firewall is blocking everything, thus making you hit your timeout for every single port), the maths is pretty simple: you need 13k seconds, or about 3 hours and a half.

你有2个(非独家)选项让它更快:

You have 2 (non-exclusive) options to make it faster:


  • 减少超时

  • 对你的代码进行并行化

由于操作是I / O限制的(与CPU绑定相反 - 也就是说,你花时间等待I / O,而不是完成一些大的计算),你可以使用很多,很多线程。尝试从20开始。他们将在其中划分3个半小时,所以最大预期时间约为10分钟。请记住,这会对另一方施加压力,即扫描的主机将看到具有不合理或奇怪模式的巨大网络活动,使扫描非常容易检测。

Since the operation is I/O bound (in contrast to CPU bound -- that is, you spend time waiting for I/O, and not for some huge calculation to complete), you can use many, many threads. Try starting with 20. They would divide the 3 hours and a half among them, so the maximum expected time is about 10 minutes. Just remember that this will put pressure on the other side, ie, the scanned host will see huge network activity with "unreasonable" or "strange" patterns, making the scan extremely easy to detect.

最简单的方法(即最小的更改)是使用ExecutorService和Future API:

The easiest way (ie, with minimal changes) is to use the ExecutorService and Future APIs:

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;
        }
      }
   });
}

然后,您可以执行以下操作:

Then, you can do something like:

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 将保留端口和扫描结果,如:

If you need to know which ports are open (and not just how many, as in the above example), you'd need to change the return type of the function to Future<SomethingElse>, where SomethingElse would hold the port and the result of the scan, something like:

public final class ScanResult {
  private final int port;
  private final boolean isOpen;
  // constructor
  // getters
}

然后,在第一个代码段中将布尔更改为 ScanResult ,并返回 new ScanResult(port,true) 新的ScanResult(port,false)而不是 true false

Then, change Boolean to ScanResult in the first snippet, and return new ScanResult(port, true) or new ScanResult(port, false) instead of just true or false

编辑:实际上,我刚注意到:在这种特殊情况下,你不需要ScanResult类来保存结果+端口,仍然知道哪个端口是打开的。由于您将期货添加到列表已订购,稍后您按照添加它们的相同顺序处理它们,您可以拥有一个计数器,您可以在每次迭代时递增以知道您正在处理哪个端口。但是,嘿,这只是完整而准确的。 不要尝试那样做,这太可怕了,我为此感到羞耻,我想到了这个...... 使用ScanResult对象更清洁,代码是方便阅读和维护,并允许您稍后使用 CompletionService 来改进扫描仪。

Actually, I just noticed: in this particular case, you don't need the ScanResult class to hold result + port, and still know which port is open. Since you add the futures to a List, which is ordered, and, later on, you process them in the same order you added them, you could have a counter that you'd increment on each iteration to know which port you are dealing with. But, hey, this is just to be complete and precise. Don't ever try doing that, it is horrible, I'm mostly ashamed that I thought about this... Using the ScanResult object is much cleaner, the code is way easier to read and maintain, and allows you to, later, for example, use a CompletionService to improve the scanner.

这篇关于使用Java扫描端口的最快方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆