Seite 1 von 1

QThread - QTcpSocket

Verfasst: 29. Dezember 2011 20:03
von sigvdr
Ziel:
Eine Liste aller Geräte im Heimnetzwerk die auf einem bestimmten Port ihren Dienst anbieten, also ein Portscanner.
Idee:
Per QTcpSocket versuchsweise eine Verbindung zu einem Server:Port herstellen, mit waitForConnected(timeout) abbrechen wenn keine Verbindung hergestellt werden konnte und dann den nächsten Port testen. Diese Schleife dann für jede mögliche Serveradresse in eine seperaten QThread verpacken und parallel suchen lassen.
Problem:
Der beschriebene Ablauf hat bisher problemlos funktioniert unter Linux und unter Windows7, bei einem Test mit Windows XP findet das Programm aber keinen Server mehr, sobald mehrere Threads gleichzeitig ablaufen.
Fragen:
Sind bei WindowsXP nur eine begrenzte Anzahl von QThreads möglich?
Müssen QThreads irgendwie organisiert werden?
Steckt das Problem schon in der Idee und es gibt eine bessere Methode die Liste zu generieren?
Habe ich im Code mal wieder Mist gebaut und seh den einfach nicht?

Code: Alles auswählen

class ScanThread : public QThread
{
    Q_OBJECT
public:
    ScanThread(QString ipToScan, int pStart=1, int pStop=255, int scanWTime = 10);
    QString ipNo(void);
public slots:
    void run(void);
    void stop(void);
    void setHostName(QHostInfo hostInfo);
signals:
    void found(QString ipNo, int portNo);
    void hostName(QString ipNo, QString hostName);
    void current(int portNo);
private:
    QString ip;
    QString name;
    int count;
    int portStart;
    int portStop;
    bool doStop;
    int scanWaitTime;
};

Code: Alles auswählen

ScanThread::ScanThread(QString ipToScan, int pStart, int pStop, int scanWTime){
    ip=ipToScan;
    portStart = pStart;
    portStop = pStop;
    scanWaitTime = scanWTime;
    name = "";
    count = 0;
}
void ScanThread::run(void){
    doStop = false;
    int port = portStart;
    QTcpSocket sock;
    while ( (!doStop) && (port <= portStop) ) {
        sock.connectToHost(ip,port);
        if ( sock.waitForConnected(scanWaitTime) ) {
            emit found(ip,port);
            if ( count == 0 ) {
                QHostInfo::lookupHost(ip,this,SLOT(setHostName(QHostInfo)));
            }
            count++;
            sock.disconnectFromHost();
            //sock.waitForDisconnected(10);
        }
        emit current(port);
        port++;
    }
    if ( count ) {
       while ( name.isEmpty() ) usleep(1000);
    }
}
void ScanThread::setHostName(QHostInfo hostInfo){
    name = hostInfo.hostName();
    if (name.isEmpty() ) name = "---";
    emit hostName(ip,name);
}
void ScanThread::stop(void){
   doStop = true;
}
QString ScanThread::ipNo(void){
    return ip;
}
Gruß Sig

Re: QThread - QTcpSocket

Verfasst: 30. Dezember 2011 21:36
von Feuer
Hallo,
du startest mehrere Threads? Interessante wäre es zu wissen, wie du sie startest bzw. verwaltest. Vielleicht hat dein XP Rechner nicht genug Speicher? Jeder Thread den du startest benötigt Speicher. Gibt es Fehlermeldungen?

Re: QThread - QTcpSocket

Verfasst: 31. Dezember 2011 12:46
von sigvdr
Hallo,

Fehlermeldungen gibt es keine!

Die Verwaltung läugt über : QList<ScanThread*> scanThreads
Gestartet werden die Threads so:

Code: Alles auswählen

