QNetworkReply wait for finished - qt

I am using Qt 4.6.3 and the following not-working code
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;
as this function returns an empty QStringList, the app crashes. How to wait until the request has finished and then process the reply within one function

You can use event loop:
QEventLoop loop;
connect(netReply, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
// here you have done.
Also you should consider adding some shorter then network timeout (20s?). I'm not sure if finished is called even if an error occured. So it is possible, that you have connect to error signal also.

First I recommend you to read the relevant documentation from the Qt Documentation Reference that you can find here: http://doc.qt.nokia.com/latest/classes.html.
Looking at your code sample it seems that you already have, along side with QNetworkRequest and QNetworkReply, a QNetworkAccessManager. What you need is to connect a slot to the finished(QNetworkReply *) signal. This signal is emitted whenever a pending network reply is finished.
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(replyFinished(QNetworkReply*)));
manager->get(QNetworkRequest(QUrl("http://api.stackoverflow.com")));
Now, in your slot, you can read the data which was sent in response to your request. Something like:
void MyClass::MySlot(QNetworkReply *data) {
QFile file("dataFromRequest");
if (!file.open(QIODevice::WriteOnly))
return;
file.write(data->readAll());
file.close();
}
EDIT:
To wait synchronously for a signal use QEventLoop. You have an example here
http://wiki.forum.nokia.com/index.php/How_to_wait_synchronously_for_a_Signal_in_Qt

These replies here are all using old syntax and do not apply to the latest QT.
To wait for the network request to finish:
QEventLoop loop;
connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
loop.exec();

Related

QNetworkAccessManager blocks its thread (freezes) when server unreachable

When server is unreachable, post() from QNetworkAccessManager(NAM) blocks thread's eventloop, it practically freezes the thread, even if the timeout signal is triggered, the quit slot is not called, it is just appended to the queue (it is been debugged while using) and is called after NAM stops blocking it, which can be minute or two. SSL is checked and everything is correct, even the version of openssl library. If I use dynamically created NAM or timer, the behavior is the same. Unknown error is printed no slot is triggered from reply signals. No SSL error or the other.
The problem is that the thread is not responsive to user inputs either like quit the application which has to wait until the NAM stops blocking the eventloop. Quit slot of the thread of course tries to interrupt the eventLoopServer in the presented method, but the slot is called after the NAM stops blocking the thread's eventloop.
Any ideas how to set timer to NAM? Or to stay responsive? If I did not used local eventloop and just connect to finished signal, the behavior is the same (based on googling)
QNetworkAccessManager mgr;
QObject::connect(&mgr, SIGNAL(finished(QNetworkReply*)), eventLoopServer, SLOT(quit()));
//eventLoopServer is created in init procedure, which is called after the thread of this controller class has been started
QTimer timer;
timer.setSingleShot(true);
QObject::connect(&timer, SIGNAL(timeout()), eventLoopServer, SLOT(quit()));
QNetworkRequest request( QUrl( QString("my url address") ) );//there is valid url (checked), not possible to share
QUrlQuery params;
params.addQueryItem("serial",licenseKey);
params.addQueryItem("pcid",pcid);
QByteArray postData ;
postData.append(params.toString());
QSslConfiguration conf = request.sslConfiguration();
conf.setPeerVerifyMode(QSslSocket::VerifyNone);
request.setSslConfiguration(conf);
QNetworkReply *reply=mgr.post(request, postData);
QObject::connect(reply, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(processSSLError(QList<QSslError>)));
QObject::connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(processError(QNetworkReply::NetworkError)));
QObject::connect(reply, SIGNAL(finished()),eventLoopServer, SLOT(quit()));
timer.start(5000);
eventLoopServer->exec();
QString strReply = (QString)reply->readAll();
qDebug()<<reply->errorString(); // prints "Unknown error"

QNetworkReply error signal not detected when connection is lost

I'm downloading files from a remote server with Qt5.5 and everything works fine but I can't detect when a QNetworkReply returns an error.
In fact, I am trying to check the case if the user is downloading a file and suddenly, he loses his Internet connection (because why not :-) ). To do that, I start a download and unplug my Ethernet cable a few seconds after.
Is the signal QNetworkReply::error(QNetworkReply::NetworkError) emitted in this case? If yes, why am I not entering my slot in my code below?
void MyClass::download(QUrl url)
{
QNetworkRequest request = QNetworkRequest(url);
QNetworkReply *reply = pManager.get(request);
// finished() is called after error(), but try both
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(requestError(QNetworkReply::NetworkError)));
connect(reply, SIGNAL(finished()), this, SLOT(requestFinished()));
}
void MyClass::requestError(QNetworkReply::NetworkError err)
{
qDebug() << "error";
}
void MyClass::requestFinished()
{
qDebug() << "finished";
}
I also connected the access manager like this :
connect(&pManager, SIGNAL(finished(QNetworkReply*)), SLOT(requestFinished(QNetworkReply*)));
When the Internet connection is not interrupted, I am going in the slot requestFinished(), but if there's not Internet anymore, I am not entering any slot.
Am I doing something wrong?
Ok, nevermind, I was doing it wrong. Since I want to check the internet connection, I have to check the network availability via QNetworkAccessManager, by doing this :
QNetworkConfigurationManager manager;
pManager.setConfiguration(manager.defaultConfiguration());
connect(&pManager, SIGNAL(networkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility)), this, SLOT(networkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility)));
And when the Internet breaks down, I will be in the corresponding slot.

