Обновлять кадр после каждой итерации

В настоящее время я пишу сканер портов в Qt (C ++) для Mac. Процесс проверки, открыт ли определенный порт или нет, работает полностью нормально. Но если диапазон портов, который пользователь хочет проверить, слишком велик, будет проверяться каждый порт, но вывод происходит только после этого процесса.
Программа на самом деле должна проверить, например, порт 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++;
}

Есть ли у вас какие-либо советы, как я мог бы иметь вывод после каждой итерации?

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"
0

Другие решения

Возможно, что-то вроде этого:

//...
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 но не снаружи. Честно говоря, мне трудно понять, не хотите ли вы первую версию (ПОСЛЕ цикла), так как сейчас вы являются добавление вывода в текстовое поле на каждом шаге итерации.

1

По вопросам рекламы [email protected]