Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QNetworkAccessManager like to know about its async behaviour.
Forum Updated to NodeBB v4.3 + New Features

QNetworkAccessManager like to know about its async behaviour.

Scheduled Pinned Locked Moved Solved General and Desktop
7 Posts 4 Posters 3.5k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • R_ramR Offline
    R_ramR Offline
    R_ram
    wrote on last edited by R_ram
    #1

    Hello developers,

    I'm trying to get simple Http requests using QNetworkAccessManager. Its working fine. But i'm surprised with its behaviour of request & response handling.

    I'm trying to get Http response using accessManger->get(url) in a for loop.
    If im sending 100 requests continuously in for loop after all gets pushed into accessmanager. It starts getting response back.

    But originally it should behave like whenever response came back in between for loop corresponding slots should gets called. But it is not like that.

    I have attached sample code with this. Please explain why its behaving like this. or else suggest some ideas to get the same.

    Thank you.

    main.cpp

    #include <QCoreApplication>
    
    
    #include "test.h"
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
        Test test;
        test.start();
    
    
        return a.exec();
    }
    

    test.h

    #ifndef TEST_H
    #define TEST_H
    
    #include <QObject>
    #include <QtNetwork/QNetworkReply>
    #include <QtNetwork/QNetworkRequest>
    
    class Test : public QObject
    {
        Q_OBJECT
    public:
        explicit Test(QObject *parent = 0);
        void start();
    
    signals:
    
    public slots:
        void handleResponse(QNetworkReply* reply);
    };
    
    #endif // TEST_H
    
    

    test.cpp

    #include "test.h"
    #include <QDebug>
    #include <iostream>
    
    #include <QtNetwork/QNetworkAccessManager>
    #include <QtNetwork/QNetworkReply>
    #include <QtNetwork/QNetworkRequest>
    
    using namespace std;
    
    Test::Test(QObject *parent) : QObject(parent)
    {
    
    }
    
    void Test::start()
    {
    
        QNetworkAccessManager *manager = new QNetworkAccessManager(this);
        connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(handleResponse(QNetworkReply*)));
        for(int i=1;i<=20;i++){
            QNetworkRequest *request = new QNetworkRequest(QUrl("http://qt-project.org"));
            request->setAttribute(QNetworkRequest::User , i);
            qDebug()<<"Process Request  "<<i;
            manager->get(*request );
         }
    }
    
    void Test::handleResponse(QNetworkReply *reply)
    {
        qDebug()<<"Handle Response of Request"<<reply->request().attribute(QNetworkRequest::User).toInt();
        reply->deleteLater();
    }
    
    

    Actual Output:

    Process Request   1
    Process Request   2
    Process Request   3
    Process Request   4
    Process Request   5
    Process Request   6
    Process Request   7
    Process Request   8
    Process Request   9
    Process Request   10
    Process Request   11
    Process Request   12
    Process Request   13
    Process Request   14
    Process Request   15
    Process Request   16
    Process Request   17
    Process Request   18
    Process Request   19
    Process Request   20
    Handle Response of Request 2
    Handle Response of Request 3
    Handle Response of Request 4
    Handle Response of Request 6
    Handle Response of Request 5
    Handle Response of Request 7
    Handle Response of Request 8
    Handle Response of Request 9
    Handle Response of Request 10
    Handle Response of Request 11
    Handle Response of Request 12
    Handle Response of Request 13
    Handle Response of Request 14
    Handle Response of Request 15
    Handle Response of Request 16
    Handle Response of Request 17
    Handle Response of Request 18
    Handle Response of Request 19
    Handle Response of Request 20
    Handle Response of Request 1
    

    Expected output:

    Process Request   1
    Process Request   2
    Process Request   3
    Process Request   4
    Process Request   5
    Process Request   6
    Handle Response of Request 2
    Handle Response of Request 3
    Process Request   7
    Process Request   8
    Process Request   9
    Process Request   10
    Handle Response of Request 4
    Handle Response of Request 6
    Process Request   11
    Process Request   12
    Process Request   13
    Handle Response of Request 5
    Handle Response of Request 7
    Process Request   14
    Process Request   15
    Process Request   16
    Process Request   17
    Process Request   18
    Handle Response of Request 8
    Handle Response of Request 9
    Process Request   19
    Process Request   20
    Handle Response of Request 10
    Handle Response of Request 11
    Handle Response of Request 12
    Handle Response of Request 13
    Handle Response of Request 14
    Handle Response of Request 15
    Handle Response of Request 16
    Handle Response of Request 17
    Handle Response of Request 18
    Handle Response of Request 19
    Handle Response of Request 20
    Handle Response of Request 1
    

    I'm expecting response needs to get back in mid of sending requests.

    jsulmJ 1 Reply Last reply
    0
    • R_ramR R_ram

      Hello developers,

      I'm trying to get simple Http requests using QNetworkAccessManager. Its working fine. But i'm surprised with its behaviour of request & response handling.

      I'm trying to get Http response using accessManger->get(url) in a for loop.
      If im sending 100 requests continuously in for loop after all gets pushed into accessmanager. It starts getting response back.

      But originally it should behave like whenever response came back in between for loop corresponding slots should gets called. But it is not like that.

      I have attached sample code with this. Please explain why its behaving like this. or else suggest some ideas to get the same.

      Thank you.

      main.cpp

      #include <QCoreApplication>
      
      
      #include "test.h"
      
      int main(int argc, char *argv[])
      {
          QCoreApplication a(argc, argv);
          Test test;
          test.start();
      
      
          return a.exec();
      }
      

      test.h

      #ifndef TEST_H
      #define TEST_H
      
      #include <QObject>
      #include <QtNetwork/QNetworkReply>
      #include <QtNetwork/QNetworkRequest>
      
      class Test : public QObject
      {
          Q_OBJECT
      public:
          explicit Test(QObject *parent = 0);
          void start();
      
      signals:
      
      public slots:
          void handleResponse(QNetworkReply* reply);
      };
      
      #endif // TEST_H
      
      

      test.cpp

      #include "test.h"
      #include <QDebug>
      #include <iostream>
      
      #include <QtNetwork/QNetworkAccessManager>
      #include <QtNetwork/QNetworkReply>
      #include <QtNetwork/QNetworkRequest>
      
      using namespace std;
      
      Test::Test(QObject *parent) : QObject(parent)
      {
      
      }
      
      void Test::start()
      {
      
          QNetworkAccessManager *manager = new QNetworkAccessManager(this);
          connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(handleResponse(QNetworkReply*)));
          for(int i=1;i<=20;i++){
              QNetworkRequest *request = new QNetworkRequest(QUrl("http://qt-project.org"));
              request->setAttribute(QNetworkRequest::User , i);
              qDebug()<<"Process Request  "<<i;
              manager->get(*request );
           }
      }
      
      void Test::handleResponse(QNetworkReply *reply)
      {
          qDebug()<<"Handle Response of Request"<<reply->request().attribute(QNetworkRequest::User).toInt();
          reply->deleteLater();
      }
      
      

      Actual Output:

      Process Request   1
      Process Request   2
      Process Request   3
      Process Request   4
      Process Request   5
      Process Request   6
      Process Request   7
      Process Request   8
      Process Request   9
      Process Request   10
      Process Request   11
      Process Request   12
      Process Request   13
      Process Request   14
      Process Request   15
      Process Request   16
      Process Request   17
      Process Request   18
      Process Request   19
      Process Request   20
      Handle Response of Request 2
      Handle Response of Request 3
      Handle Response of Request 4
      Handle Response of Request 6
      Handle Response of Request 5
      Handle Response of Request 7
      Handle Response of Request 8
      Handle Response of Request 9
      Handle Response of Request 10
      Handle Response of Request 11
      Handle Response of Request 12
      Handle Response of Request 13
      Handle Response of Request 14
      Handle Response of Request 15
      Handle Response of Request 16
      Handle Response of Request 17
      Handle Response of Request 18
      Handle Response of Request 19
      Handle Response of Request 20
      Handle Response of Request 1
      

      Expected output:

      Process Request   1
      Process Request   2
      Process Request   3
      Process Request   4
      Process Request   5
      Process Request   6
      Handle Response of Request 2
      Handle Response of Request 3
      Process Request   7
      Process Request   8
      Process Request   9
      Process Request   10
      Handle Response of Request 4
      Handle Response of Request 6
      Process Request   11
      Process Request   12
      Process Request   13
      Handle Response of Request 5
      Handle Response of Request 7
      Process Request   14
      Process Request   15
      Process Request   16
      Process Request   17
      Process Request   18
      Handle Response of Request 8
      Handle Response of Request 9
      Process Request   19
      Process Request   20
      Handle Response of Request 10
      Handle Response of Request 11
      Handle Response of Request 12
      Handle Response of Request 13
      Handle Response of Request 14
      Handle Response of Request 15
      Handle Response of Request 16
      Handle Response of Request 17
      Handle Response of Request 18
      Handle Response of Request 19
      Handle Response of Request 20
      Handle Response of Request 1
      

      I'm expecting response needs to get back in mid of sending requests.

      jsulmJ Offline
      jsulmJ Offline
      jsulm
      Lifetime Qt Champion
      wrote on last edited by jsulm
      #2

      @R_ram Well, inside the for loop you just send the requests:

      manager->get(*request );
      

      this call is assynchronous. So, you send 20 requests one after another in a very short time period. In that time period you will not get any responses as the request needs some time to reach the server, server needs time to process the request and then some time is needed to deliver the response from server to your client. I would say what you see is what you should expect. What you can do is: use a timer to send requests more slowly (like one request per second), then you should see something like what you expect.

      https://forum.qt.io/topic/113070/qt-code-of-conduct

      aha_1980A 1 Reply Last reply
      2
      • jsulmJ jsulm

        @R_ram Well, inside the for loop you just send the requests:

        manager->get(*request );
        

        this call is assynchronous. So, you send 20 requests one after another in a very short time period. In that time period you will not get any responses as the request needs some time to reach the server, server needs time to process the request and then some time is needed to deliver the response from server to your client. I would say what you see is what you should expect. What you can do is: use a timer to send requests more slowly (like one request per second), then you should see something like what you expect.

        aha_1980A Offline
        aha_1980A Offline
        aha_1980
        Lifetime Qt Champion
        wrote on last edited by aha_1980
        #3

        @jsulm said in QNetworkAccessManager like to know about its async behaviour.:

        @R_ram Well, inside the for loop you just send the requests:

        manager->get(*request );
        

        this call is assynchronous. So, you send 20 requests one after another in a very short time period. In that time period you will not get any responses as the request needs some time to reach the server, server needs time to process the request and then some time is needed to deliver the response from server to your client.

        That is all correct, but I have to add that slots are no interrupts. A slot can only be called if your function return the execution to Qt's event loop.

        I would say what you see is what you should expect. What you can do is: use a timer to send requests more slowly (like one request per second), then you should see something like what you expect.

        Using a QTimer with a short timeout should really work here.

        Happy New Year!

        Qt has to stay free or it will die.

        jsulmJ 1 Reply Last reply
        4
        • aha_1980A aha_1980

          @jsulm said in QNetworkAccessManager like to know about its async behaviour.:

          @R_ram Well, inside the for loop you just send the requests:

          manager->get(*request );
          

          this call is assynchronous. So, you send 20 requests one after another in a very short time period. In that time period you will not get any responses as the request needs some time to reach the server, server needs time to process the request and then some time is needed to deliver the response from server to your client.

          That is all correct, but I have to add that slots are no interrupts. A slot can only be called if your function return the execution to Qt's event loop.

          I would say what you see is what you should expect. What you can do is: use a timer to send requests more slowly (like one request per second), then you should see something like what you expect.

          Using a QTimer with a short timeout should really work here.

          Happy New Year!

          jsulmJ Offline
          jsulmJ Offline
          jsulm
          Lifetime Qt Champion
          wrote on last edited by
          #4

          @aha_1980 Yes you're right, this is another good point: while the for loop is executing no signals will be triggered (blocked event loop).

          https://forum.qt.io/topic/113070/qt-code-of-conduct

          1 Reply Last reply
          0
          • VRoninV Offline
            VRoninV Offline
            VRonin
            wrote on last edited by
            #5

            Or just add QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); after manager->get(*request );

            "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
            ~Napoleon Bonaparte

            On a crusade to banish setIndexWidget() from the holy land of Qt

            R_ramR 1 Reply Last reply
            2
            • VRoninV Offline
              VRoninV Offline
              VRonin
              wrote on last edited by VRonin
              #6

              request is leaked, allocate it on the stack instead of using new

              Slightly related question for people smarter than me:
              I think QNetworkReply here leaks if Test is destroyed before finished is emitted. I might be wrong though.
              (if it turns out I'm right just change manager->get(*request ); into QNetworkReply* const reply = manager->get(*request ); QObject::connect(reply,&QNetworkReply::finished,reply,&QNetworkReply::deleteLater);)

              EDIT

              the above fails if QCoreApplication dies before the signal:

              // do not use!
              QNetworkReply* const reply = manager->get(*request );
              QObject::connect(reply,&QNetworkReply::finished,[reply](){
              if(qApp) reply->deleteLater();
              else delete reply;
              });
              QObject::connect(qApp,&QCoreApplication::aboutToQuit,reply,[reply](){reply->abort();});
              

              I admit I might be overthinking this though so seek a second opinion

              EDIT 2:

              Thanks to @kshegunov , I was indeed overthinking it. The QNetworkReply is a child of QNetworkAccessManager so no need to do anything manually to prevent leaks

              "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
              ~Napoleon Bonaparte

              On a crusade to banish setIndexWidget() from the holy land of Qt

              1 Reply Last reply
              3
              • VRoninV VRonin

                Or just add QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); after manager->get(*request );

                R_ramR Offline
                R_ramR Offline
                R_ram
                wrote on last edited by R_ram
                #7

                @VRonin Thanks for reply. Its working as expected. Thanks a lot for all of your replies.

                1 Reply Last reply
                1

                • Login

                • Login or register to search.
                • First post
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • Users
                • Groups
                • Search
                • Get Qt Extensions
                • Unsolved