Thread sending http request using Qt

2.1k views Asked by At

I am trying to create a thread (HttpWorker) that when required wakes up and sends a http request. I would like this to be done in a single thread. I am using Qt for the implementation.

The way I thought i would do it is to have a class MyHttpWorker, move it to another thread, connect the slots/signals etc. Then on thread start I would use QNetworkAccessManager to call get requests. I would use QWaitCondition to pause the thread after the request has been sent and I would resume this thread whenever I need to send another one.

However, when I pause the httpworker thread, the FinishedSlot is not called at all. If I use the class to simply call one http request, it executes with no problem. So the problem is connected to QWaitCondition (or just freezing the threads in general).

I could simply create and destroy one worker and thread for each request I have, but I require to send lot of http requests, so I think this method would be way too consuming (creating threads and destroying them over and over).

I appreciate any help I can get.

Here is my code:

MyHttpWorker.h

#include <QNetworkReply>
#include <QDebug>
#include <QObject>
#include <QNetworkAccessManager>
#include <QThread>
#include <QWaitCondition>
#include <QMutex>    

class MyHttpWorker : public QObject
    {
        Q_OBJECT

        QNetworkAccessManager* nam;        
        QMutex syncPause;
        QWaitCondition pauseCond;        

    public:
        explicit MyHttpWorker(QObject *parent = 0);        
        void MyWake();            
    public slots:        
         void SetTheThread(QThread* thread);
         void MyStart();        
         void finishedSlot(QNetworkReply* reply);            
    };

MyHttpWorker.cpp

MyHttpWorker::MyHttpWorker(QObject *parent) :
    QObject(parent)
{
    nam = new QNetworkAccessManager(this);
    QObject::connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(finishedSlot(QNetworkReply*)));    
}

void MyHttpWorker::finishedSlot(QNetworkReply* reply)
{
    qDebug() << "Finished"; //This slot is never even reached, when i used QWaitCond...
    if (reply->error() == QNetworkReply::NoError)
    {
        QByteArray bytes = reply->readAll();
        QString string(bytes);
        qDebug() << string;
    }else
    {
        qDebug() << reply->errorString();
    }
    reply->deleteLater();
}

void MyHttpWorker::SetTheThread(QThread* thread){
    QObject::connect(thread,SIGNAL(started()),this,SLOT(MyStart()));
}

void MyHttpWorker::MyWake(){    
    pauseCond.wakeAll();
}

void MyHttpWorker::MyStart(){    
    qDebug() << "Start" ; 

    while(true){

        syncPause.lock();    
        qDebug() << "thread waiting...";
        pauseCond.wait(&syncPause);
        qDebug() << "thread resumed.";
        syncPause.unlock();

        //sending the actual request here
        QNetworkRequest myRequest;
        myRequest.setUrl(QUrl("http://www.google.com"));
        nam->get(myRequest);



    }

}

main.cpp

#include <QCoreApplication>
#include <QThread>
#include <QDebug>
#include <myhttpworker.h>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

   //create the worker, thread and launch it... (worker is waiting by default)
    MyHttpWorker* worker = new MyHttpWorker;    
    QThread* httpThread = new QThread;    
    worker->SetTheThread(httpThread);
    worker->moveToThread(httpThread);    
    httpThread->start();

   //try and send 5 requests ...
     for(int i=0;i<5;i++){
         qDebug() << "Unpausing";    
         QThread::currentThread()->msleep(1000);    
         worker->MyWake();    
     }

    return a.exec();
}
1

There are 1 answers

2
ratchet freak On BEST ANSWER

don't create an infinite loop but let the even loop handle it:

void MyHttpWorker::MyWake()
{
    QMetaObject::invokeMethod(this,"doSend");
    //send to the event loop
}

// new slot
void MyHttpWorker::doSend(){    
    //sending the actual request here
    QNetworkRequest myRequest;
    myRequest.setUrl(QUrl("http://www.google.com"));
    nam->get(myRequest);
}
//and remove the myStart and all that synchronisation

then when you want to stop it just send a quit to the thread. I suggest you also connect the finished signal of the thread to the deleteLater slot of MyHttpWorker