QTcpSocket calling readyRead multiple times



  • 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();
    }
    

  • Moderators

    @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.



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


  • Moderators

    @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.



  • @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 ();
    }
    


  • @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.


  • Moderators

    @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.


Log in to reply
 

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