0

so, I'm trying to run some simple code in Qt to return the contents of a given web page. After doing quick research, I was able to develop my own class to simplify the process:

WebFetch::WebFetch()
{
    nam = new QNetworkAccessManager(this);
    connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(finished(QNetworkReply*)));
}

QString WebFetch::get(QString url)
{
    nam->get(QNetworkRequest(QUrl(url)));
}

void WebFetch::finished(QNetworkReply* reply)
{
    QByteArray data = reply->readAll();
    QString str(data);
}

However, there big problem that I'm finding with the above code is that the call is asynchronous. I would like the "get" function to simply return the string after it is retrieved, which seems impossible on the account that it needs to wait for the finished signal, at which point there's no way of having "get" return whatever content is retrieved by the "finished" slot. Is there any alternative to the above method or is there a way I can get "get" to return the content retrieved by "finished"? Any help would be greatly appreciated. Thanks!

user153737
  • 31
  • 4
  • You can do this without Qt, possibly using [nstream](http://www.keithschwarz.com/interesting/code/?dir=nstream)s, which works perfectly. – Tom Knapen Apr 21 '14 at 18:42
  • As you said, Qt is full asynchronous, with the help of Qt event loop. Even asynchronous looks like to be annoying, it is powerful, for example, in order to hold some error cases, or if the web server takes several seconds to response... – AntiClimacus Apr 21 '14 at 18:43
  • You can run a local QEventLoop to make it synchronous – CapelliC Apr 21 '14 at 20:19

1 Answers1

0

The call being asynchronous is not a problem - it's a big win. With a synchronous call, you're essentially wasting potentially hundreds ok KB of RAM, and an entire thread, just idly waiting for something to come back. You can't write such code while pretending that things happen synchronously or even "quickly" for that matter. I won't even comment on the insanity of running such synchronous code in the GUI thread. It's also a very bad idea to run a local event loop, since suddenly all of your GUI code becomes reentrant. My bet is that you neither design nor test for that.

You have to break down whatever code is expecting the result into two parts: the first part needs to place the request. The second part, in a slot, is notified when the request is finished and continues doing whatever is to be done.

If you wish to have it all in a single method, use C++11:

QNetworkAccessManager * mgr = ...;
QObject::connect(mgr, &QNetworkAccessManager::finished, 
[this, mgr](QNetworkReply * reply){
  // here you can do things with the reply
});
mgr->get(QNetworkRequest("....");

For a complete example, see this 300-line photographic mosaic generator that pulls random images from imgur. It extensively uses asynchronous, multithreaded processing and lambdas in the above style.

Community
  • 1
  • 1
Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313