基于Qt的端口扫描程序的设计与实现

发布于:2024-12-18 ⋅ 阅读:(193) ⋅ 点赞:(0)

        下面是一个使用Qt和C++实现的简单端口扫描程序的示例。这个程序将使用TCP connect方法进行端口扫描,并利用多线程技术来提高扫描效率。

1. 创建Qt项目

首先,创建一个新的Qt项目。你可以使用Qt Creator来创建一个Qt Widgets应用程序。

2. 添加必要的头文件

在你的主窗口类文件(例如mainwindow.h)中,添加必要的头文件:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QThread>
#include <QTcpSocket>
#include <QQueue>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class PortScanner : public QThread
{
    Q_OBJECT
public:
    explicit PortScanner(const QString &ip, int startPort, int endPort, QObject *parent = nullptr);
    void run() override;

signals:
    void portOpen(int port);
    void portClosed(int port);
    void scanningFinished();

private:
    QString ip;
    int startPort;
    int endPort;
};

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_scanButton_clicked();
    void onPortOpen(int port);
    void onPortClosed(int port);
    void onScanningFinished();

private:
    Ui::MainWindow *ui;
    QQueue<PortScanner*> scanners;
    int totalPorts;
    int scannedPorts;
};

#endif // MAINWINDOW_H

3. 实现PortScanner类

mainwindow.cpp中实现PortScanner类:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QTcpSocket>
#include <QThread>
#include <QDebug>

PortScanner::PortScanner(const QString &ip, int startPort, int endPort, QObject *parent)
    : QThread(parent), ip(ip), startPort(startPort), endPort(endPort)
{
}

void PortScanner::run()
{
    for (int port = startPort; port <= endPort; ++port) {
        QTcpSocket socket;
        socket.connectToHost(ip, port);
        if (socket.waitForConnected(1000)) {
            emit portOpen(port);
            socket.disconnectFromHost();
        } else {
            emit portClosed(port);
        }
    }
    emit scanningFinished();
}

4. 实现MainWindow类

继续在mainwindow.cpp中实现MainWindow类:

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent), ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    scannedPorts = 0;
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_scanButton_clicked()
{
    QString ip = ui->ipLineEdit->text();
    int startPort = ui->startPortSpinbox->value();
    int endPort = ui->endPortSpinbox->value();
    int threadCount = ui->threadCountSpinbox->value();

    totalPorts = endPort - startPort + 1;
    scannedPorts = 0;
    ui->resultTextBrowser->clear();

    int portsPerThread = totalPorts / threadCount;
    int remainingPorts = totalPorts % threadCount;

    int currentPort = startPort;
    for (int i = 0; i < threadCount; ++i) {
        int end = currentPort + portsPerThread - 1;
        if (remainingPorts > 0) {
            end += 1;
            remainingPorts -= 1;
        }
        PortScanner *scanner = new PortScanner(ip, currentPort, end);
        connect(scanner, &PortScanner::portOpen, this, &MainWindow::onPortOpen);
        connect(scanner, &PortScanner::portClosed, this, &MainWindow::onPortClosed);
        connect(scanner, &PortScanner::scanningFinished, this, &MainWindow::onScanningFinished);
        scanners.enqueue(scanner);
        scanner->start();
        currentPort = end + 1;
    }
}

void MainWindow::onPortOpen(int port)
{
    ui->resultTextBrowser->append("Port " + QString::number(port) + " is open.");
}

void MainWindow::onPortClosed(int port)
{
    // Optionally, you can log closed ports here
}

void MainWindow::onScanningFinished()
{
    if (!scanners.isEmpty()) {
        delete scanners.dequeue();
    }
    scannedPorts++;
    if (scannedPorts >= totalPorts) {
        ui->resultTextBrowser->append("Scanning finished.");
    }
}

5. 设计UI

在Qt Designer中设计主窗口UI,添加以下控件:

  • QLineEdit:用于输入目标IP地址

  • QSpinBox:用于输入起始端口和结束端口

  • QSpinBox:用于输入线程数量

  • QPushButton:用于开始扫描

  • QTextBrowser:用于显示扫描结果

确保在mainwindow.ui中正确设置了这些控件的ObjectName,例如:

  • ipLineEdit

  • startPortSpinbox

  • endPortSpinbox

  • threadCountSpinbox

  • scanButton

  • resultTextBrowser

6. 编译和运行

编译并运行你的Qt项目。输入目标IP地址、端口范围和线程数量,然后点击“扫描”按钮开始端口扫描。

这个示例实现了基本的端口扫描功能,使用TCP connect方法和多线程技术来提高扫描效率。你可以根据需要进一步扩展和优化这个程序,例如添加更多的扫描方法(如TCP SYN和TCP FIN扫描),增加用户界面的友好性,或者改进错误处理机制。

完整代码

为了方便起见,以下是完整的代码示例。

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QThread>
#include <QTcpSocket>
#include <QQueue>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class PortScanner : public QThread
{
    Q_OBJECT
public:
    explicit PortScanner(const QString &ip, int startPort, int endPort, QObject *parent = nullptr);
    void run() override;

signals:
    void portOpen(int port);
    void portClosed(int port);
    void scanningFinished();

private:
    QString ip;
    int startPort;
    int endPort;
};

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_scanButton_clicked();
    void onPortOpen(int port);
    void onPortClosed(int port);
    void onScanningFinished();

