PDA

View Full Version : Problem in using QHttp with QTimer



Ferdous
5th September 2008, 10:18
Given file names and time out periods, I've to download them. If the time period expires for a file, the download is canceled.

Initially, for debugging purpose, I display a message box informing that the download is successfully finished. This works for download of a single file in the main application. But problem arises when I try to download more than one file. The program just hangs!

Another problem occurs when I comment out that message box display. This time, in case of a single file, the download is finished completely. But the process doesn't exit. The task manager shows that process even after download is complete. As for multiple file download, the problem, the problem is same - the program hangs.

I have been trying to figure out the problem.

Please help me. Here's the code:

CTimedHttp header file:


#ifndef TIMEDHTTP_H
#define TIMEDHTTP_H

#include <QHttp>

class QFile;
class QTimer;

class CTimedHttp : public QHttp
{
Q_OBJECT

private:
// Default time out period.
static const long INFINITE_TIME = 1000000; // 1000 seconds

// Required to initialize HTTP get ID with an improbable integer
static const long INVALID_GET_ID = -10;

// Indicates whether the request times out or not.
bool m_bIsTimedOut;

// Indicates whether the request finished without any interruption or not
bool m_bIsRequestFinished;

// Unique ID returned by HTTP get() request
long m_lHttpGetId;

// File to be downloaded
QFile *m_pFile;

QTimer *timer;

private:
void initialize();

private slots:
void requestTimeout();
void timedHttpRequestFinished(int requestId, bool error);

public:
CTimedHttp(QObject* parent = 0);
CTimedHttp(const QString& hostName, quint16 port = 80, QObject* parent = 0);
CTimedHttp(const QString& hostName, QHttp::ConnectionMode mode, quint16 port = 80, QObject *parent = 0);

void setTimedOut(bool bIsTimedOut);
bool isTimedOut();

void setRequestFinished(bool bIsRequestFinished);
bool isRequestFinished();

long getHttpGetId();
void setHttpGetId(long lHttpGetId);

void get(const QString& strPath, long lTimeoutPeriod = INFINITE_TIME);
};

#endif


CTimedHttp cpp file:
[ That message box statement is in timedHttpRequestFinished() function ]


#include <QtNetwork>
#include <QMessageBox>

#include "CTimedHttp.h"


CTimedHttp::CTimedHttp(QObject* parent /* = 0 */) : QHttp(parent)
{
initialize();
}

CTimedHttp::CTimedHttp(const QString& hostName, quint16 port /* = 80 */, QObject* parent /* = 0 */) : QHttp(hostName, port, parent)
{
initialize();
}

CTimedHttp::CTimedHttp(const QString& hostName, ConnectionMode mode, quint16 port /* = 80 */, QObject *parent /* = 0 */)
: QHttp(hostName, mode, port, parent)
{
initialize();
}

void CTimedHttp::initialize()
{
setTimedOut(false);
setRequestFinished(false);
setHttpGetId(INVALID_GET_ID);

m_pFile = 0;

connect(this, SIGNAL(requestFinished(int, bool)), this, SLOT(timedHttpRequestFinished(int, bool)));
}

void CTimedHttp::setTimedOut(bool bIsTimedOut)
{
m_bIsTimedOut = bIsTimedOut;
}

bool CTimedHttp::isTimedOut()
{
return m_bIsTimedOut;
}

void CTimedHttp::setRequestFinished(bool bIsRequestFinished)
{
m_bIsRequestFinished = bIsRequestFinished;
}

bool CTimedHttp::isRequestFinished()
{
return m_bIsRequestFinished;
}

void CTimedHttp::setHttpGetId(long lHttpGetId)
{
m_lHttpGetId = lHttpGetId;
}

long CTimedHttp::getHttpGetId()
{
return m_lHttpGetId;
}

void CTimedHttp::get(const QString& strPath, long lTimeoutPeriod)
{
QUrl url(strPath);
QFileInfo fileInfo(url.path());
QString fileName = fileInfo.fileName();

if (fileName.isEmpty() == true)
{
// [TODO] : warn the user
QMessageBox::critical(0, "ERROR", "You haven't specified any file name!", QMessageBox::Ok);

return;
}

m_pFile = new QFile(fileName);
if (m_pFile->open(QIODevice::WriteOnly) == false)
{
// [TODO] : warn the user
QMessageBox::critical(0, "ERROR", "Cann't open the file!", QMessageBox::Ok);

delete m_pFile;
m_pFile = 0;

return;
}

/* setHost(url.host()); // default to port 80
m_lHttpGetId = QHttp::get(url.path(), m_pFile);

QTimer::singleShot(lTimeoutPeriod, this, SLOT(requestTimeout()));

*/
setHost(url.host()); // default to port 80

timer = new QTimer();
connect(timer, SIGNAL(timeout()), this, SLOT(requestTimeout()));
timer->setSingleShot(true);

timer->start(lTimeoutPeriod);
m_lHttpGetId = QHttp::get(url.path(), m_pFile);

}

void CTimedHttp::requestTimeout()
{
if (isRequestFinished() == true)
{
return;
}

setTimedOut(true);
abort();

m_pFile->close();
m_pFile->remove();
delete m_pFile;
m_pFile = 0;

// DEBUG
QMessageBox::critical(0, "ERROR", "Request timed out!", QMessageBox::Ok);
}

void CTimedHttp::timedHttpRequestFinished(int iRequestId, bool bError)
{
if (isTimedOut() == true
|| iRequestId != getHttpGetId()) // not the intended request
{
return;
}

timer->stop();

setRequestFinished(true);

if (bError == true)
{
m_pFile->remove();

// [TODO] : What in case of error?
QMessageBox::critical(0, "ERROR", "The request finished with error!", QMessageBox::Ok);

return;
}

// DEBUG]
// If I comment out this statement, the process does not exit
QMessageBox::information(0, "Info", "Download is successful", QMessageBox::Ok);

m_pFile->close();
delete m_pFile;
m_pFile = 0;
}


Main file:


#include <QApplication>

#include "CTimedHttp.h"

int main(int argc, char *argv[])
{
QApplication app(argc, argv);

CTimedHttp* timedHttp = new CTimedHttp();
timedHttp->get("http://www.google.com.bd/index.html", 60000);
timedHttp->get("http://ferdous.newsit.es/routine.html", 60000);

return app.exec();
}

jacek
6th September 2008, 00:31
This works for download of a single file in the main application. But problem arises when I try to download more than one file. The program just hangs!
Your implementation is not suited for multiple downloads. You have just a single set of variables that control the download state, so you can't share them between multiple downloads. For example, when you invoke get() for the second time, you overwrite the m_pFile.

QHttp::get() returns an id and both requestStarted() and requestFinished() signals also carry it. You can use it to distinguish between multiple downloads.

Note also that QHttp will start its work after you start the event loop. That is when the program flow reaches "return app.exec()" line.



Another problem occurs when I comment out that message box display. This time, in case of a single file, the download is finished completely. But the process doesn't exit.
As long as the event loop is running, your application will run. By default Qt stops the event loop when you close the last window. If there are no windows, you can't close the last one, so your application keeps running. You will have to stop the event loop yourself.

Ferdous
6th September 2008, 13:48
Thanks for your help.

I've added a signal

void quitApplication()
which is connected to quit() slot

connect(this, SIGNAL(quitApplication()), qApp, SLOT(quit()));
and is emitted at the end of requestTimeout() and timedHttpRequestFinished() function. Now download for a single file works fine.