1. 概述
使用Java进行端口扫描是一种枚举目标机器上开放或活动端口的方法。主要目标是列出当前运行的应用程序和服务。
在这个教程中,我们将解释如何开发一个简单的Java应用程序来进行端口扫描,以便我们可以用来扫描主机上的开放端口。
2. 计算机端口是什么?
计算机端口是一个逻辑实体,它使得可以将特定服务与连接关联起来。此外,端口由1到65535之间的整数标识。按照惯例,前1024个端口被保留给标准服务,如:
- 端口20:FTP
- 端口23:Telnet
- 端口25:SMTP
- 端口80:HTTP
端口扫描的思路是创建一个TCP套接字,并尝试连接到特定端口。如果连接成功建立,我们就标记这个端口为开放;否则,标记为关闭。
然而,逐一尝试连接65535个端口可能需要大约200毫秒,这听起来时间不长,但对单个主机的所有端口进行逐一扫描可能会花费相当多的时间。
为了解决性能问题,我们将采用多线程(multithreaded)方法。这相比顺序连接每个端口,能大大提高扫描速度。
3. 实现
为了实现我们的程序,我们创建一个带有两个参数的函数portScan()
:
-
ip
:要扫描的IP地址,对于localhost来说,相当于127.0.0.1 -
nbrPortMaxToScan
:要扫描的最大端口号数量,如果我们想扫描所有端口,这个数字等于65535
3.1. 实现
让我们看看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"));
}
该方法返回一个包含所有开放端口的列表。为此,我们创建一个新的Socket对象,作为两个主机之间连接的桥梁。如果连接成功建立,我们就假设端口是开放的,然后继续下一行。相反,如果连接失败,我们就假设端口是关闭的,并抛出一个SocketTimeoutException
异常,然后进入异常处理块。
3.2. 多线程
为了优化扫描目标机器所有65535个端口所需的时间,我们将并行运行我们的方法。我们使用ExecutorService
,它封装了一个线程池和一个任务队列,用于执行任务。池中的所有线程仍在运行。
服务检查队列中是否有待处理的任务,如果有,就取出任务并执行。任务执行完毕后,线程再次等待服务从队列中分配新的任务。
此外,我们使用一个具有10个线程的FixedThreadPool
,这意味着程序最多将并行运行10个线程。我们可以根据我们的机器配置和能力调整线程池大小。
4. 总结
在这篇简短的教程中,我们解释了如何使用Socket和多线程方法开发一个简单的Java端口扫描应用程序。
如往常一样,代码片段可在GitHub上找到。