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. How to get the whole file from TCP server?
Forum Updated to NodeBB v4.3 + New Features

How to get the whole file from TCP server?

Scheduled Pinned Locked Moved Solved General and Desktop
13 Posts 4 Posters 949 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.
  • M Offline
    M Offline
    mpergand
    wrote on last edited by mpergand
    #2

    Create and open a QFile for writting before you start the download,
    and write data to the file as they arrive.

    QObject::connect(&dataChannel, &FtpDataChannel::dataReceived,
                         [](const QByteArray &data) {
           myFile->write(data);
        });
    

    See docs about QFile.

    K 1 Reply Last reply
    3
    • M mpergand

      Create and open a QFile for writting before you start the download,
      and write data to the file as they arrive.

      QObject::connect(&dataChannel, &FtpDataChannel::dataReceived,
                           [](const QByteArray &data) {
             myFile->write(data);
          });
      

      See docs about QFile.

      K Offline
      K Offline
      kayakaan02
      wrote on last edited by
      #3

      @mpergand Thank you, but this doesn't resolve the problem.

      I think QByteArray's size is too small, for example the file is 1450kb but it can only write first 64kb of it

      1 Reply Last reply
      0
      • K Offline
        K Offline
        kayakaan02
        wrote on last edited by
        #4

        @mpergand So I first opened the file before receiving data, to empty the file. And then wrote the data to file in append mode. But the size is not consistent?

        Sometimes it's 320kb sometimes 250kb sometimes 550kb and so on.

        Any idea what can be causing this or how can I solve it?

        jsulmJ 1 Reply Last reply
        0
        • K kayakaan02

          @mpergand So I first opened the file before receiving data, to empty the file. And then wrote the data to file in append mode. But the size is not consistent?

          Sometimes it's 320kb sometimes 250kb sometimes 550kb and so on.

          Any idea what can be causing this or how can I solve it?

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

          @kayakaan02 Please show how exactly you open the file.

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

          1 Reply Last reply
          0
          • K Offline
            K Offline
            kayakaan02
            wrote on last edited by kayakaan02
            #6

            This is how I open the file, because I think the connect is repeating itself, I first opened the file and emptied it with WriteOnly and empty string, and then appended the data. b.txt is 1401 kb and test.txt changes(350-680kb).

            QString server = "127.0.0.1";
            QString file = "b.txt";
            
            QCoreApplication app(argc, argv);
            FtpClient ftpClient;
            FtpDataChannel dataChannel;
            FtpControlChannel controlChannel;
            
            QFile myfqle("C:\\test.txt");
            myfqle.open(QIODevice::WriteOnly);
            myfqle.write("");
            // Print all data retrieved from the server on the console.
            QObject::connect(&dataChannel, &FtpDataChannel::dataReceived,
                             [](const QByteArray &data) {
                QFile myfqle("C:\\test.txt");
                myfqle.open(QIODevice::Append);
                myfqle.write(data);
                });
            

            edit: I also tried myfqle.write(data.constData()); it expands the range a few hundred kbs but still not enough

            jsulmJ 1 Reply Last reply
            0
            • K kayakaan02

              This is how I open the file, because I think the connect is repeating itself, I first opened the file and emptied it with WriteOnly and empty string, and then appended the data. b.txt is 1401 kb and test.txt changes(350-680kb).

              QString server = "127.0.0.1";
              QString file = "b.txt";
              
              QCoreApplication app(argc, argv);
              FtpClient ftpClient;
              FtpDataChannel dataChannel;
              FtpControlChannel controlChannel;
              
              QFile myfqle("C:\\test.txt");
              myfqle.open(QIODevice::WriteOnly);
              myfqle.write("");
              // Print all data retrieved from the server on the console.
              QObject::connect(&dataChannel, &FtpDataChannel::dataReceived,
                               [](const QByteArray &data) {
                  QFile myfqle("C:\\test.txt");
                  myfqle.open(QIODevice::Append);
                  myfqle.write(data);
                  });
              

              edit: I also tried myfqle.write(data.constData()); it expands the range a few hundred kbs but still not enough

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

              @kayakaan02 said in How to get the whole file from TCP server?:

              QFile myfqle("C:\test.txt");

              You should not open the file every time you get new data! Opening an closing files is a time consuming operation.
              Did you also check whether the whole file was actually transferred?

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

              1 Reply Last reply
              2
              • K Offline
                K Offline
                kayakaan02
                wrote on last edited by kayakaan02
                #8

                @jsulm

                QFile myfqle("C:\\test.txt");
                myfqle.open(QIODevice::WriteOnly);
                myfqle.write("");
                // Print all data retrieved from the server on the console.
                QObject::connect(&dataChannel, &FtpDataChannel::dataReceived,
                                 [&myfqle](const QByteArray &data) {
                    myfqle.write(data.constData());
                    });
                

                This gives me better results but still not enough. I can get data up to 1200-1300kb's consistently but it gets worse with the data size.

                Any way I can optimize this more?

                Also for the size of 4203kb it outputs a file in range of 2000-3000kb range.

                1 Reply Last reply
                0
                • K Offline
                  K Offline
                  kayakaan02
                  wrote on last edited by
                  #9

                  Edit: I solved the problem by using Sleep(1) at the end of every buffer uploading from ftp client.

                  JonBJ 1 Reply Last reply
                  0
                  • K Offline
                    K Offline
                    kayakaan02
                    wrote on last edited by
                    #10

                    @jsulm I also have another question.

                    So when transmitting a rar file, with using data.constData() it cannot create the rar file. But it has no problem with only using data.

                    Is constData() really important/what does it really do?

                    1 Reply Last reply
                    0
                    • K kayakaan02

                      Edit: I solved the problem by using Sleep(1) at the end of every buffer uploading from ftp client.

                      JonBJ Offline
                      JonBJ Offline
                      JonB
                      wrote on last edited by JonB
                      #11

                      @kayakaan02 said in How to get the whole file from TCP server?:

                      Edit: I solved the problem by using Sleep(1) at the end of every buffer uploading from ftp client.

                      You really ought not and should not need to do any such thing. I cannot believe writing to a file cannot keep up with FTP reception.

                      The first thing to note is I do not see where you close() the file? Until you close a file you are writing to you may get an "incorrect" size.

                      So when transmitting a rar file, with using data.constData() it cannot create the rar file. But it has no problem with only using data.

                      Again something fishy here! Both should work equally.

                      Another question: what is the scope/lifetime of the QFile myfqle you show? Is it a local variable in some function? Does it definitely live until all the bytes have been received, or could it go out of scope before it has finished receiving?

                      1 Reply Last reply
                      0
                      • K Offline
                        K Offline
                        kayakaan02
                        wrote on last edited by
                        #12

                        It is the exact code from the example "Qt SCXML FTP Client Example". It will be a bit long but let me put the main.cpp:

                        struct Command {
                            QString cmd;
                            QString args;
                        };
                        
                        int main(int argc, char *argv[])
                        {
                        //    if (argc != 3) {
                        //        qDebug() << "Usage: ftpclient <server> <file>";
                        //        return 1;
                        //    }
                        
                            //QString server = QString::fromLocal8Bit(argv[1]);
                           // QString file = QString::fromLocal8Bit(argv[2]);
                            QString server = "127.0.0.1";
                            QString file = "b.txt";
                        
                            QCoreApplication app(argc, argv);
                            FtpClient ftpClient;
                            FtpDataChannel dataChannel;
                            FtpControlChannel controlChannel;
                        
                        ///////////////////////////////////////////////////////////////////////////////////
                        ///////////////////////////////////////////////////////////////////////////////////
                        ///////////////////////////////////////////////////////////////////////////////////
                            //HERE///////////////////////////////////////////////////////////////////////////////////
                            QFile myfqle("C:\\Users\\thevo\\Desktop\\aaf5h6j\\test7.txt");
                            myfqle.open(QIODevice::WriteOnly);
                            // Print all data retrieved from the server on the console.
                            QObject::connect(&dataChannel, &FtpDataChannel::dataReceived,
                                             [&myfqle](const QByteArray &data) {
                                myfqle.write(data);
                            });
                        ///////////////////////////////////////////////////////////////////////////////////
                        ///////////////////////////////////////////////////////////////////////////////////
                        ///////////////////////////////////////////////////////////////////////////////////
                        ///////////////////////////////////////////////////////////////////////////////////
                        
                        
                            // Translate server replies into state machine events.
                            QObject::connect(&controlChannel, &FtpControlChannel::reply, &ftpClient,
                                             [&ftpClient](int code, const QString &parameters) {
                                ftpClient.submitEvent(QString("reply.%1xx")
                                                      .arg(code / 100), parameters);
                            });
                        
                            // Translate commands from the state machine into FTP control messages.
                            ftpClient.connectToEvent("submit.cmd", &controlChannel,
                                                     [&controlChannel](const QScxmlEvent &event) {
                                controlChannel.command(event.name().mid(11).toUtf8(),
                                                       event.data().toMap()["params"].toByteArray());
                            });
                        
                            // Commands to be sent
                            QList<Command> commands({
                                {"cmd.USER", "admin"},// login
                                {"cmd.PORT", "21"},         // announce port for data connection,
                                                          // args added below.
                                {"cmd.RETR", file}        // retrieve a file
                            });
                        
                            // When entering "B" state, send the next command.
                            ftpClient.connectToState("B", QScxmlStateMachine::onEntry([&]() {
                                if (commands.isEmpty()) {
                                    app.quit();
                                    return;
                                }
                                Command command = commands.takeFirst();
                                qDebug() << "Posting command" << command.cmd << command.args;
                                ftpClient.submitEvent(command.cmd, command.args);
                            }));
                        
                            // If the server asks for a password, send one.
                            ftpClient.connectToState("P", QScxmlStateMachine::onEntry([&ftpClient]() {
                                qDebug() << "Sending password";
                                ftpClient.submitEvent("cmd.PASS", "qt");
                            }));
                            qDebug() << "hi" << "\n";
                            QString hi;
                        
                            // Connect to our own local FTP server
                            controlChannel.connectToServer(server);
                            QObject::connect(&controlChannel, &FtpControlChannel::opened,
                                             [&](const QHostAddress &address, int) {
                                dataChannel.listen(address);
                                hi= dataChannel.portspec();
                                qDebug() << "hi" << hi<< commands[1].args << "\n";
                                commands[1].args = selam;
                        
                                ftpClient.start();
                            });
                        
                            qDebug() << "file: " << file << "\n";
                        
                        
                            return app.exec();
                        }
                        
                        

                        I put the part inside of a lot of "/"'s so it's easier to notice.

                        If I close the file in or after the QObject::connect scope it just says device not open and no data in file at all so I assume it runs main more than once to get the data.

                        I tried to declare myfqle outside of the main scope but it generated some errors.

                        Also at the end of the main I did some extra changes just to see how things work but that doesn't make any difference

                        It acts weird at constData() with rar files that makes me wonder why :D

                        JonBJ 1 Reply Last reply
                        0
                        • K kayakaan02

                          It is the exact code from the example "Qt SCXML FTP Client Example". It will be a bit long but let me put the main.cpp:

                          struct Command {
                              QString cmd;
                              QString args;
                          };
                          
                          int main(int argc, char *argv[])
                          {
                          //    if (argc != 3) {
                          //        qDebug() << "Usage: ftpclient <server> <file>";
                          //        return 1;
                          //    }
                          
                              //QString server = QString::fromLocal8Bit(argv[1]);
                             // QString file = QString::fromLocal8Bit(argv[2]);
                              QString server = "127.0.0.1";
                              QString file = "b.txt";
                          
                              QCoreApplication app(argc, argv);
                              FtpClient ftpClient;
                              FtpDataChannel dataChannel;
                              FtpControlChannel controlChannel;
                          
                          ///////////////////////////////////////////////////////////////////////////////////
                          ///////////////////////////////////////////////////////////////////////////////////
                          ///////////////////////////////////////////////////////////////////////////////////
                              //HERE///////////////////////////////////////////////////////////////////////////////////
                              QFile myfqle("C:\\Users\\thevo\\Desktop\\aaf5h6j\\test7.txt");
                              myfqle.open(QIODevice::WriteOnly);
                              // Print all data retrieved from the server on the console.
                              QObject::connect(&dataChannel, &FtpDataChannel::dataReceived,
                                               [&myfqle](const QByteArray &data) {
                                  myfqle.write(data);
                              });
                          ///////////////////////////////////////////////////////////////////////////////////
                          ///////////////////////////////////////////////////////////////////////////////////
                          ///////////////////////////////////////////////////////////////////////////////////
                          ///////////////////////////////////////////////////////////////////////////////////
                          
                          
                              // Translate server replies into state machine events.
                              QObject::connect(&controlChannel, &FtpControlChannel::reply, &ftpClient,
                                               [&ftpClient](int code, const QString &parameters) {
                                  ftpClient.submitEvent(QString("reply.%1xx")
                                                        .arg(code / 100), parameters);
                              });
                          
                              // Translate commands from the state machine into FTP control messages.
                              ftpClient.connectToEvent("submit.cmd", &controlChannel,
                                                       [&controlChannel](const QScxmlEvent &event) {
                                  controlChannel.command(event.name().mid(11).toUtf8(),
                                                         event.data().toMap()["params"].toByteArray());
                              });
                          
                              // Commands to be sent
                              QList<Command> commands({
                                  {"cmd.USER", "admin"},// login
                                  {"cmd.PORT", "21"},         // announce port for data connection,
                                                            // args added below.
                                  {"cmd.RETR", file}        // retrieve a file
                              });
                          
                              // When entering "B" state, send the next command.
                              ftpClient.connectToState("B", QScxmlStateMachine::onEntry([&]() {
                                  if (commands.isEmpty()) {
                                      app.quit();
                                      return;
                                  }
                                  Command command = commands.takeFirst();
                                  qDebug() << "Posting command" << command.cmd << command.args;
                                  ftpClient.submitEvent(command.cmd, command.args);
                              }));
                          
                              // If the server asks for a password, send one.
                              ftpClient.connectToState("P", QScxmlStateMachine::onEntry([&ftpClient]() {
                                  qDebug() << "Sending password";
                                  ftpClient.submitEvent("cmd.PASS", "qt");
                              }));
                              qDebug() << "hi" << "\n";
                              QString hi;
                          
                              // Connect to our own local FTP server
                              controlChannel.connectToServer(server);
                              QObject::connect(&controlChannel, &FtpControlChannel::opened,
                                               [&](const QHostAddress &address, int) {
                                  dataChannel.listen(address);
                                  hi= dataChannel.portspec();
                                  qDebug() << "hi" << hi<< commands[1].args << "\n";
                                  commands[1].args = selam;
                          
                                  ftpClient.start();
                              });
                          
                              qDebug() << "file: " << file << "\n";
                          
                          
                              return app.exec();
                          }
                          
                          

                          I put the part inside of a lot of "/"'s so it's easier to notice.

                          If I close the file in or after the QObject::connect scope it just says device not open and no data in file at all so I assume it runs main more than once to get the data.

                          I tried to declare myfqle outside of the main scope but it generated some errors.

                          Also at the end of the main I did some extra changes just to see how things work but that doesn't make any difference

                          It acts weird at constData() with rar files that makes me wonder why :D

                          JonBJ Offline
                          JonBJ Offline
                          JonB
                          wrote on last edited by
                          #13

                          @kayakaan02
                          FWIW this code never sees completion of the file transfer and closes QFile myfqle. Are you looking at the file content/size while the program is still running or after you have exited it? Because the former will not give reliable size/content.

                          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