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. QTcpSocket calling readyRead multiple times
Qt 6.11 is out! See what's new in the release blog

QTcpSocket calling readyRead multiple times

Scheduled Pinned Locked Moved Unsolved General and Desktop
7 Posts 3 Posters 4.7k Views 1 Watching
  • 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.
  • N Offline
    N Offline
    Natoleet
    wrote on last edited by Natoleet
    #1

    I'm messing around with QTcpSocket in order to understand how it works. I'm trying to download a 1MB file from the internet and it's calling readyRead multiple times.

    How does QTcpSocket works? And why is it calling readyRead multiple times?

    #include <QCoreApplication>
    #include <QUrl>
    #include <QDebug>
    #include <QObject>
    #include <QTcpSocket>
    
    int main(int argc, char *argv[])
    {
      QCoreApplication a(argc, argv);
    
      auto socket = new QTcpSocket;
    
      QUrl url = "http://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_1mb.mp4";
    
      QObject::connect(socket, &QTcpSocket::connected
      , [=] () {
        qDebug() << "connected";
    
        QString target = url.path();
    
        if (! url.query().isEmpty()) {
          target.append(QString("?%1").arg(url.query()));
        }
    
        QStringList headerList;
        headerList << QString("GET %1 HTTP/1.1").arg(target);
        headerList << QString("Host: %1").arg(url.host());
        headerList << "\r\n";
    
        auto headers = headerList.join("\r\n");
    
        socket->write(headers.toStdString().c_str());
      });
    
      QObject::connect(socket, &QTcpSocket::disconnected
      , [=] () {
        qDebug() << "disconnected";
      });
    
      QObject::connect(socket, &QTcpSocket::readyRead
      , [=] () {
        qDebug() << "reading...";
      });
    
      socket->connectToHost(url.host(), url.port(80));
    
      if (! socket->waitForConnected()) {
        qDebug() << "Error: " << socket->errorString();
      }
    
      return a.exec();
    }
    
    K 1 Reply Last reply
    0
    • N Natoleet

      I'm messing around with QTcpSocket in order to understand how it works. I'm trying to download a 1MB file from the internet and it's calling readyRead multiple times.

      How does QTcpSocket works? And why is it calling readyRead multiple times?

      #include <QCoreApplication>
      #include <QUrl>
      #include <QDebug>
      #include <QObject>
      #include <QTcpSocket>
      
      int main(int argc, char *argv[])
      {
        QCoreApplication a(argc, argv);
      
        auto socket = new QTcpSocket;
      
        QUrl url = "http://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_1mb.mp4";
      
        QObject::connect(socket, &QTcpSocket::connected
        , [=] () {
          qDebug() << "connected";
      
          QString target = url.path();
      
          if (! url.query().isEmpty()) {
            target.append(QString("?%1").arg(url.query()));
          }
      
          QStringList headerList;
          headerList << QString("GET %1 HTTP/1.1").arg(target);
          headerList << QString("Host: %1").arg(url.host());
          headerList << "\r\n";
      
          auto headers = headerList.join("\r\n");
      
          socket->write(headers.toStdString().c_str());
        });
      
        QObject::connect(socket, &QTcpSocket::disconnected
        , [=] () {
          qDebug() << "disconnected";
        });
      
        QObject::connect(socket, &QTcpSocket::readyRead
        , [=] () {
          qDebug() << "reading...";
        });
      
        socket->connectToHost(url.host(), url.port(80));
      
        if (! socket->waitForConnected()) {
          qDebug() << "Error: " << socket->errorString();
        }
      
        return a.exec();
      }
      
      K Offline
      K Offline
      koahnig
      wrote on last edited by koahnig
      #2

      @Natoleet
      Hi and welcome to devnet

      Every time the TCP socket receives information the readyRead signal is issued. Typically it depends on size of information and certainly also on computer and internet speed. Only for very tiny message you may rely upon that the signal may be triggered only once.

      Personally I think the fortune client and fortune server examples are a good entry for understanding the way of implementation. You can run both in parallel on the same machine. When you have one of them in the debugger it is also easy to play around towars what you try to achieve.

      Vote the answer(s) that helped you to solve your issue(s)

      1 Reply Last reply
      0
      • N Offline
        N Offline
        Natoleet
        wrote on last edited by
        #3

        Isn't fortune client example only sending a text message? In my example above, how to save the content in a file?

        K B 2 Replies Last reply
        0
        • N Natoleet

          Isn't fortune client example only sending a text message? In my example above, how to save the content in a file?

          K Offline
          K Offline
          koahnig
          wrote on last edited by
          #4

          @Natoleet

          Basically you can what ever you receive handle as usual in C++. E.g. you can read the socket byte by byte and store in a std::fstream or you can use also QDataStream stuff.

          However, in your case QNetworkAccessManager might be a better choice. It would download the file at once.

          Vote the answer(s) that helped you to solve your issue(s)

          1 Reply Last reply
          0
          • N Natoleet

            Isn't fortune client example only sending a text message? In my example above, how to save the content in a file?

            B Offline
            B Offline
            bsomervi
            wrote on last edited by bsomervi
            #5

            @Natoleet using QNetworkAccessManager you can connect the QNetworkAccessManager::finished(QNetworkReply*) or QNetworkReply::finished() signal to a slot that uses QNetWorkReply::readAll()' signal:

            void MyClass::onRequestComplete(QNetworkReply * reply) {
               if (!reply.error ()) {
                  QFile result {"my_result.txt"};
                  result.write (reply->readAll ());
               }
               reply->deleteLater ();
            }
            
            N 1 Reply Last reply
            0
            • B bsomervi

              @Natoleet using QNetworkAccessManager you can connect the QNetworkAccessManager::finished(QNetworkReply*) or QNetworkReply::finished() signal to a slot that uses QNetWorkReply::readAll()' signal:

              void MyClass::onRequestComplete(QNetworkReply * reply) {
                 if (!reply.error ()) {
                    QFile result {"my_result.txt"};
                    result.write (reply->readAll ());
                 }
                 reply->deleteLater ();
              }
              
              N Offline
              N Offline
              Natoleet
              wrote on last edited by
              #6

              @bsomervi I'm not interested in QNetworkAccessManager I want to understand the sockets and use it with HTTP.
              I tried to read but the first time that readyRead is called is with the headers and the other times is with the body.
              I want to get the header separated and save the body in a file.

              K 1 Reply Last reply
              -1
              • N Natoleet

                @bsomervi I'm not interested in QNetworkAccessManager I want to understand the sockets and use it with HTTP.
                I tried to read but the first time that readyRead is called is with the headers and the other times is with the body.
                I want to get the header separated and save the body in a file.

                K Offline
                K Offline
                koahnig
                wrote on last edited by
                #7

                @Natoleet

                There will not be a rule when readyRead is called. It completely depends on the factors as described above. You like to separate responses you need other means in order to do so.

                Certainly you can use QTcpSocket also for file download with http. However, the idea of Qt is to make live a bit easier. QNetworkAccessManager has been introduced to allow file download with minimal coding. In that case you would also get a readyRead signal, but only once at the end.
                In your approach you basically have to replicate some of this functionality. For small files you may receive only one readyRead signal at the end. However, for larger files you will receive several readyRead. You have to collect the chunks and assemble the complete file and furthermore check somehow if it is completed.

                As already posted above
                @koahnig said:

                Basically you can what ever you receive handle as usual in C++. E.g. you can read the socket byte by byte and store in a std::fstream or you can use also QDataStream stuff.

                Vote the answer(s) that helped you to solve your issue(s)

                1 Reply Last reply
                0

                • Login

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