QNetworkReply等待完成

17

我正在使用Qt 4.6.3和以下不起作用的代码

QStringList userInfo;
QNetworkRequest netRequest(QUrl("http://api.stackoverflow.com/1.1/users/587532"));
QNetworkReply *netReply = netman->get(netRequest);

// from here onwards not working
netReply->waitForReadyRead(-1);
if (netReply->isFinished()==true)
{userInfo << do sth to reply;}
return userInfo;

由于此函数返回一个空的QStringList,应用程序会崩溃。如何等待请求完成,然后在一个函数内处理回复。


1
老问题,但仍然非常相关。Qt 真的应该为 QNetworkReply 提供一个 waitForFinished() 函数。 - LorenDB
3个回答

44
你可以使用事件循环:
QEventLoop loop;
connect(netReply, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
// here you have done.

此外,您应该考虑添加一些比网络超时时间更短的时间(20秒?)。我不确定即使发生错误是否也会调用finished。因此,您可能还连接到错误信号。


另一个答案也提到了QEventLoop,这个答案曾经是正确的。 - Alexis Wilke
1
我还没有遇到过完成的插槽没有被调用的情况。我知道文档中说它通常会被调用,但对我来说它总是被调用。 - chikuba
这只是意味着你应该考虑连接到一些额外的信号。它并不重要是否“总是为我调用”。可能会出现情况(正如文档所说)当您无法获得finished()信号时,因此您的事件循环将被卡住。 - Kamil Klimek

6
这里的回复都使用了旧的语法,不适用于最新版本的QT。 等待网络请求完成的方法:
QEventLoop loop;
connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
loop.exec();

5

首先,我建议您阅读Qt文档参考中与此相关的文档,您可以在这里找到:http://doc.qt.nokia.com/latest/classes.html

从您的代码示例来看,似乎您已经有了QNetworkRequestQNetworkReply以及一个QNetworkAccessManager。您需要做的是将一个槽连接到finished(QNetworkReply *)信号。每当一个挂起的网络回复完成时,都会发射此信号。

QNetworkAccessManager *manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)),
        this, SLOT(replyFinished(QNetworkReply*)));

manager->get(QNetworkRequest(QUrl("http://api.stackoverflow.com")));
现在,在您的插槽中,您可以读取响应请求时发送的数据。类似于:
void MyClass::MySlot(QNetworkReply *data) {
    QFile file("dataFromRequest");
    if (!file.open(QIODevice::WriteOnly))
        return;
    file.write(data->readAll());
    file.close();
}

编辑:

如果需要同步等待信号,请使用QEventLoop。这里有一个示例:

http://wiki.forum.nokia.com/index.php/How_to_wait_synchronously_for_a_Signal_in_Qt


我也知道这个,但是我怎么能在同一个函数内返回接收到的数据呢?(我没有额外的插槽函数) - yolo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,