qidao123.com技术社区-IT企服评测·应用市场

标题: QT 将单线程改为线程池 端口扫描3.5 [打印本页]

作者: 商道如狼道    时间: 2025-1-11 13:02
标题: QT 将单线程改为线程池 端口扫描3.5
接上篇QT实现 端口扫描暂停和继续功能 3-CSDN博客
多线程与线程池的关系


1. 修改 MyThread 类为 ScanTask 类

将 MyThread 类重命名为 ScanTask,并使其继续自 QRunnable。这样可以将每个端口扫描任务作为一个独立的任务提交到线程池中。    
ScanTask.h

  1. #ifndef SCANTASK_H  
  2. #define SCANTASK_H  
  3. #include <QTcpSocket>  
  4. #include <QDebug>  
  5. #include <QRunnable>  
  6. #include <QObject>  
  7. class ScanTask : public QObject, public QRunnable // 需要继承两个类  
  8. {  
  9.     Q_OBJECT  
  10. public:  
  11.     ScanTask(QString strIP, int intPort);  
  12.     ~ScanTask();  
  13.     void setPaused(bool paused); // 设置暂停状态  
  14.     void closeThread(); // 关闭线程  
  15. protected:  
  16.     void run() override; // 重写 run 方法  
  17. private:  
  18.     volatile bool isStop; // 控制任务停止  
  19.     volatile bool isPaused; // 控制任务暂停  
  20.     QString m_strIP; // IP 地址  
  21.     int m_intPort; // 端口号  
  22. signals:  
  23.     void send_scan_signal(int port, bool isOpen); // 发送扫描结果信号  
  24.     void finished(int port, bool isOpen); // 扫描完成信号  
  25. };  
  26. #endif // SCANTASK_H
复制代码
ScanTask.cpp

  1. #include "scantask.h"  
  2. ScanTask::ScanTask(QString strIP, int intPort)  
  3.     : m_strIP(strIP), m_intPort(intPort), isStop(false), isPaused(false) // 初始化成员变量  
  4. {  
  5. }  
  6. ScanTask::~ScanTask()  
  7. {  
  8.     qDebug("ScanTask deleted.");  
  9. }  
  10. void ScanTask::setPaused(bool paused)  
  11. {  
  12.     isPaused = paused; // 更新暂停状态  
  13. }  
  14. void ScanTask::closeThread()  
  15. {  
  16.     isStop = true; // 设置为停止状态  
  17. }  
  18. void ScanTask::run()  
  19. {  
  20.     QTcpSocket socket;  
  21.     socket.abort(); // 取消任何现有连接  
  22.     // 执行端口扫描  
  23.     if (isStop) return; // 检查是否停止  
  24.     socket.connectToHost(m_strIP, m_intPort); // 连接到指定的 IP 和端口  
  25.     if (socket.waitForConnected(1000)) // 等待连接  
  26.     {  
  27.         emit send_scan_signal(m_intPort, true); // 发送信号,表示端口打开  
  28.         qDebug("%d: %s", m_intPort, "opened"); // 调试信息  
  29.     }  
  30.     else  
  31.     {  
  32.         emit send_scan_signal(m_intPort, false); // 发送信号,表示端口关闭  
  33.         qDebug("%d: %s", m_intPort, "closed");  
  34.     }  
  35. }
复制代码
2. 修改 MainWindow 类以使用线程池

在 MainWindow 类中,我们将使用 QThreadPool 来管理 ScanTask 的实例,并在扫描按钮点击事件中提交任务。
MainWindow.h

  1. #ifndef MAINWINDOW_H  
  2. #define MAINWINDOW_H  
  3. #include <QMessageBox>  
  4. #include <QTreeWidget>  
  5. #include <QMainWindow>  
  6. #include <QThreadPool>  
  7. #include "scantask.h"  
  8. QT_BEGIN_NAMESPACE  
  9. namespace Ui { class MainWindow; }  
  10. QT_END_NAMESPACE  
  11. class MainWindow : public QMainWindow  
  12. {  
  13.     Q_OBJECT  
  14. public:  
  15.     MainWindow(QWidget *parent = nullptr);  
  16.     ~MainWindow();  
  17. protected:  
  18. private:  
  19.     Ui::MainWindow *ui;  
  20.     QTreeWidgetItem *itemRoot; // 树形控件的条目,用于表示目标 IP  
  21.     QTreeWidgetItem *itemLeaf; // 树形控件的条目,用于表示目标端口  
  22.     QThreadPool *threadpool; // 声明一个线程池  
  23.     bool isPaused; // 控制暂停状态  
  24. private slots:  
  25.     void on_pushButton_Scan_clicked();  
  26.     void on_stopButton_clicked();  
  27.     void on_pushButton_Quit_clicked();  
  28.     void recv_result(int port, bool isOpen); // 自定义槽函数,用于接收线程发送的消息  
  29.     void on_pushButton_Stop_clicked(); // 暂停按钮点击事件  
  30.     void on_pushButton_Continue_clicked(); // 继续按钮点击事件  
  31. };  
  32. #endif // MAINWINDOW_H
