Java Swing 子域名扫描工具 - 多线程,暂停,停止功能,支持字典导入
使用 Java Swing 写一个子域名扫描工具,要求多线程,有开启,暂停,停止功能,支持域名字典导入
由于该任务需要创建 GUI 界面和多线程处理,建议使用 Swing 和 Java 线程来实现。
以下是一个简单的实现:
- 创建 GUI 界面
在 Swing 中,可以使用 JFrame、JPanel、JButton 等组件来创建 GUI 界面。在这个任务中,我们需要以下组件:
- JTextField:用于输入目标域名。
- JTextArea:用于显示扫描结果。
- JButton:用于启动、暂停和停止扫描。
- JProgressBar:用于显示扫描进度。
首先,我们需要创建一个 JFrame,然后在其中添加以上组件。
import javax.swing.*;
public class SubdomainScanner extends JFrame {
private JPanel mainPanel;
private JTextField domainTextField;
private JTextArea resultTextArea;
private JButton startButton;
private JButton pauseButton;
private JButton stopButton;
private JProgressBar progressBar;
private JButton dictionaryButton;
private String[] dictionary;
private ScannerThread scannerThread;
public SubdomainScanner() {
// 设置窗口标题
setTitle('子域名扫描工具');
// 设置窗口大小
setSize(600, 400);
// 创建主面板
mainPanel = new JPanel();
// 创建组件并添加到主面板中
domainTextField = new JTextField(20);
mainPanel.add(domainTextField);
resultTextArea = new JTextArea(20, 50);
mainPanel.add(new JScrollPane(resultTextArea));
startButton = new JButton('开始');
mainPanel.add(startButton);
pauseButton = new JButton('暂停');
mainPanel.add(pauseButton);
stopButton = new JButton('停止');
mainPanel.add(stopButton);
progressBar = new JProgressBar(0, 100);
progressBar.setStringPainted(true);
mainPanel.add(progressBar);
dictionaryButton = new JButton('导入字典');
mainPanel.add(dictionaryButton);
// 将主面板添加到窗口中
add(mainPanel);
// 设置窗口可见
setVisible(true);
}
}
- 实现多线程扫描
为了实现多线程扫描,我们需要创建一个类来继承 Thread 类,并重写其 run 方法,用于执行扫描任务。在 run 方法中,我们可以使用 Java 的 Socket 类来进行 DNS 解析和端口扫描。为了防止阻塞主线程,我们需要使用 SwingUtilities.invokeLater 方法来更新 GUI 界面。
import java.net.*;
import javax.swing.*;
public class ScannerThread extends Thread {
private String domain;
private JTextArea resultArea;
private JProgressBar progressBar;
private volatile boolean paused;
private volatile boolean stopped;
public ScannerThread(String domain, JTextArea resultArea, JProgressBar progressBar) {
this.domain = domain;
this.resultArea = resultArea;
this.progressBar = progressBar;
}
public void pause() {
paused = true;
}
public void resumeThread() {
paused = false;
}
public void stopThread() {
stopped = true;
}
@Override
public void run() {
// TODO: 扫描任务
}
}
在 ScannerThread 类中,我们还添加了 paused、stopped、pause、resumeThread 和 stopThread 方法。paused 和 stopped 用于控制扫描的状态,pause 和 resumeThread 用于暂停和恢复扫描任务,stopThread 用于停止扫描任务。
- 实现导入字典功能
为了支持导入字典功能,我们可以在 GUI 界面中添加一个按钮,用于选择字典文件。在按钮的 ActionListener 中,我们可以使用 Java 的 FileChooser 类来打开文件选择对话框,让用户选择字典文件。然后,我们可以使用 Java 的 Scanner 类来读取字典文件中的内容,并将其存储在一个字符串数组中,以便后续使用。
import java.io.*;
import java.util.*;
import javax.swing.*;
public class SubdomainScanner extends JFrame {
// ...
private JButton dictionaryButton;
private String[] dictionary;
public SubdomainScanner() {
// ...
dictionaryButton = new JButton('导入字典');
mainPanel.add(dictionaryButton);
dictionaryButton.addActionListener(e -> {
JFileChooser fileChooser = new JFileChooser();
int result = fileChooser.showOpenDialog(this);
if (result == JFileChooser.APPROVE_OPTION) {
File file = fileChooser.getSelectedFile();
try (Scanner scanner = new Scanner(file)) {
List<String> lines = new ArrayList<>();
while (scanner.hasNextLine()) {
String line = scanner.nextLine().trim().toLowerCase();
if (!line.isEmpty()) {
lines.add(line);
}
}
dictionary = lines.toArray(new String[lines.size()]);
JOptionPane.showMessageDialog(this, '字典导入成功!');
} catch (IOException ex) {
JOptionPane.showMessageDialog(this, '字典导入失败:' + ex.getMessage(), '错误', JOptionPane.ERROR_MESSAGE);
}
}
});
}
}
在以上代码中,我们使用了 Java 8 的 Lambda 表达式来简化代码。在文件选择对话框中,我们只选择 txt 文件,并使用 Scanner 类读取文件内容。如果字典导入成功,会弹出一个提示对话框。
- 实现启动、暂停和停止扫描功能
在 GUI 界面中,我们添加了三个按钮:启动、暂停和停止。在启动按钮的 ActionListener 中,我们创建一个 ScannerThread 对象,并启动该线程。在扫描过程中,我们可以使用 SwingUtilities.invokeLater 方法来更新 GUI 界面。在暂停按钮的 ActionListener 中,我们调用 ScannerThread 的 pause 方法来暂停扫描任务。在停止按钮的 ActionListener 中,我们调用 ScannerThread 的 stopThread 方法来停止扫描任务。
import javax.swing.*;
public class SubdomainScanner extends JFrame {
// ...
private ScannerThread scannerThread;
public SubdomainScanner() {
// ...
startButton.addActionListener(e -> {
String domain = domainTextField.getText().trim().toLowerCase();
if (domain.isEmpty()) {
JOptionPane.showMessageDialog(this, '请输入目标域名!', '提示', JOptionPane.WARNING_MESSAGE);
domainTextField.requestFocus();
return;
}
if (dictionary == null || dictionary.length == 0) {
JOptionPane.showMessageDialog(this, '请先导入字典!', '提示', JOptionPane.WARNING_MESSAGE);
return;
}
scannerThread = new ScannerThread(domain, resultTextArea, progressBar);
scannerThread.start();
});
pauseButton.addActionListener(e -> {
if (scannerThread != null) {
scannerThread.pause();
}
});
stopButton.addActionListener(e -> {
if (scannerThread != null) {
scannerThread.stopThread();
}
});
}
}
- 完整代码
import java.awt.*;
import java.io.*;
import java.net.*;
import java.util.*;
import javax.swing.*;
public class SubdomainScanner extends JFrame {
private JPanel mainPanel;
private JTextField domainTextField;
private JTextArea resultTextArea;
private JButton startButton;
private JButton pauseButton;
private JButton stopButton;
private JProgressBar progressBar;
private JButton dictionaryButton;
private String[] dictionary;
private ScannerThread scannerThread;
public SubdomainScanner() {
// 设置窗口标题
setTitle('子域名扫描工具');
// 设置窗口大小
setSize(600, 400);
// 创建主面板
mainPanel = new JPanel();
// 创建组件并添加到主面板中
domainTextField = new JTextField(20);
mainPanel.add(domainTextField);
resultTextArea = new JTextArea(20, 50);
mainPanel.add(new JScrollPane(resultTextArea));
startButton = new JButton('开始');
mainPanel.add(startButton);
pauseButton = new JButton('暂停');
mainPanel.add(pauseButton);
stopButton = new JButton('停止');
mainPanel.add(stopButton);
progressBar = new JProgressBar(0, 100);
progressBar.setStringPainted(true);
mainPanel.add(progressBar);
dictionaryButton = new JButton('导入字典');
mainPanel.add(dictionaryButton);
// 将主面板添加到窗口中
add(mainPanel);
// 设置窗口可见
setVisible(true);
// 添加事件监听器
startButton.addActionListener(e -> {
String domain = domainTextField.getText().trim().toLowerCase();
if (domain.isEmpty()) {
JOptionPane.showMessageDialog(this, '请输入目标域名!', '提示', JOptionPane.WARNING_MESSAGE);
domainTextField.requestFocus();
return;
}
if (dictionary == null || dictionary.length == 0) {
JOptionPane.showMessageDialog(this, '请先导入字典!', '提示', JOptionPane.WARNING_MESSAGE);
return;
}
scannerThread = new ScannerThread(domain, resultTextArea, progressBar);
scannerThread.start();
});
pauseButton.addActionListener(e -> {
if (scannerThread != null) {
scannerThread.pause();
}
});
stopButton.addActionListener(e -> {
if (scannerThread != null) {
scannerThread.stopThread();
}
});
dictionaryButton.addActionListener(e -> {
JFileChooser fileChooser = new JFileChooser();
int result = fileChooser.showOpenDialog(this);
if (result == JFileChooser.APPROVE_OPTION) {
File file = fileChooser.getSelectedFile();
try (Scanner scanner = new Scanner(file)) {
List<String> lines = new ArrayList<>();
while (scanner.hasNextLine()) {
String line = scanner.nextLine().trim().toLowerCase();
if (!line.isEmpty()) {
lines.add(line);
}
}
dictionary = lines.toArray(new String[lines.size()]);
JOptionPane.showMessageDialog(this, '字典导入成功!');
} catch (IOException ex) {
JOptionPane.showMessageDialog(this, '字典导入失败:' + ex.getMessage(), '错误', JOptionPane.ERROR_MESSAGE);
}
}
});
}
private static class ScannerThread extends Thread {
private String domain;
private JTextArea resultArea;
private JProgressBar progressBar;
private volatile boolean paused;
private volatile boolean stopped;
public ScannerThread(String domain, JTextArea resultArea, JProgressBar progressBar) {
this.domain = domain;
this.resultArea = resultArea;
this.progressBar = progressBar;
}
public void pause() {
paused = true;
}
public void resumeThread() {
paused = false;
}
public void stopThread() {
stopped = true;
}
@Override
public void run() {
String[] subdomains = dictionary;
int total = subdomains.length;
int count = 0;
int found = 0;
for (String subdomain : subdomains) {
if (stopped) {
break;
}
if (!subdomain.isEmpty()) {
String hostname = subdomain + '.' + domain;
try {
InetAddress[] addresses = InetAddress.getAllByName(hostname);
for (InetAddress addr : addresses) {
if (stopped) {
break;
}
String ip = addr.getHostAddress();
String line = hostname + ' [' + ip + ']';
SwingUtilities.invokeLater(() -> resultArea.append(line + '\n'));
found++;
}
} catch (UnknownHostException ex) {
// ignore
}
count++;
int progress = count * 100 / total;
SwingUtilities.invokeLater(() -> progressBar.setValue(progress));
while (paused) {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
// ignore
}
}
}
}
SwingUtilities.invokeLater(() -> {
progressBar.setValue(100);
progressBar.setString('扫描完成!');
});
}
}
public static void main(String[] args) {
new SubdomainScanner();
}
}
原文地址: https://www.cveoy.top/t/topic/lDwS 著作权归作者所有。请勿转载和采集!