Issues with QTcpSocket within QThread



  • So first off, I have created a QTcpSocket in my thread class header and instantiate it in my run() function of my thread (which I do believe is the proper way to do so by creating a pointer to the object, then instantiating in the run function so it is local to the current thread).

    Here's an example code of what I am doing here.

    header file to thread class:
    @
    #ifndef CLSTCPTHREAD_H
    #define CLSTCPTHREAD_H

    #include <QThread>
    #include <QtNetwork>

    class clsTcpThread : public QThread
    {
    Q_OBJECT
    public:
    explicit clsTcpThread(QObject *parent = 0);

    // methods
    void run();
    
    // defines
    QTcpSocket *incTcpSocket;    // tcp socket creation
    

    signals:

    public slots:
    void incTcpReadyReadSignal();
    void incTcpSocketDisconnected();

    };

    #endif // CLSTCPTHREAD_H
    @

    heres the run function in my thread class cpp:
    @
    /*
    // main thread loop...
    */
    void clsTcpThread::run()
    {
    // create tcp socket and signals
    this->incTcpSocket = new QTcpSocket(this); // tcp socket creation
    connect(this->incTcpSocket, SIGNAL(readyRead()), this, SLOT(incTcpReadyReadSignal())); // ready read on tcp socket
    connect(this->incTcpSocket, SIGNAL(disconnected()), this, SLOT(incTcpSocketDisconnected())); // socket disconnected

    if (incTcpSocket->state() != QTcpSocket::UnconnectedState){
          incTcpSocket->close();
    }
    else {  // socket closed...
          while (infiniteLoop){
               if (connectedSocket == false){
                    incTcpSocket->connectToHost("127.0.0.1", port);
                    // check connection status
                    if (incTcpSocket->waitForConnected(tcpConnectTimeOut) == false){ // connection failed
                         qDebug() << "Cannot Connect";
                         connectedSocket = false;
                    }
                    else{
                         connectedSocket = true;
                    }
                    /*
                    //  send connect message to server and get reply...
                    */
               }
               else{
                    ...
                    build packet
                    ...
                    if ((ret = incTcpSocket->write(dataOutPacket, dataOutPacket.length())) > 0){
                         qDebug() << "Write successful: Byte count - " << ret;   // write success
                         incTcpSocket->flush();  // write success
                    }
                    else {
                         qDebug() << "Failed to write to server socket";
                    }
               }
               // delay...
               this->msleep(3000);
          }
     }
    

    }
    @

    Just a little background, my server is running in vb6 accepting the data, and yesterday I wrote a Qt app that communicated successfully (send and received data) using simple signals and slots and tcp communications without a QThread implemented and it worked perfect in a Qt application.

    So two issues arose here when trying to do this in a thread:

    A. For some reason on my write in my run() function within the QThread class, it returns the proper byte size I am trying to send in Ret(which is great!), but my vb app doesnt trigger its data arrival until the incTcpSocket->flush() command is initiated. This doesnt make sense to me at all. If it was serial communication, then yes, I could see why. Why does the data not 'actually' send until I flush the butter. Could anyone explain this to me?

    B. After my data sends correctly using the flush and my data arrival hits in my vb6 app with the correct byte count, I send data back. I checked and made sure that the data is sent correctly, and it indeed does, but I am not getting my readyRead signal from my slot() in thread class. I have a ready read slot(), its there, i just didnt included the code in my example above.

    So is the way I defined my connect statements correct (ive always done them in my initial declaration on the class initialization, never on the go like this)? and why should I have to flush the output buffer of the tcp port for it to actually send?

    I'm a little baffled right now, yet ive never done this with threads so, any thing could happen I guess...

    EDIT: I edited the code examples a little bit to be more like what I have...



  • For signals to work, you need a running event loop in the thread. As you do not start one, it does not work.

    The easiest way to achieve your goal would be to put your existing non-threaded code into a QObject based class, then instantiate a QThread object and an object of your new class and move the latter to the thread:

    @
    QThread *t = new QThread;
    MyNetworkHandler *handler = new MyNetworkHandler;
    handler->moveToThread(t);
    t->start();
    @

    And please read the "Threads, Events and QObjects":/wiki/Threads_Events_QObjects wiki article about the gory details.



  • Thank you Volker for your timely response. I will be trying this very soon to see how it goes. I guess I am still a little boggled due to the fact that I need to flush the tcp buffer before my data actually sends. It might be due to the thread having an internal tcp port.

    Hopefully I will have success! Thanks!



  • So I apologize for the double post, but I ended up trying this out and this is how I have implemented the socket and thread.

    in main cpp file this is how I initialize the signals and slots and my thread:
    @
    connect(&incTcpSocket, SIGNAL(readyRead()), &testThread, SLOT(incTcpReadyReadSignal())); // ready read on tcp socket
    connect(&incTcpSocket, SIGNAL(disconnected()), &testThread, SLOT(incTcpSocketDisconnected())); // socket disconnected
    // start the tcp thread
    incTcpSocket.moveToThread(&testThread); // move events to thread
    testThread.start(); // start the thread
    @

    So, I wanted my slots to run in my thread aka so tcp events happen within the thread its self.

    The thing is, my tcpSocket has to be global between the two threads for to be able to read and write to the socket within the run() while loop in the QThread (if the tcp socket is defined in the main.cpp, or else the program wont compile and flag errors saying cannot fined object "incTcpSocket"). So instead I had to create a tcpSocket as an extern in a header globalexterns.hpp with a globalexterns.cpp denoted for the global declaration to share between the two threads.

    Im am still not recieving the events on my tcp socket for some reason...



  • Do you get any output on the console? Errors? Warnings?

    Be careful with your testThread object - it is not in the new thread, but in the main thread (where it has been created).

    Also, if you access the socket from two different threads, you must protect it with a [[Doc:QMutex]] against simultaneous access!



  • So what I have resulting in doing is creating my tcp socket globally (using QMutex to protect the object from simultaneous accessing). My events are connected in the main thread to my main thread ready read slots.

    Still, for some reason I have to tcpSocket->flush before all the data is sent out the socket. but if I dont flush, my return from my write function still says I sent the desired amount of byte I was trying to send out.

    And my ready read signal is not being triggered for some reason.

    Is there any restrictions on creating a socket globally? Or do I have to make a tcp socket a specific way in windows compared to linux (where I have always done them and have never had a problem like this...Ever).

    EDIT: the tcp flush, and the tcp write are both being done within the while loop in the thread



  • Hard to say what's going wrong.

    The best approach would be to boil down your application to a very simple test project, just your main class and the thread and some glue logic, that demonstrates the error.

    Just zip everything together (actually not everything but only the sources - .h. + .cpp, and the project file - .pro, no xxx.o or similar compiler output) and upload it somewhere so that we can grab it.s



  • I have zipped a sample project which has the same idea what I am trying to accomplish. Hope this helps. Thank you again for your help.

    Heres the download link.
    http://www.filefactory.com/file/c2cb12e/n/tcpClientTest.rar

    Click the download link on the bottem...this was the first fileshare site I could find.



  • Where I do my write in my thread....if you add the tcpSocket -> flush() command, it sends out and the server receives the data...



  • I'll have a look later this week.



  • I actually figured out a way around it...I needed a quick solution since this project needs to be done asap. Still not sure why the global tcp socket isn't working but my solution seems to be working. I kept the tcp socket local to the main thread, and used signals to call into my functions that connect, write, etc from my tcp thread. Its just a little complicated since instead of mutex's I had to use quite a bit of booleans to make sure the signals were not being accessed multiple times (for example, waiting to connect has a timeout, I dont want to loop in my thread unless and call the same signal until that whole connect slot has finished).

    I would still like to see if I can get my example code to work. I'm finding out my skills with threading in c++ lacking. I thank you again for your time Volker.



  • It is old post but maybe it will be helpful.

    Check your worker constructor if there are any "new" keyword (object which you are putting on heap) then the whole object will be started in main thread not in your thread to which you moved worker.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.