1. Overview
1.概述
Port scanning with Java is a method of enumerating the open or active ports of a target machine. The goal is mainly to list the open ports in order to know the applications and services that are currently running.
用Java进行端口扫描是一种列举目标机器的开放或活动端口的方法。其目的主要是列出开放的端口,以便了解当前正在运行的应用程序和服务。
In this tutorial, we’ll explain how to develop a simple application for port scanning with Java that we can use to scan a host for open ports.
在本教程中,我们将解释如何用Java开发一个简单的端口扫描应用程序,我们可以用它来扫描一个主机的开放端口。
2. What Is a Computer Port?
2.什么是计算机端口?
A computer port is a logical entity that makes it possible to associate a particular service with a connection. Furthermore, a port is identified by an integer from 1 to 65535. By convention, the first 1024 are reserved for standard services such as:
计算机端口是一个逻辑实体,它使人们有可能将一个特定的服务与一个连接联系起来。此外,一个端口由一个从1到65535的整数来标识。根据惯例,前1024个被保留给标准服务,如:。
- Port 20: FTP
- Port 23: Telnet
- Port 25: SMTP
- Port 80: HTTP
The idea of a port scanner is to create a TCP Socket and try to connect to a specific port. If the connection is successfully established, then we’ll mark this port as open, and if not, we’ll mark it as closed.
端口扫描器的想法是创建一个TCPSocket并尝试连接到一个特定的端口。如果连接成功建立,那么我们将把这个端口标记为开放,如果不是,我们将把它标记为关闭。
However, establishing a connection on each of the 65535 ports can take up to 200 ms per port. This may sound like a short amount of time, but in total, it would take a considerable amount of time to scan all ports of a single host one by one.
然而,在65535个端口中的每一个上建立一个连接,每个端口可能需要200毫秒。这听起来是很短的时间,但总的来说,逐一扫描一台主机的所有端口需要相当长的时间。
To solve the performance issue, we’ll use the multi-threaded approach. This can dramatically speed up the process compared to attempting to connect to each port sequentially.
为了解决性能问题,我们将使用multi-threaded方法。与试图依次连接每个端口相比,这可以极大地加快这一过程。
3. Implementation
3.实施
To implement our program, we create a function portScan() with two parameters as input:
为了实现我们的程序,我们创建了一个函数portScan(),有两个参数作为输入。
- ip: the IP address to scan; it’s equivalent to 127.0.0.1 for localhost
- nbrPortMaxToScan: the maximal number of ports to scan; this number is equivalent to 65535 if we want to scan all ports
3.1 Implementation
3.1 实施
Let’s see what our portScan() method looks like:
让我们看看我们的portScan()方法是什么样子。
public void runPortScan(String ip, int nbrPortMaxToScan) throws IOException {
ConcurrentLinkedQueue openPorts = new ConcurrentLinkedQueue<>();
ExecutorService executorService = Executors.newFixedThreadPool(poolSize);
AtomicInteger port = new AtomicInteger(0);
while (port.get() < nbrPortMaxToScan) {
final int currentPort = port.getAndIncrement();
executorService.submit(() -> {
try {
Socket socket = new Socket();
socket.connect(new InetSocketAddress(ip, currentPort), timeOut);
socket.close();
openPorts.add(currentPort);
System.out.println(ip + " ,port open: " + currentPort);
} catch (IOException e) {
System.err.println(e);
}
});
}
executorService.shutdown();
try {
executorService.awaitTermination(10, TimeUnit.MINUTES);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
List openPortList = new ArrayList<>();
System.out.println("openPortsQueue: " + openPorts.size());
while (!openPorts.isEmpty()) {
openPortList.add(openPorts.poll());
}
openPortList.forEach(p -> System.out.println("port " + p + " is open"));
}
Our method returns a List with all open ports. To do so, we create a new Socket object to be used as a connector between two hosts. If a connection is successfully established, then we assume that the port is open, in which case we continue to the next line. On the other hand, if the connection fails, then we assume that the port is closed and a SocketTimeoutException is thrown and we are thrown to the exception catch block.
我们的方法返回一个包含所有开放端口的List。为此,我们创建了一个新的Socket对象,作为两个主机之间的连接器。如果一个连接被成功建立,那么我们就认为该端口是开放的,在这种情况下,我们继续下一行。另一方面,如果连接失败,那么我们假定端口是关闭的,并抛出一个SocketTimeoutException ,我们被抛向异常catch块。
3.2 Multithreading
3.2 多线程
In order to optimize the amount of time needed to scan all 65535 Ports of the target machine, we’ll run our method concurrently. We use the ExecutorService, which encapsulates a pool of threads and a queue of tasks to be executed. All threads in the pool are still running.
为了优化扫描目标机器的所有65535个端口所需的时间,我们将并发地运行我们的方法。我们使用ExecutorService,它封装了一个线程池和一个待执行的任务队列。池中的所有线程都还在运行。
The service checks if a task is to be processed in the queue and, if so, it withdraws the task and executes it. Once the task is executed, the thread waits again for the service to assign it a new task from the queue.
服务检查队列中是否有任务要被处理,如果有,它就撤回任务并执行它。一旦任务被执行,线程再次等待服务从队列中分配给它一个新任务。
Furthermore, we use a FixedThreadPool with 10 Threads, which means that the program is going to run up to a maximum of 10 threads in parallel. We can adjust this pool size according to our machine configuration and capacities.
此外,我们使用一个有10个Thread的FixedThreadPool,这意味着程序最多可以并行运行10个线程。我们可以根据我们的机器配置和能力来调整这个池的大小。
4. Conclusion
4.总结
In this quick tutorial, we explained how to develop a simple application for port scanning with Java using Sockets and a multi-threaded approach.
在这个快速教程中,我们解释了如何使用Sockets和多线程方法开发一个用于端口扫描的简单应用。
As always, the code snippets are available over on GitHub.
像往常一样,代码片段可在GitHub上获得。