Probleme mit QAbstractSocket

Alles rund um die Programmierung mit Qt
Antworten
grisu_1972
Beiträge: 13
Registriert: 5. September 2008 10:54

Probleme mit QAbstractSocket

Beitrag von grisu_1972 »

Hallo Leute,

ich habe hier ein Problem mit einem einfachen TCP Client der auf QAbstractSocket aufsetzt:

Das Verhalten ist wiefolgt:
1. das Programm wird gestartet
2. es läuft einige Stunden und sendet alle 10 ms eine Botschaft an einen Client (in einer Endlosschleife)
3. dann kommt irgendwann der Zeitpunkt, an dem das Tool aufhört zu senden
4. die Verbindung bleibt erhalten (sowohl Client als auch Server zeigen mittels netstat an, das die Verbindung noch besteht! Aber es werden keine Daten mehr gesendet!
5. das Program kann mittels eine neue Verbindung aufbauen und weitersenden aber

Hatte jemand schonmal diese Problem?

Der Client läuft in einem WorkerThread und sendet in einer Endlosschleife:





Code: Alles auswählen

void workerThread::run()
{
    openConnection();
    init();
    QList <telegram> liTelegrams =  configService::getInstance()->getTeleList();
    size.setNum ( liTelegrams.size() );
    do
    {
        QList <telegram>::iterator it = liTelegrams.begin();
        while ( it != liTelegrams.end() )
        {
            QList <QByteArray> lba;
            QByteArray ba;
            lba = ( it )->getMessageAsByteArray();
            QList <QByteArray>::iterator itLBa;
            itLBa = lba.begin();
            while ( itLBa != lba.end() )
            {
                bool b;
                int a = ( itLBa )->toInt ( &b, 16 );
                ba.append ( ( char ) a );

                itLBa++;
            }
            tcpSocket->write ( ba.data(), ba.size() );
            tcpSocket->waitForBytesWritten ( -1 );

            it++;
        }
    }
    while ( configService::getInstance()->getRunAsLoop() );

}


void workerThread::init()
{
    if ( tcpSocket == NULL )
    {
        tcpSocket = new QTcpSocket ( );
        connect ( tcpSocket, SIGNAL ( error ( QAbstractSocket::SocketError ) ), this, SLOT ( slot_socketError ( QAbstractSocket::SocketError ) ) );
        connect ( tcpSocket, SIGNAL ( readyRead() ), this, SLOT ( slot_newMsgReceived() ) );
        connect ( tcpSocket, SIGNAL ( bytesWritten ( qint64 ) ), this, SLOT ( slot_bytesWritten ( qint64 ) ) );
    }

}


void workerThread::openConnection()
{

    init();
    int state = tcpSocket->state();
    if ( state  != QAbstractSocket::ConnectedState )
    {
        QString tmpAddresse =  configService::getInstance()->getServerAddress();
        int tmpPort =  configService::getInstance()->getServerPort();
        tcpSocket->connectToHost ( tmpAddresse,tmpPort );
    }
}


Hier der Aufruf des Sende Thread!

Code: Alles auswählen

void clientGui::slot_startPressed()
{
    workerThread wThread;
    wThread.openConnection();
    wThread.start();
    logService::getInstance()->addMsg ( "Starte Sende Thread!" );
}
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

mit fallen einige Dinge auf (wie z.B. dass du nicht auf "connected()" wartest).. aber seien wir ehrlich:

Code: Alles auswählen

void clientGui::slot_startPressed()
{
    workerThread wThread;
    wThread.openConnection();
    wThread.start();
    logService::getInstance()->addMsg ( "Starte Sende Thread!" );
} 
Die Variabel "wThread" lebt nicht wirklich lange.....
ab2cd4
Beiträge: 9
Registriert: 17. Oktober 2008 19:30

Beitrag von ab2cd4 »

Du könntest

Code: Alles auswählen

QByteArray QByteArray::fromHex ( const QByteArray & hexEncoded ) 
verwenden um die ByteArrays umzuwandeln.

Der Aufruf des Netzwerkthreads macht nicht besonders viel Sinn.

Code: Alles auswählen

void clientGui::slot_startPressed()
{
    workerThread wThread; //der Arbeitsthread muss unbedingt als Pointer zur GUI hinzugefügt werden, da er ansonsten ziemlich schnell zu nicht mehr verwendetem Arbeitsspeicher wird
    wThread.openConnection(); //openConnection() und init() werden auch im Thread aufgerufen
    wThread.start(); //damit der Netzwerkcode auch wirklich im Thread läuft darf er erst innerhalb von diesem erstellt werden
    //-->Verbindung im Thread initiieren und dann warten bis die Verbindung steht und erst dann senden
    logService::getInstance()->addMsg ( "Starte Sende Thread!" );
} 
Die am Anfang erwähnten 10ms Wartezeit sind auch nicht zu erkennen. Entweder du hast sie in configService::getInstance()->getRunAsLoop() versteckt oder die Wartezeit ist die Zeit, die gewartet wird bis die Daten gesendet sind.

Du könntest zudem die vielen Variablen die du für temporäre Werte verwendest direkt setzen oder den Funktionen übergeben.

z.B.

Code: Alles auswählen

tcpSocket->connectToHost (configService::getInstance()->getServerAddress(), configService::getInstance()->getServerPort());
grisu_1972
Beiträge: 13
Registriert: 5. September 2008 10:54

Beitrag von grisu_1972 »

Die workerThread hatte ich als Membervariable eingebunden. Da er im Posting vorhanden war, war ein (mein) copy paste Fehler (sorry)!
Ich benutze alledings eine Klassenvariable und kein mit neu angelegtes Objekt, das sollte aber kein Problem sein!

Code: Alles auswählen

/** Klasse für die Schnittstelle zur Benutzeroberfläche */
class clientGui:public QDialog
{
...
...
   private:
        /** Membervariable fuer den Sendethread */
        workerThread wThread;
 }

Code: Alles auswählen

void clientGui::slot_startPressed()
{

    //wThread.openConnection(); // raus, wird in workerThread erledigt
    wThread.start();
    logService::getInstance()->addMsg ( "Starte Sende Thread!" );
} 


Folgendes verstehe ich nicht:
wThread.start(); //damit der Netzwerkcode auch wirklich im Thread läuft darf er erst innerhalb von diesem erstellt werden

ich habe es wiefogt verstanden:
Das was im Thread ausgeführt werden soll kommt in die run() Methode und die wird durch die Methode start() von aussen angestossen!


Kannst du mir da auf die Sprünge helfen?
ab2cd4
Beiträge: 9
Registriert: 17. Oktober 2008 19:30

Beitrag von ab2cd4 »

Wenn du ein QObject, hier QAbstractSocket, erstellst wird es an den Thread gebunden, in dem es im Moment läuft. Das heißt, dass bei der Initialisierung deines Arbeitsthreads, der Socket mit initialisiert wird und dieser beim ersten Codestück im ersten Post eigentlich nicht im Workerthread läuft.
Mit meinem Kommentar hatte ich gemeint, dass der der Socket erst innerhalb, des Threads erstellt werden sollte, was du ja nun machst. Da du den Socket jedoch per Hand zwingst die Daten zu versenden, sollte es eigentlich(?) egal sein, wo du den Thread erzeugst. Ich weiß allerdings nicht, was passiert wenn der Eventloop von der GUI und dein WorkerThread gleichzeitig versuchen die Daten zu versenden, was jetzt ja nicht mehr der Fall ist.
Antworten