用Java扫描端口的最快方法

用Java扫描端口的最快方法,java,sockets,ip,port-scanning,Java,Sockets,Ip,Port Scanning,我做了一个非常简单的端口扫描器,但是它运行得太慢了,所以我正在寻找一种方法使它扫描得更快。这是我的密码: public boolean portIsOpen(String ip, int port, int timeout) { try { Socket socket = new Socket(); socket.connect(new InetSocketAddress(ip, port), timeout); socket.close(

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

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端口都需要200ms(在最坏的情况下,防火墙会封锁所有端口,从而使每个端口都超时),那么数学很简单:需要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;
        }
      }
   });
}
然后,将第一个代码段中的
Boolean
更改为
ScanResult
,并返回
new ScanResult(port,true)
new ScanResult(port,false)
,而不只是
true
false


编辑:实际上,我刚刚注意到:在这种特殊情况下,您不需要ScanResult类来保存result+端口,并且仍然知道哪个端口是打开的。由于您将未来添加到一个排序为列表,并且以后按照添加它们的相同顺序对它们进行处理,因此您可以拥有一个计数器,在每次迭代中递增该计数器,以了解您要处理的端口。但是,嘿,这只是为了完整和准确永远不要尝试那样做,这太可怕了,想到这一点我感到非常羞愧使用ScanResult对象更干净,代码更易于阅读和维护,并且允许您在以后使用
CompletionService
来改进扫描仪。

除了并行扫描外,您还可以使用更高级的端口扫描技术,如TCP SYN和TCP FIN扫描)此处解释:。可在此处找到实现的VB代码:


但是,为了使用这些技术,您需要使用原始TCP/IP套接字。您应该为此使用库。

如果您决定使用Nmap选项并想继续使用Java,您应该查看


这是一个简单的API,允许您将Nmap集成到java应用程序中。

代码示例的灵感来自“Bruno Reis”

类端口扫描程序{ 公共静态void main(最终字符串…args)抛出InterruptedException、ExecutionException{ final Executors服务es=Executors.newFixedThreadPool(20); 最终字符串ip=“127.0.0.1”; 最终int超时=200; 最终列表期货=新的ArrayList();
对于(int port=1;port我编写了自己的异步portscanner java服务,它可以像Nmap一样通过TCP SYN scan扫描端口。它还支持IMCP ping扫描,并且可以以非常高的吞吐量工作(取决于网络能够支持什么):


在内部,它使用java绑定pcap,并通过JMS/AMQP公开其服务。尽管您也可以在应用程序中直接使用它(如果您不介意它具有根权限)。

不,这里最快的方法是使用动态创建的线程方法

Executors.newCachedThreadPool();
通过这种方式,它使用线程直到所有线程都被执行,然后当所有线程都被执行并且有一个新任务时,它将打开一个新线程并在其上执行新任务

这是我的代码片段(由Jack和Bruno Reis带来的信任)

我还添加了一个功能来搜索您键入的任何IP地址,以获得一些附加功能和易用性

    import java.net.InetSocketAddress;
    import java.net.Socket;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Scanner;
    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;

    class PortScanner {

    public static void main(final String... args) throws InterruptedException, ExecutionException 
    {
        final ExecutorService es = Executors.newCachedThreadPool();
        System.out.print("Please input the ip address you would like to scan for open ports: ");
        Scanner inputScanner = new Scanner(System.in);
        final String ip = inputScanner.nextLine();
        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)");
 es.shutdown();
    }



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

    }
    }
导入java.net.InetSocketAddress;
导入java.net.Socket;
导入java.util.ArrayList;
导入java.util.List;
导入java.util.Scanner;
导入java.util.concurrent.Callable;
导入java.util.concurrent.ExecutionException;
导入java.util.concurrent.ExecutorService;
导入java.util.concurrent.Executors;
导入java.util.concurrent.Future;
导入java.util.concurrent.TimeUnit;
类端口扫描程序{
公共静态void main(最终字符串…args)抛出InterruptedException、ExecutionException
{
final Executor服务es=Executors.newCachedThreadPool();
System.out.print(“请输入您希望扫描打开端口的ip地址:”;
扫描仪输入扫描仪=新扫描仪(System.in);
最后一个字符串ip=inputScanner.nextLine();
最终int超时=200;
最终列表期货=新的ArrayList();

对于(int-port=1;端口我没有使用它,但不会使用SocketFactory()还有帮助吗?我真的看不出使用SocketFactory与这个问题有什么关系。你能解释一下你的想法吗?我认为SocketFactory可以实现为在后台有一个类似SocketPool的东西,这可以提高速度。不确定这是否有效。这不是一个建议,只是对你的方法的一个查询。“SocketPool”一个TCP套接字是四倍<代码>(SRC IP,SRC端口,Dest-IP,Dest-Posits)< /C> >是不可变的(即,你不能改变连接中的IPS或端口);因为你测试的每个端口都是一个不同的DeST端口,你需要为你测试的每个端口需要一个不同的TCP套接字,因此没有POO。
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;
    }

}
}
Executors.newCachedThreadPool();
    import java.net.InetSocketAddress;
    import java.net.Socket;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Scanner;
    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;

    class PortScanner {

    public static void main(final String... args) throws InterruptedException, ExecutionException 
    {
        final ExecutorService es = Executors.newCachedThreadPool();
        System.out.print("Please input the ip address you would like to scan for open ports: ");
        Scanner inputScanner = new Scanner(System.in);
        final String ip = inputScanner.nextLine();
        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)");
 es.shutdown();
    }



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

    }
    }