QNetworkAccessManager不返回任何数据

时间:2014-02-04 21:00:00

标签: qt network-programming

我遇到了一些我无法看到自己的错误。在研究了QT和堆栈站点之后,我编写了以下代码:

void RateOfExchangeGetter::run(){
    mRunning = true;
    mAccessManager = new QNetworkAccessManager();
    //connect(mAccessManager, SIGNAL(finished(QNetworkReply*)),
    //         this, SLOT(replyFinished(QNetworkReply*)));

    while(mRunning){
        QNetworkReply *reply;
        for(SiteParser *parser: mSiteParsers){
            QNetworkRequest request(QUrl("https://www.google.pl/"));
            request.setRawHeader("User-Agent", "MyOwnBrowser 1.0");
            qDebug() << "here";
            reply = mAccessManager->get(request);
            parser->setQNetworkReply(reply);
            connect(reply, SIGNAL(readyRead()), parser, SLOT(slotReadyRead()));
            connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
                    parser, SLOT(slotError(QNetworkReply::NetworkError)));
            connect(reply, SIGNAL(sslErrors(QList<QSslError>)),
                    parser, SLOT(slotSslErrors(QList<QSslError>)));
        }
        //for test only ->
        this->sleep(10);
        QByteArray array = reply->read(50);
        qDebug() << array;
    }
} 

好的眼睛可能已经注意到了 - 这段代码放在继承QThread的类中。 由于某种原因(我找不到),我无法从get函数接收任何数据(我知道它是异步的),没有信号被传输,并且在等待10秒之后,没有数据可用于读取。我还试图通过QNetworkAccessManager本身的完成信号获取数据,但也没有出现。

感谢任何可能知道正在发生的事情的人。

1 个答案:

答案 0 :(得分:2)

您的线程的run()方法中没有事件循环,因此任何网络代码都无法正常工作。

您应该将所有代码放入QObject,然后将其移至通用线程。 QThread::run()的默认实现会旋转事件循环。

我也没有太多理由要求有多个解析器。您可以简单地让QNetworkReply在其内部缓冲区中累积响应,直到请求完成为止 - 然后您可以一次性解析它,从而无需解析器状态。使用finished广告位代替readyReadreadyRead广告位仅对大量请求有意义。

以下是如何做到的。请注意布防机制,以防止工作线程和主线程之间的比赛。您可以保证在调用finishedAllRequests 。如果没有这种机制,工作线程可能能够在arm()有机会运行之前处理所有请求,并且没有信号将到达收件人,或者您可能会在下一个请求被处理之前获得多个信号已添加。

connect

输出:

#include <QCoreApplication>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QPointer>
#include <QSslError>
#include <QThread>
#include <QMetaMethod>
#include <QDebug>

class Parser : public QObject {
    Q_OBJECT
    bool m_armed;
    QList<QNetworkReply*> m_replies;
    QPointer<QNetworkAccessManager> m_manager;
    QMetaMethod m_addRequestImpl, m_armImpl;
    Q_SLOT void finished() {
        QNetworkReply * reply = static_cast<QNetworkReply*>(sender());
        Q_ASSERT(m_replies.contains(reply));
        qDebug() << "reply" << reply << "is finished";
        // ... use the data
        m_replies.removeAll(reply);
        if (m_armed && m_replies.isEmpty()) {
            emit finishedAllRequests();
            m_armed = false;
        }
    }
    Q_SLOT void error(QNetworkReply::NetworkError) {
        QNetworkReply * reply = static_cast<QNetworkReply*>(sender());
        m_replies.removeAll(reply);
    }
    Q_SLOT void sslErrors(QList<QSslError>) {
        QNetworkReply * reply = static_cast<QNetworkReply*>(sender());
        m_replies.removeAll(reply);
    }
    Q_INVOKABLE void addRequestImpl(const QNetworkRequest & req) {
        QNetworkReply * reply = m_manager->get(req);
        connect(reply, SIGNAL(finished()), SLOT(finished()));
        connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
                SLOT(error(QNetworkReply::NetworkError)));
        connect(reply, SIGNAL(sslErrors(QList<QSslError>)),
                SLOT(sslErrors(QList<QSslError>)));
        m_replies << reply;
    }
    Q_INVOKABLE void armImpl() {
        if (m_replies.isEmpty()) {
            emit finishedAllRequests();
            m_armed = false;
        } else
            m_armed = true;
    }
    static QMetaMethod method(const char * signature) {
        return staticMetaObject.method(staticMetaObject.indexOfMethod(signature));
    }
public:
    // The API is fully thread-safe. The methods can be accessed from any thread.
    explicit Parser(QNetworkAccessManager * nam, QObject * parent = 0) :
        QObject(parent), m_armed(false), m_manager(nam),
        m_addRequestImpl(method("addRequestImpl(QNetworkRequest)")),
        m_armImpl(method("armImpl()"))
    {}
    void addRequest(const QNetworkRequest & req) {
        m_addRequestImpl.invoke(this, Q_ARG(QNetworkRequest, req));
    }
    void arm() {
        m_armImpl.invoke(this);
    }
    Q_SIGNAL void finishedAllRequests();
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QThread * thread = new QThread(&a);
    thread->start();
    QNetworkAccessManager mgr;
    Parser parser(&mgr);
    mgr.moveToThread(thread);
    parser.moveToThread(thread);
    for (int i = 0; i < 10; ++i) {
        QNetworkRequest request(QUrl("https://www.google.pl/"));
        request.setRawHeader("User-Agent", "MyOwnBrowser 1.0");
        parser.addRequest(request);
    }
    thread->connect(&parser, SIGNAL(finishedAllRequests()), SLOT(quit()));
    a.connect(thread, SIGNAL(finished()), SLOT(quit()));
    parser.arm();
    int rc = a.exec();
    thread->wait();
    delete thread; // Otherwise mgr's destruction would fail
    return rc;
}

#include "main.moc"