复制代码
MainWindow.cpp

  1. #include "mainwindow.h"  
  2. #include "ui_mainwindow.h"  
  3. MainWindow::MainWindow(QWidget *parent)  
  4.     : QMainWindow(parent)  
  5.     , ui(new Ui::MainWindow)  
  6. {  
  7.     ui->setupUi(this);  
  8.     // 给 QTreeWidget 初始化表头  
  9.     QStringList head;  
  10.     head << "扫描结果";  
  11.     ui->treeWidget->setHeaderLabels(head);  
  12.     threadpool = new QThreadPool; // 创建线程池  
  13.     threadpool->setMaxThreadCount(10); // 设置最大线程数  
  14.     isPaused = false; // 初始化暂停状态  
  15. }  
  16. MainWindow::~MainWindow()  
  17. {  
  18.     delete ui;  
  19. }  
  20. void MainWindow::on_pushButton_Scan_clicked()  
  21. {  
  22.     ui->pushButton_Scan->setEnabled(false); // 正在扫描时,禁用扫描按钮  
  23.     QString strIP = ui->lineEdit_IP->text(); // 获取用户输入的 IP 地址  
  24.     int startPort = ui->spinBox_Port->value(); // 获取用户输入的起始端口  
  25.     int endPort = startPort + 10; // 假设扫描 10 个端口  
  26.     // 验证 IP 地址是否为空  
  27.     if (strIP.isEmpty()) {  
  28.         QMessageBox::information(this, "Error", "请输入 IP", QMessageBox::Ok);  
  29.         return; // 退出函数  
  30.     }  
  31.     ui->treeWidget->clear(); // 清空 QTreeWidget 中的先前结果  
  32.     itemRoot = new QTreeWidgetItem(ui->treeWidget, QStringList(strIP)); // 创建根节点,显示 IP 地址  
  33.     for (int i = startPort; i < endPort; i++) { // 扫描指定范围的端口  
  34.         ScanTask *task = new ScanTask(strIP, i); // 创建新的扫描任务  
  35.         connect(task, &ScanTask::send_scan_signal, this, &MainWindow::recv_result); // 连接信号  
  36.         threadpool->start(task); // 将任务提交到线程池  
  37.         QThread::msleep(10); // 短暂休眠,避免过快提交任务  
  38.     }  
  39. }  
  40. void MainWindow::recv_result(int port, bool isOpen)  
  41. {  
  42.     QString strPort = QString::number(port); // 将端口号转换为字符串  
  43.     // 根据端口状态创建叶子节点  
  44.     if (isOpen)  
  45.         itemLeaf = new QTreeWidgetItem(itemRoot, QStringList(strPort + " opened")); // 端口打开  
  46.     else  
  47.         itemLeaf = new QTreeWidgetItem(itemRoot, QStringList(strPort + " closed")); // 端口关闭  
  48.     ui->treeWidget->expandAll(); // 展开所有项  
  49. }  
  50. void MainWindow::on_stopButton_clicked()  
  51. {  
  52.     // 停止所有正在运行的任务  
  53.     threadpool->clear(); // 清理线程池中未执行完的任务  
  54.     ui->pushButton_Scan->setEnabled(true); // 重新启用扫描按钮  
  55. }  
  56. void MainWindow::on_pushButton_Quit_clicked()  
  57. {  
  58.     QApplication::quit(); // 退出应用程序  
  59. }  
  60. void MainWindow::on_pushButton_Stop_clicked()  
  61. {  
  62.     isPaused = true; // 设置为暂停状态  
  63.     ui->pushButton_Stop->setEnabled(false); // 禁用暂停按钮  
  64.     ui->pushButton_Continue->setVisible(true); // 显示继续按钮  
  65. }  
  66. void MainWindow::on_pushButton_Continue_clicked()  
  67. {  
  68.     isPaused = false; // 设置为继续状态  
  69.     ui->pushButton_Stop->setEnabled(true); // 启用暂停按钮  
  70.     ui->pushButton_Continue->setVisible(false); // 隐藏继续按钮  
  71. }
复制代码
原理记录

信号发出和槽的调用


线程池的自带功能




















免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 qidao123.com技术社区-IT企服评测·应用市场 (https://dis.qidao123.com/) Powered by Discuz! X3.4