QNetworkAccessManager sends GET two times

I've got some class to interfere with HTTP-server.
Here is meaningfull code parts:
const QString someClass::BASEURL = QString("http://127.0.0.1:8000/?");
someClass::someClass():
manager(new QNetworkAccessManager(this))
{
}
QNetworkReply *someClass::run(QString request)
{
qDebug() << request;
QEventLoop loop;
QObject::connect(manager, SIGNAL(finished(QNetworkReply*)), &loop, SLOT(quit()));
QNetworkReply *res = manager->get(QNetworkRequest(QUrl(BASEURL + request)));
loop.exec();
return res;
}
When I call method run(), sometimes (not every time) the are two identical GET-requests
(I looked with tcpdump). qDebug() executes 1 time.
Is there some error in my code? I can't see any possible explanation.
UPDATE:
After some tcpdump ouptut research.
After second request it sends packet with RST flag as an answer to FIN.
But I still can see no difference in TCP-streams that triggers the problem and that doesn't.
F.e. here is wireshark's output. Stream 8 went well. Stream 11 was duplicated with Stream 12.
I'm stuck with this. Maybe it's some protocol errors from server-size, I'm not sure. Or maybe it's a bug in QNetworkAccessManager.
Have you tried rewriting you code to be more asynchronous without using QEventLoop in a local scope? Your code looks good to me, but there might be some weird QT bug that you running into in the way it queues up requests for processing and using QEventLoop in the local scope. I usually use QNetworkAccessManager in the following manner to send GET and POST requests:
void someClass::run(QString request)
{
qDebug() << request;
QObject::connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(on_request_complete(QNetworkReply*)));
QNetworkReply *res = manager->get(QNetworkRequest(QUrl(BASEURL + request)));
}
void someClass::on_request_complete(QNetworkReply* response)
{
// Do stuff with your response here
}

How to send data back from PHP after a HTTP Post in Qt?

I'm using this code to make a simple HTTP Post ( a login )
QNetworkAccessManager *nwam = new QNetworkAccessManager;
QNetworkRequest request(QUrl("http://localhost/laptop/trylogin.php"));
QByteArray data;
QUrl params;
QString userString(user);
QString passString(pass);
params.addQueryItem("user", userString );
params.addQueryItem("pass", passString );
data.append(params.toString());
data.remove(0,1);
QNetworkReply *reply = nwam->post(request,data);
If the logging succeedes or not, how do i send and read the response in Qt ?
You get the response / reply in the reply pointer.
Use QNetworkReply::error() to see if there was an error.
You can catch reply signals cause it works with Signals and slots.. So you have to connect a slot to the signal httpreadyread emitted by reply and then read the reply by reply.readAll method.. READ qtnetwork module documentation..

downloadProgress not emitted from QNetworkReply

I'm trying to build a module which downloads a binary file in Qt, using QNetworkAccessManager. I use the same approach detailed in the documentation (see below), but while I do get readyRead signals, downloadProgress never arrives.
Everything happens on the same thread (the project is big so I cannot paste it all).
Any ideas?
QNetworkRequest request;
request.setUrl("http://XXX.s3.amazonaws.com/XXX.exe");
request.setRawHeader("User-Agent", "MyOwnBrowser 1.0");
QNetworkAccessManager * m_manager = new QNetworkAccessManager( this );
m_reply = m_manager->get(request);
m_reply->setParent(this);
connect(m_reply, SIGNAL(readyRead()), this, SLOT(slotReadyRead()));
connect(m_reply, SIGNAL(downloadProgress(qint64 bytesReceived, qint64 bytesTotal)),
this, SLOT(replyDownloadProgress(qint64 bytesReceived, qint64 bytesTotal)));
ok found it
wow what a simple mistake.
the answer is syntactic:
connect(m_reply, SIGNAL(downloadProgress(qint64 bytesReceived, qint64 bytesTotal)),
this, SLOT(replyDownloadProgress(qint64 bytesReceived, qint64 bytesTotal)));
is an error
it should be:
connect(m_reply, SIGNAL(downloadProgress(qint64 , qint64 )),
this, SLOT(replyDownloadProgress(qint64 , qint64 ));
once i changed it, i got the signal.
QT DOES NOT CHECK SYNTAX ERRORS IN ITS PREPROCESSOR (note to self)
I've patched my Qt to use a qFatal() instead of qWarning(), so the app asserts instead of printing error messages (that cannot be seen when linking against a release-build Qt). YMMV.

Resources