• 5335阅读
  • 0回复

请助:QNetworkAcessManager  无信号返回 [复制链接]

上一主题 下一主题
离线xiajingan
 
只看楼主 倒序阅读 楼主  发表于: 2010-03-15
— 本帖被 XChinux 从 General Qt Programming 移动到本区(2011-01-02) —
在一个下载程序的开发中,我实现了一个CHttpProvider类用于提供http请求和接收下载数据。先通过GetFileInfo获取远程文件的数据。主线程在获取远程文件数据取,根据文件大小进行分段,然后启动多个下载线程对每段下载。每个线程都会有一个此类的新对象。

结果是主线程式不能正确的获取文件信息,QNetworkAccessManager的head函数后,没有finished(QNetworkReply *)返回。

我考虑,是不是有可能是线程的消息循环的问题,让我无法接受此信号。或者是其它问题,请求帮助!

#include <QHttp>
#include <QNetworkReply>
#include <QNetworkAccessManager>
//#include <QHttpRequestHeader>
//#include <QHttpResponseHeader>
#include <QByteArray>
#include <QWaitCondition>
#include <QMutex>
#include <QPointer>
#include "providerbase.h"
#include "mirror.h"
#include "httpdef.h"

/**
* \class
* \brief send http request and recive response for downloading.
*/
class CHttpProvider :
    public QObject,
    public CProviderBase
{
Q_OBJECT
private:

    QPointer<QNetworkReply>    _reply;
    QPointer<QNetworkAccessManager>    _manager;
    QIODevice *_dest;

    CRemoteFileInfo *_fileInfo;
    QString _contentRange;

    bool _isHeadReq;
    QWaitCondition _condReq;
    QMutex    _mutexReq;

public:
    CHttpProvider();
    virtual bool getFileInfo(CMirror *mirror, CRemoteFileInfo *info);
    virtual void setProviderRange(int start, int end, int length);
    virtual bool startTrans(CMirror *mirror, QIODevice *dest);
    virtual bool stopTrans();
    virtual CProviderBase *createNew();
    virtual ~CHttpProvider();

private:
    bool headRequest(CMirror *mirror = 0);
    bool downloadRequest(CMirror *mirror = 0, QIODevice *dest = 0);


public slots:
    void onFinished();
    void onError(QNetworkReply::NetworkError code);
    void onDownloadProgress(qint64 current, qint64 total);
    void onReadyRead();
    void onReplyFinished(QNetworkReply *reply);
};


#include <QMessageBox>

CHttpProvider::CHttpProvider()
{
    _manager = new QNetworkAccessManager();
    //used to remark head request.
    _isHeadReq = false;

    connect(_manager, SIGNAL(finished(QNetworkReply *)),
        this, SLOT(onReplyFinished(QNetworkReply *)));

}
CHttpProvider::~CHttpProvider()
{
    if (!_reply.isNull())
        _reply->close();
    if (!_reply.isNull())
        _reply->abort();
    if (!_reply.isNull())
        _reply->disconnect();
    if (!_reply.isNull())
        _reply->deleteLater();

    if (!_manager.isNull())
        _manager->deleteLater();
}
bool CHttpProvider::headRequest(CMirror *mirror)
{
    bool ret = false;
    _manager->head(QNetworkRequest(*(mirror->getUrl())));
    _isHeadReq = true;
    _mutexReq.lock();
    if (_condReq.wait(&_mutexReq, HTTP_REQUEST_TIMEOUT))
        ret = true;
    else
        ret = false;
    _mutexReq.unlock();
    return ret;
}
bool CHttpProvider::downloadRequest(CMirror *mirror, QIODevice *dest)
{
    bool ret = false;
    this->_dest = dest;

    if (_dest->open(QIODevice::QIODevice::Append))
    {
        QNetworkRequest getR(*(mirror->getUrl()));
        getR.setRawHeader(QByteArray("Range"), _contentRange.toUtf8());
        _manager->get(getR);
        _isHeadReq = false;

        _mutexReq.lock();
        if (_condReq.wait(&_mutexReq, 20000))
            ret = true;
        else
            ret = false;
        _mutexReq.unlock();
    }
    else
    {
#ifdef _DEBUG
        CTrace::TraceQ.trace("dest device is failed to open");
#endif
    }
    return ret;
}

