Signals aren't good for bool functions



  • Let's say that I want to check my internet connection in my linux machine. So I have this code:
    [code]
    bool connected_to_internet()
    {
    QProcess ping_google = new QProcess(0);
    QString exec="ping";
    QStringList params;
    params << "google.com" << "-c" << "1" << "-w" << "2";
    ping_google->start(exec, params);
    if(!ping_google->waitForFinished(2005))
    return false;
    if(ping_google->exitCode())
    return false;
    return true;
    }
    [/code]
    I want the code to be more portable, so I thought using this code, instead:
    [code]
    QNetworkAccessManager manager = new QNetworkAccessManager(this);
    connect(manager, SIGNAL(finished(QNetworkReply
    )),
    this, SLOT(replyFinished(QNetworkReply
    )));
    manager->get(QNetworkRequest(QUrl("http://google.com")));
    [/code]
    but it is a boolean killer! The check whether I have internet or not will come from inside the replyFinished() function!
    This prevents me from using:
    [code]
    if(connected_to_internet()){
    //do actions
    }
    [/code]
    Also, I cannot use 'this' in static functions and functions like connected_to_internet() are very nicely used if being static.

    Is there any solution for these problems?



  • QNetworkAccessManager, from what I can see, doesn't support synchronous (or "blocking") http requests. Not because they couldn't do it (blocking is actually easier to implement), but because blocking network stuff is kind of an anti-pattern.

    I agree that a blocking get request would make your code nice and simple. But if you think about it from the user's perspective: it's not nice to block the whole application, only because the website you're using to test the internet connection isn't responding for 20 seconds (or longer).

    I see two possibilities: Create a wrapper for QNetworkAccessManager that reintroduces blocking behaviour. Or (imho better) get rid of the program design that requires blocking.

    //EDIT:
    Maybe a wrapper is not necessary. You could try this:
    @
    QNetworkReply *reply = manager->get(QNetworkRequest(QUrl("http://google.com")));
    while (reply->isRunning())
    {
    sleep(100); // or some equivalent function in order to not use 100% CPU by too frequent polling
    }
    // handle the reply here.
    @

    Note that I'd probably never do it like that in my own code, and I feel a little bit dirty now.



  • Agreed with DerManu.

    @if(connected_to_internet()){
    //do actions
    }@

    This is a block design. You may try use a var instead a function to do the state test, like:

    @
    // isConnected may be a bool type or enum, and getting the state of it should be in another function and only run once before everything is ready.
    if( isConnected ){
    //do actions
    }@



  • Hi,

    I can agree that blocking is not a good approach. But using sleep() in code is not the best solution, as you doing pooling on your own. Better is to take some advantages from Qt and utilize its signals, slots and execution loops.
    I think that you could implement internal event loop that will wait for signal from Network.

    @
    somefunction()
    {
    QNetworkAccessManager *manager = new QNetworkAccessManager(this);
    QEventLoop loop;
    QTimer timer;

    timer.setSingleShot(true);
    connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
    connect(manager, SIGNAL(finished()), &loop, SLOT(quit()));

    timer.start(5000); //your predefined timeout
    manager->get(QNetworkRequest(QUrl("http://google.com")));
    loop.exec();

    if (timer.isActive) //replay received before timer, you can then get replay form network access manager and do whatever you want with it
    else //timer elapsed, no replay from client, ups
    }
    @

    Above do not block whole application. It only creates event loop and 'block' function in which was executed till quit() is called.



  • I was just recently thinking about something similar. The above solution using QEventLoop is a nested eventloop, correct ? I'm using something almost identical in my code. Now yesterday I read this "article":http://delta.affinix.com/2006/10/23/nested-eventloops/, which made me fear that my code is dangerous. Also in the nokia "article":http://www.developer.nokia.com/Community/Wiki/How_to_wait_synchronously_for_a_Signal_in_Qt that gave me the idea to use this, the approach is not recommented.

    Is the use of a nested eventloop for network communication (sockets) ok, or is it potentially dangerous ?



  • It is ok for certain scenario's, but still potentially dangerous. That goes for things like QApplication::processEvents as well.

    The -best- safest thing you can do, IMHO, is avoid them. That includes avoiding using the blocking API's of QProcess and the networking classes. It even includes using QDialog::exec and the QMessageBox static functions: these also run their own eventloop. Yes, that is a lot to swallow...

    Instead, design your application in such a way that you don't need these functions. That will get easier with Qt5, especially if you're using a C++ compiler that supports lambda functions.

    For the actual case here, I'd look into using [[doc:QNetworkConfiguration]].



  • My problem is that I had to redesign a network framework at work which up until then was completely synchronous. Of course I immediately got rid of that and introduced asyncronous methods for all the previously syncronous interface functions. But unfortunatly it was a requirement to also keep the synchronous functions for backwards compatibility reasons (since the framework is used by many applications the company builds).

    So I need something to convert my asyncronous communication to syncronous communication easily (I really don't want to have to develop two completely different solutions for this).

    P.S. the sockets for the communication are running inside their own thread and are not inside the main GUI thread, if that helps.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.