使用 Java Swing 写一个子域名扫描工具,要求多线程,有开启,暂停,停止功能,支持域名字典导入

由于该任务需要创建 GUI 界面和多线程处理,建议使用 Swing 和 Java 线程来实现。

以下是一个简单的实现:

  1. 创建 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);
    }
}
  1. 实现多线程扫描

为了实现多线程扫描,我们需要创建一个类来继承 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 用于停止扫描任务。

  1. 实现导入字典功能

为了支持导入字典功能,我们可以在 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 类读取文件内容。如果字典导入成功,会弹出一个提示对话框。

  1. 实现启动、暂停和停止扫描功能

在 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();
            }
        });
    }
}
  1. 完整代码
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();
    }
}
Java Swing 子域名扫描工具 - 多线程,暂停,停止功能,支持字典导入

原文地址: https://www.cveoy.top/t/topic/lDwS 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录