/**
* \fn
* \brief get remote file information, make a head request and wait result.
*             - inherated from CProviderBase.
*/
bool CHttpProvider::getFileInfo(CMirror *mirror, CRemoteFileInfo *info)
{
    _fileInfo = info;

#ifdef _DEBUG
    CTrace::TraceQ.trace("In GetFileInfo function of http provider to remote %s", qPrintable(mirror->getUrl()->toString()));
#endif

    if (headRequest(mirror))
    {
        _fileInfo->FileSize = _reply->header(QNetworkRequest::ContentLengthHeader).toInt();
        _fileInfo->MimeType = _reply->header(QNetworkRequest::ContentTypeHeader).toString();
        _fileInfo->AcceptRanges = true;
#ifdef _DEBUG
        CTrace::TraceQ.trace("FileInfo as follows: FileSize %d, MimeType %s, AcceptRanges %s",
            _fileInfo->FileSize, qPrintable(_fileInfo->MimeType), _fileInfo->AcceptRanges ? "true" : "false");
#endif
        onFinished();
        return true;
    }
    return false;
}

bool CHttpProvider::startTrans(CMirror *mirror, QIODevice *dest)
{
//    _getId = 0;
    
#ifdef _DEBUG
    CTrace::TraceQ.trace("In StartTrans function of http provider to remote %s", qPrintable(mirror->getUrl()->toString()));
#endif
    return downloadRequest(mirror, dest);
}

bool CHttpProvider::stopTrans()
{
    _reply->close();
    return true;
}

void CHttpProvider::setProviderRange(int start, int end, int length)
{
    _contentRange = QString(tr("%1=%2-%3"))
        .arg(tr("bytes"))
        .arg(start)
        .arg(end);
#ifdef _DEBUG
    CTrace::TraceQ.trace("Current range is set to %s", qPrintable(_contentRange));
#endif
}

CProviderBase *CHttpProvider::createNew()
{
    CHttpProvider *provider = new CHttpProvider();
    return provider;
}


void CHttpProvider::onReplyFinished(QNetworkReply *reply)
{
    this->_reply = reply;
    
    if (!_isHeadReq)
    {
        connect(_reply, SIGNAL(downloadProgress(qint64, qint64)),
            this, SLOT(onDownloadProgress(qint64, qint64)));
        connect(_reply, SIGNAL(finished()),
            this, SLOT(onFinished()), Qt::DirectConnection);
        connect(_reply, SIGNAL(error(QNetworkReply::NetworkError )),
            this, SLOT(onError(QNetworkReply::NetworkError)));
        connect(_reply, SIGNAL(readyRead()),
            this, SLOT(onReadyRead()));
    }
    _condReq.wakeAll();
}

void CHttpProvider::onFinished()
{
    if (!_reply.isNull())
    {
        _reply->abort();
        _reply->disconnect();
        _reply->deleteLater();
    }

    if (_dest != NULL)
    {
        _dest->close();
    }

#ifdef _DEBUG
    if (_isHeadReq)
        CTrace::TraceQ.trace("HEAD request finished!");
    else
        CTrace::TraceQ.trace("GET request finished!");
#endif

    if (!_isHeadReq && _input != NULL)
    {
        _input->onReadComplete(false);
    }

}

void CHttpProvider::onDownloadProgress(qint64 current, qint64 total)
{
#ifdef _DEBUG
    CTrace::TraceQ.trace("downloading progress, current %d total %d", current, total);
#endif
}

void CHttpProvider::onError(QNetworkReply::NetworkError code)
{
#ifdef _DEBUG
    if (_isHeadReq)
        CTrace::TraceQ.trace("HEAD request error %d", code);
    else
        CTrace::TraceQ.trace("GET request error %d", code);
#endif
    _input->onReadComplete(true);
}

void CHttpProvider::onReadyRead()
{
    QByteArray buff = _reply->readAll();
    int size = buff.length();
    _dest->write(buff);
#ifdef _DEBUG
    CTrace::TraceQ.trace("Another %d is downloaded to dest file", size);
#endif
}
快速回复
限100 字节
 
上一个 下一个