private:
    Ui::MainWindow *ui;
    QQueue<PortScanner*> scanners;
    int totalPorts;
    int scannedPorts;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QTcpSocket>
#include <QThread>
#include <QDebug>

PortScanner::PortScanner(const QString &ip, int startPort, int endPort, QObject *parent)
    : QThread(parent), ip(ip), startPort(startPort), endPort(endPort)
{
}

void PortScanner::run()
{
    for (int port = startPort; port <= endPort; ++port) {
        QTcpSocket socket;
        socket.connectToHost(ip, port);
        if (socket.waitForConnected(1000)) {
            emit portOpen(port);
            socket.disconnectFromHost();
        } else {
            emit portClosed(port);
        }
    }
    emit scanningFinished();
}

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent), ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    scannedPorts = 0;
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_scanButton_clicked()
{
    QString ip = ui->ipLineEdit->text();
    int startPort = ui->startPortSpinbox->value();
    int endPort = ui->endPortSpinbox->value();
    int threadCount = ui->threadCountSpinbox->value();

    totalPorts = endPort - startPort + 1;
    scannedPorts = 0;
    ui->resultTextBrowser->clear();

    int portsPerThread = totalPorts / threadCount;
    int remainingPorts = totalPorts % threadCount;

    int currentPort = startPort;
    for (int i = 0; i < threadCount; ++i) {
        int end = currentPort + portsPerThread - 1;
        if (remainingPorts > 0) {
            end += 1;
            remainingPorts -= 1;
        }
        PortScanner *scanner = new PortScanner(ip, currentPort, end);
        connect(scanner, &PortScanner::portOpen, this, &MainWindow::onPortOpen);
        connect(scanner, &PortScanner::portClosed, this, &MainWindow::onPortClosed);
        connect(scanner, &PortScanner::scanningFinished, this, &MainWindow::onScanningFinished);
        scanners.enqueue(scanner);
        scanner->start();
        currentPort = end + 1;
    }
}

void MainWindow::onPortOpen(int port)
{
    ui->resultTextBrowser->append("Port " + QString::number(port) + " is open.");
}

void MainWindow::onPortClosed(int port)
{
    // Optionally, you can log closed ports here
}

void MainWindow::onScanningFinished()
{
    if (!scanners.isEmpty()) {
        PortScanner *scanner = scanners.dequeue();
        scanner->deleteLater();
    }
    scannedPorts++;
    if (scannedPorts >= totalPorts) {
        ui->resultTextBrowser->append("Scanning finished.");
    }
}

mainwindow.ui

你需要在Qt Designer中设计主窗口的UI,包含以下控件:

  • QLineEditipLineEdit,用于输入IP地址

  • QSpinBoxstartPortSpinbox,用于输入起始端口

  • QSpinBoxendPortSpinbox,用于输入结束端口

  • QSpinBoxthreadCountSpinbox,用于输入线程数量

  • QPushButtonscanButton,用于开始扫描

  • QTextBrowserresultTextBrowser,用于显示扫描结果

确保正确设置这些控件的ObjectName,以便在代码中正确引用它们。

运行项目

  1. 创建一个新的Qt Widgets应用程序项目。

  2. 将上述代码分别放入相应的头文件和源文件中。

  3. 在Qt Designer中设计主窗口UI,并确保ObjectName与代码中一致。

  4. 编译并运行项目。

现在,你可以输入目标IP地址、端口范围和线程数量,然后点击“扫描”按钮开始端口扫描。扫描结果将显示在resultTextBrowser中。

注意事项

  • 合法性:确保你只有在获得授权的情况下才能对目标主机进行端口扫描,否则可能违反法律法规。

  • 性能:多线程扫描可以提高扫描速度,但过多的线程可能会导致性能下降或被目标主机封禁。请根据实际情况调整线程数量。

  • 错误处理:当前实现中,对于连接超时或错误情况,统一视为端口关闭。你可以根据需要增加更详细的错误处理和日志记录。

  • 扫描方法:示例中仅实现了TCP connect扫描,你可以进一步扩展,实现其他类型的扫描,如TCP SYN扫描等。但需要注意,某些扫描方法可能需要管理员权限或使用原始套接字,这在某些操作系统上可能受限。

进一步改进

  • 添加进度条:显示扫描进度,使用户了解扫描的完成情况。

  • 支持多种扫描方法:如TCP SYN扫描、UDP扫描等,并提供相应的选项供用户选择。

  • 增加目标主机解析:支持输入主机名,并自动解析为IP地址。

  • 结果导出:允许用户将扫描结果导出为文件,如文本文件或CSV文件。

  • 图形化展示:使用图表等方式展示开放端口的情况。

  • 增加扫描速度控制:允许用户设置扫描延迟,以减少对目标主机的影响。

  • 集成Nmap等现有工具:通过调用外部程序如Nmap来进行更复杂的扫描,并解析其输出结果。

通过这些改进,可以使端口扫描程序更加功能丰富和用户友好。

参考资料


网站公告

今日签到

点亮在社区的每一天
去签到