void MainWindow::connectMultiThread(void){
    int port = ui->lEPort->text().toInt();
    QString ipAdr = ui->lEIp->text(); // z.B. 192.168.1.25

    int pointPos = ipAdr.lastIndexOf(".");
    int ipDevice = 1;

    ipAdr = ipAdr.left(pointPos+1); // -> 192.168.1.

    for ( int i = 0; i < 100; i++ ) {
        ui->tEMessage->append("connecting..."+ipAdr+QString::number(ipDevice));
        portScan = new ScanThread(ipAdr+QString::number(ipDevice++),port-10,port+500,50);
        //connect(portScan, SIGNAL(current(int)),this,  SLOT(status(int)));
        connect(portScan, SIGNAL(finished()),this,  SLOT(multiScanFinished()));
        connect(portScan, SIGNAL(found(QString,int)),this,  SLOT(scanFound(QString,int)));
        connect(portScan, SIGNAL(hostName(QString,QString)),this,  SLOT(scanHostName(QString,QString)));
        scanThreads << portScan;
        portScan->start();
    }
}
Und so wieder aufgeräumt

Code: Alles auswählen

void MainWindow::multiScanFinished(){
    for (int i = scanThreads.count()-1 ; i >= 0 ; i--) {
        if ( scanThreads[i]->isFinished()) {
            ui->tEMessage->append("done ->"+scanThreads[i]->ipNo());
            delete scanThreads.takeAt(i);
        }
    }
    if ( scanThreads.count() == 0 ) {
        ui->tEMessage->append("last thread closed");
    }
}
Das ganze reduziert als Miniprojekt im Anhang

Gruß Sig

Re: QThread - QTcpSocket

Verfasst: 5. Januar 2012 19:14
von sigvdr
Hallo,

nach einigen Experimenten habe ich jetzt neue Erkenntnisse, die mich aber keinen Schritt weitergebracht haben. Das oben geschilderte Problem hängt nicht mit der Benutzung von Threads zusammen. Auch wenn ich oft hintereinander (ohne QThread) versuche über QTcpSocket eine Verbindung herzustellen findet das Programm (nur unter WindowsXP) vorhandene Geräte/Ports nicht mehr.
Beispiel:

Code: Alles auswählen

//    QTcpSocket *sock = new QTcpSocket;
    for ( int i = ipMin; i <= ipMax; i++) {
        ipNo = ipBase+QString::number(i);
        QTcpSocket *sock = new QTcpSocket;
        for (int port = portMin; port <= portMax; port++ ) {
//            QTcpSocket *sock = new QTcpSocket;
            sock->connectToHost(ipNo,port,QIODevice::ReadOnly);
            if ( sock->waitForConnected(scanWTime) ) {
                sock->disconnectFromHost();
                scanFound(ipNo, port);
            } else {
                ui->tEError->append(ipNo+"->"+sock->errorString());
            }
//            delete sock;
            ui->pBar->setValue(ui->pBar->value()+1);
        }
        delete sock;
    }
//    delete sock;
Unabhängig davon wo im Beispiel der QTcpSocket erstellt wird habe ich immer das selbe Verhalten. Scanne ich mit diesem Code nur auf tatsächlich vorhandenen IP-Adressen finde ich alle dort verfügbaren Ports. Wenn aber auch auf nicht vorhandenen IP-Adressen gescannt wird, wird nichts mehr gefunden. Das Programm läuft aber ohne Fehlermeldungen durch und mit sock->errorString() gibt es auch nur (wie erwartet) die Meldung vom "timeout".
Es scheint so, als ob nach QTcpSocket::waitForConnected(scanWTime) eine art "Aufräumaktion" notwendig wäre, aber auch mit socket->close() oder delete socket nach jedem Versuch komme ich nicht weiter.

Noch einmal zur Erinnerung:
Das Problem existiert bei mir nur mit WindowsXP nicht mit Windows7 und nicht mit Linux.
Es gibt keine Programmabstürze oder Fehlermeldungen.

Evtl. hat doch noch jemand eine Idee wie ich hier weiter suchen kann!

Gruß Sig