我遇到了一些我无法看到自己的错误。在研究了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本身的完成信号获取数据,但也没有出现。
感谢任何可能知道正在发生的事情的人。
答案 0 :(得分:2)
您的线程的run()
方法中没有事件循环,因此任何网络代码都无法正常工作。
您应该将所有代码放入QObject
,然后将其移至通用线程。 QThread::run()
的默认实现会旋转事件循环。
我也没有太多理由要求有多个解析器。您可以简单地让QNetworkReply
在其内部缓冲区中累积响应,直到请求完成为止 - 然后您可以一次性解析它,从而无需解析器状态。使用finished
广告位代替readyRead
。 readyRead
广告位仅对大量请求有意义。
以下是如何做到的。请注意布防机制,以防止工作线程和主线程之间的比赛。您可以保证在调用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"