0

I am currently coding a port-scanner in Qt(C++) for Mac. The process of checking if a certain port is open or not works completely fine. But if the port range which the user wants to check is too big, every port will be checked but the output happens only after this process. The program actually should check for example port 1 and output the result. After that it should check the next and output and so on...

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++;
}

Have you got any advise how I could have an output after each iteration?

4

2 回答 2

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而不是在外面。坦率地说,我很难理解您是否不想要第一个版本(循环之后),因为现在您正在每个迭代步骤中将输出添加到文本字段中。

于 2016-09-13T11:58:51.843 回答
0

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

// 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-09-13T14:41:29.987 回答