【问题标题】:Update frame after each iteration每次迭代后更新帧
【发布时间】:2023-04-03 19:09:01
【问题描述】:

我目前正在为 Mac 编写 Qt(C++) 中的端口扫描程序。检查某个端口是否打开的过程完全正常。 但是如果用户想要检查的端口范围太大,每个端口都会被检查,但是只有在这个过程之后才会输出。 该程序实际上应该检查例如端口 1 并输出结果。之后它应该检查下一个和输出等等......

void MainWindow::checkPort(int portmin, int portmax, string ip) {
int dif = portmax - portmin;
if (dif <= 0)
    return;

unsigned int open = 0;
unsigned int closed = 0;
int checked = 0;

sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(ip.c_str());

for (int i = portmin; i <= portmax; i++) {
    int s = socket(AF_INET, SOCK_STREAM, 0);
    addr.sin_port = htons(i);

    int con = ::connect(s, reinterpret_cast<sockaddr*>(&addr), sizeof(sockaddr));

    if (con == 0){
        ui->textEdit->setTextColor(Qt::green);
        ui->textEdit->append("Port " + QString::number(i) + " open.");
        open++;
    }

    if (con == -1) {
        ui->textEdit->setTextColor(Qt::red);
        ui->textEdit->append("Port " + QString::number(i) + " closed.");
        closed++;
    }

    ::close(con);
    ::close(s);
    checked++;
}

您有什么建议我如何在每次迭代后获得输出

【问题讨论】:

  • 您可能希望在循环中调用QApplication::processEvents(),让 UI 有机会处理消息并显示更新。
  • @KarstenKoop 非常感谢!这解决了我的问题。
  • 您的代码阻止了 gui。停止阻止 gui,一切都会好起来的。您正在在每次迭代后都有输出,但您永远不会返回到事件循环,因此 UI 没有机会刷新自己。 不要使用processEvents。将此方法的任何使用视为错误。这是一个异步的世界,不要写假装的代码,你会为自己省去很多麻烦。
  • @KarstenKoop 这将重新进入事件循环,并简单地隐藏端口扫描仪不应该以这种方式开始编写的事实。

标签: c++ qt sockets port port-scanning


【解决方案1】:

大概是这样的:

//...
bool tooManyPorts = dif > 10000; // Set flag to true if port range is too big (for example more than 10 000 ports
// 
QString msgs = "";
for (int i = portmin; i <= portmax; i++) {
    int s = socket(AF_INET, SOCK_STREAM, 0);
    addr.sin_port = htons(i);

    if (con == 0){
        if (tooManyPorts) {
            QString("<font color='green'>Port " + QString::number(i) + " open.</font><br/>");
        }
        else {
            ui->textEdit->setTextColor(Qt::green);
            ui->textEdit->append("Port " + QString::number(i) + " open.");
        }
        open++;
    }

    if (con == -1) {
        if (tooManyPorts) {
            msgs += QString("<font color='red'>Port " + QString::number(i) + " closed.</font><br/>");
        }
        else {
            ui->textEdit->setTextColor(Qt::red);
            ui->textEdit->append("Port " + QString::number(i) + " closed.");
        }
        closed++;
    }
    // ...
}
if(tooManyPorts) {
    ui->textEdit->append(msgs); // Add all iteration messages to text edit
}

注意格式化部分使用 HTML。

这会将所有输出添加到循环之后的字段中。为了让它在每次迭代中都能正常工作,只需在循环中设置msgs = ... 而不是msgs += ...,然后将if(tooManyPorts) ... 移动到for 的末尾而不是在外面。坦率地说,我很难理解您是否不想要第一个版本(循环之后),因为现在您正在在每个迭代步骤中将输出添加到您的文本字段。

【讨论】:

  • 哦,我希望在每个迭代步骤之后将输出添加到文本字段中,但是对于我的代码,即使它确实应该发生,它也不会在现实中发生。但我会试试你的解决方案。 更新: 也不行。输出是整体添加的,不是逐步添加的。
  • 嗯,你能提供更多关于你的文本编辑对象的信息,比如它的属性。我有一个应用程序,它每隔几毫秒根据收到的事件添加多个字符串,我没有问题。请完善您的问题。
  • 我用@Karsten Koop 的建议解决了这个问题。问题是 append 在短时间内被频繁调用,因此 GUI 无法在每个迭代步骤中刷新和更新。
  • 哦,我的……你在主线程中处理你的端口……:-/你真的应该考虑为此添加一个单独的线程(参见here)。您还可以添加输出信息的小子集的功能,例如每 10 个端口收集信息(正如我在帖子中使用QString 写的那样),然后添加它。一般来说,你需要避免在主线程中做太多的事情。
【解决方案2】:

最简单的解决方案是使用线程池同时运行整个扫描作业。线程间通信通过信号槽机制安全地完成:

// https://github.com/KubaO/stackoverflown/tree/master/questions/async-portscan-39469180
#include <QtWidgets>
#include <QtConcurrent>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>

class Scanner : public QObject {
    Q_OBJECT
    bool running = false, stop = false;
    int open = 0, closed = 0, total = 0;
    void scan() {
        running = true;
        sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = inet_addr("127.0.0.1");
        for (int i = 1; i < 65536 && !stop; ++i) {
            auto s = socket(AF_INET, SOCK_STREAM, 0);
            addr.sin_port = htons(i);
            auto con = ::connect(s, reinterpret_cast<sockaddr*>(&addr), sizeof(sockaddr));
            emit hasResult(i, con == 0);
            con == 0 ? ++open : ++closed;
            ++total;
            ::close(s);
        }
        emit done();
        running = false;
    }
public:
    ~Scanner() {
        stop = true;
        while (running);
    }
    Q_SIGNAL void hasResult(int port, bool open);
    Q_SIGNAL void done();
    Q_SLOT void start() {
        QtConcurrent::run(this, &Scanner::scan);
    }
};

int main(int argc, char ** argv) {
    using Q = QObject;
    QApplication app{argc, argv};
    QWidget ui;
    QVBoxLayout layout{&ui};
    QTextBrowser log;
    QProgressBar bar;
    QPushButton scan{"Scan localhost"};
    layout.addWidget(&log);
    layout.addWidget(&bar);
    layout.addWidget(&scan);
    bar.setRange(1, 65535);
    ui.show();

    Scanner scanner;
    Q::connect(&scan, &QPushButton::clicked, &scanner, [&]{
        scan.setEnabled(false);
        scanner.start();
    });
    Q::connect(&scanner, &Scanner::hasResult, &log, [&](int port, bool isOpen){
        bar.setValue(port);
        if (!isOpen) return;
        auto color = isOpen ? QStringLiteral("green") : QStringLiteral("red");
        auto state = isOpen ? QStringLiteral("open") : QStringLiteral("closed");
        log.append(QStringLiteral("<font color=\"%1\">Port %2 is %3.</font><br/>").
                   arg(color).arg(port).arg(state));
    });
    Q::connect(&scanner, &Scanner::done, &scan, [&]{
        bar.reset();
        scan.setEnabled(true);
    });
    return app.exec();
}
#include "main.moc"

【讨论】:

    猜你喜欢
    • 2016-04-09
    • 1970-01-01
    • 2022-01-10
    • 2016-08-02
    • 1970-01-01
    • 2017-11-20
    • 1970-01-01
    • 2021-06-27
    • 2018-03-01
    相关资源
    最近更新 更多