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. TCP connection for file transfer
Forum Updated to NodeBB v4.3 + New Features

TCP connection for file transfer

Scheduled Pinned Locked Moved Unsolved General and Desktop
16 Posts 5 Posters 4.9k 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.
  • Chandras002C Chandras002

    Dear QT community,

    Another QT newbie. I am trying to use Server and client setup using (Qt5 with TcpSocket) in LAN environment.
    LAN environment has 10 computer's connected with Ethernet. One computer act as server the remaining act like client.

    Server has to 2 things do:

    1. Send message between clients
    2. transfer a (executable and text file) to clients. (another Windows PC in LAN which has Qt installed)

    For the sending message, i am using QTcpSocket (similar to Fortune server /client example)
    Question 1 :
    For the File transfer, I know only the IP address and default port number of destination machine.
    Without any receiving agent at destination machine , how to accomplish using FTP?
    Or is there any alternative way for without using QFtp?

    Question 2: when file transfer possible via QFtp then i my Server has running 2 server (QTcpSocket and QFtp ) which may be complex to implement ?

    Am i missing something? Any thoughts/questions highly welcome Many thanks.

    Cheers!
    chandra

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

    @Chandras002 said in TCP connection for file transfer:

    LAN environment has 10 computer's connected with Ethernet. One computer act as server the remaining act like client.

    Then why reinvent the wheel? File sharing already exists. Keywords: CIFS, Samba, NFS.

    I didn't have a deeper look at QFtp, but I thought it is only a client?

    Qt has to stay free or it will die.

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

      You don't need to use FTP protocol, you can send files directly via TCP.

      1. open the file for reading with QFile
      2. send a qint64 that tells the receiving end how big the file should be
      3. use QFile::read and QTcpSocket::write to send chunks of the file
      4. use QFile::write and QTcpSocket::read on the receiving end to reconstruct the file on the other end

      "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 1 Reply Last reply
      8
      • VRoninV VRonin

        You don't need to use FTP protocol, you can send files directly via TCP.

        1. open the file for reading with QFile
        2. send a qint64 that tells the receiving end how big the file should be
        3. use QFile::read and QTcpSocket::write to send chunks of the file
        4. use QFile::write and QTcpSocket::read on the receiving end to reconstruct the file on the other end
        R Offline
        R Offline
        robcont_
        wrote on last edited by
        #4

        @VRonin
        What if the data that has to be sent is a big QImage? It would be great to use the transaction mechanism. Please, give a look to my topic here.

        VRoninV 1 Reply Last reply
        0
        • R robcont_

          @VRonin
          What if the data that has to be sent is a big QImage? It would be great to use the transaction mechanism. Please, give a look to my topic here.

          VRoninV Offline
          VRoninV Offline
          VRonin
          wrote on last edited by
          #5

          @robcont_ said in TCP connection for file transfer:

          What if the data that has to be sent is a big QImage?

          1MB is not big. You can stream it direcly:

          void VCameraServer::sendTcpData()
          {
                  QDataStream out(mTcpClient);
                  out.setVersion(QDataStream::Qt_5_11);
                  QImage image(filePath);
          if(image.isNull()) 
          return;
                  out << image;
          }
          
          void VCameraClient::newTcpDataRead()
          {   
              QDataStream in(mTcpSocket);
          QImage  image;
              in.setVersion(QDataStream::Qt_5_11);
              in.startTransaction();
              in  >> image;
              if ( !in.commitTransaction() ) 
          return;
              qDebug() << "Recv:" << image.size() << "bytes; img name:" << "; image format:" << image.format();   
              if (image.isNull()) qDebug() << "Recv  image is null!";
              else update();
          }
          

          "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 1 Reply Last reply
          2
          • VRoninV VRonin

            @robcont_ said in TCP connection for file transfer:

            What if the data that has to be sent is a big QImage?

            1MB is not big. You can stream it direcly:

            void VCameraServer::sendTcpData()
            {
                    QDataStream out(mTcpClient);
                    out.setVersion(QDataStream::Qt_5_11);
                    QImage image(filePath);
            if(image.isNull()) 
            return;
                    out << image;
            }
            
            void VCameraClient::newTcpDataRead()
            {   
                QDataStream in(mTcpSocket);
            QImage  image;
                in.setVersion(QDataStream::Qt_5_11);
                in.startTransaction();
                in  >> image;
                if ( !in.commitTransaction() ) 
            return;
                qDebug() << "Recv:" << image.size() << "bytes; img name:" << "; image format:" << image.format();   
                if (image.isNull()) qDebug() << "Recv  image is null!";
                else update();
            }
            
            R Offline
            R Offline
            robcont_
            wrote on last edited by robcont_
            #6

            @VRonin
            Thanks for the quick reply. I tried your code but is not working. The log is the same as what I wrote in my first post here.
            I connected my newTcpDataRead() slots to the readyRead() signal of QTcpSocket. What is not clear to me is why the transactions mechanism doesn't work properly when transferring a QImage. It seems like is not able to rebuild the data received in chunks.

            I'm new on Qt and I'm struggling on this for days.

            JonBJ 1 Reply Last reply
            0
            • R robcont_

              @VRonin
              Thanks for the quick reply. I tried your code but is not working. The log is the same as what I wrote in my first post here.
              I connected my newTcpDataRead() slots to the readyRead() signal of QTcpSocket. What is not clear to me is why the transactions mechanism doesn't work properly when transferring a QImage. It seems like is not able to rebuild the data received in chunks.

              I'm new on Qt and I'm struggling on this for days.

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

              @robcont_
              Not sure what you mean. @VRonin's code looks right to me. Transactions don't care (or know) whether QImages or anything else is being sent.

              I looked at the other question. I note you were using out.device()->seek(0);. I don't suppose that has consequences for the transactions? I didn't understand why you are doing that, why do you have to go back and put a size in instead of putting it in in the first place before the data?

              R 1 Reply Last reply
              0
              • JonBJ JonB

                @robcont_
                Not sure what you mean. @VRonin's code looks right to me. Transactions don't care (or know) whether QImages or anything else is being sent.

                I looked at the other question. I note you were using out.device()->seek(0);. I don't suppose that has consequences for the transactions? I didn't understand why you are doing that, why do you have to go back and put a size in instead of putting it in in the first place before the data?

                R Offline
                R Offline
                robcont_
                wrote on last edited by
                #8

                @JonB

                @VRonin's code looks right to me. Transactions don't care (or know) whether QImages or anything else is being sent.

                @VRonin's code is very close to what I wrote the first time (please take a look here). It works well with small data transferred (strings, numbers, lists) in a single chunk, but not with "bigger" QImage sent over TCP in many chunks. I followed the Fortune Client example , I read the documentation about QDataStream and transactions and I know it was built to simplified data streaming.
                This is why I'm not understanding what's going wrong. Any suggestion or sample code is welcome.

                I looked at the other question. I note you were using out.device()->seek(0);. I don't suppose that has consequences for the transactions? I didn't understand why you are doing that, why do you have to go back and put a size in instead of putting it in in the first place before the data?

                Because when serializing a QImage the size of eachQByteArray block to be sent is not the same as the image itself. The client side must know exactly how many bytes to read, that is the block size not the image size. Below the log of my server part.

                CameraServer: written 452690; block 452690; image 921600
                CameraServer: written 551787; block 551787; image 921600
                CameraServer: written 550869; block 550869; image 921600
                CameraServer: written 550516; block 550516; image 921600
                CameraServer: written 551006; block 551006; image 921600
                CameraServer: written 550753; block 550753; image 921600
                CameraServer: written 550669; block 550669; image 921600
                CameraServer: written 550158; block 550158; image 921600
                CameraServer: written 549714; block 549714; image 921600
                CameraServer: written 549828; block 549828; image 921600
                [...]
                
                VRoninV JonBJ 2 Replies Last reply
                0
                • R robcont_

                  @JonB

                  @VRonin's code looks right to me. Transactions don't care (or know) whether QImages or anything else is being sent.

                  @VRonin's code is very close to what I wrote the first time (please take a look here). It works well with small data transferred (strings, numbers, lists) in a single chunk, but not with "bigger" QImage sent over TCP in many chunks. I followed the Fortune Client example , I read the documentation about QDataStream and transactions and I know it was built to simplified data streaming.
                  This is why I'm not understanding what's going wrong. Any suggestion or sample code is welcome.

                  I looked at the other question. I note you were using out.device()->seek(0);. I don't suppose that has consequences for the transactions? I didn't understand why you are doing that, why do you have to go back and put a size in instead of putting it in in the first place before the data?

                  Because when serializing a QImage the size of eachQByteArray block to be sent is not the same as the image itself. The client side must know exactly how many bytes to read, that is the block size not the image size. Below the log of my server part.

                  CameraServer: written 452690; block 452690; image 921600
                  CameraServer: written 551787; block 551787; image 921600
                  CameraServer: written 550869; block 550869; image 921600
                  CameraServer: written 550516; block 550516; image 921600
                  CameraServer: written 551006; block 551006; image 921600
                  CameraServer: written 550753; block 550753; image 921600
                  CameraServer: written 550669; block 550669; image 921600
                  CameraServer: written 550158; block 550158; image 921600
                  CameraServer: written 549714; block 549714; image 921600
                  CameraServer: written 549828; block 549828; image 921600
                  [...]
                  
                  VRoninV Offline
                  VRoninV Offline
                  VRonin
                  wrote on last edited by
                  #9

                  @robcont_ said in TCP connection for file transfer:

                  Because when serializing a QImage the size of eachQByteArray block to be sent is not the same as the image itself. The client side must know exactly how many bytes to read, that is the block size not the image size. Below the log of my server part.

                  Datastream transactions already take care of this automatically, no need to do anything manually

                  "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 1 Reply Last reply
                  1
                  • VRoninV VRonin

                    @robcont_ said in TCP connection for file transfer:

                    Because when serializing a QImage the size of eachQByteArray block to be sent is not the same as the image itself. The client side must know exactly how many bytes to read, that is the block size not the image size. Below the log of my server part.

                    Datastream transactions already take care of this automatically, no need to do anything manually

                    R Offline
                    R Offline
                    robcont_
                    wrote on last edited by robcont_
                    #10

                    @VRonin said in TCP connection for file transfer:

                    Datastream transactions already take care of this automatically, no need to do anything manually

                    I know, but the code is not working properly and I'm not understanding why. This is why I asked for help on this forum.
                    As I said, when reading the stream with transactions (i.e your sample code) this is my log:

                    QIODevice::ungetChar  (QTcpSocket): Called while transaction is in progress
                    QIODevice::ungetChar  (QTcpSocket): Called while transaction is in progress
                    QIODevice::ungetChar  (QTcpSocket): Called while transaction is in progress
                    QIODevice::ungetChar  (QTcpSocket): Called while transaction is in progress
                    QIODevice::ungetChar  (QTcpSocket): Called while transaction is in progress
                    QIODevice::ungetChar  (QTcpSocket): Called while transaction is in progress
                    QIODevice::ungetChar  (QTcpSocket): Called while transaction is in progress
                    QIODevice::ungetChar  (QTcpSocket): Called while transaction is in progress
                    QIODevice::ungetChar  (QTcpSocket): Called while transaction is in progress
                    QIODevice::ungetChar  (QTcpSocket): Called while transaction is in progress
                    QIODevice::ungetChar  (QTcpSocket): Called while transaction is in progress
                    QIODevice::ungetChar  (QTcpSocket): Called while transaction is in progress
                    QIODevice::ungetChar  (QTcpSocket): Called while transaction is in progress
                    QIODevice::ungetChar  (QTcpSocket): Called while transaction is in progress
                    QIODevice::ungetChar  (QTcpSocket): Called while transaction is in progress
                    QIODevice::ungetChar  (QTcpSocket): Called while transaction is in progress
                    Qimage is null!
                    
                    VRoninV 1 Reply Last reply
                    0
                    • R robcont_

                      @VRonin said in TCP connection for file transfer:

                      Datastream transactions already take care of this automatically, no need to do anything manually

                      I know, but the code is not working properly and I'm not understanding why. This is why I asked for help on this forum.
                      As I said, when reading the stream with transactions (i.e your sample code) this is my log:

                      QIODevice::ungetChar  (QTcpSocket): Called while transaction is in progress
                      QIODevice::ungetChar  (QTcpSocket): Called while transaction is in progress
                      QIODevice::ungetChar  (QTcpSocket): Called while transaction is in progress
                      QIODevice::ungetChar  (QTcpSocket): Called while transaction is in progress
                      QIODevice::ungetChar  (QTcpSocket): Called while transaction is in progress
                      QIODevice::ungetChar  (QTcpSocket): Called while transaction is in progress
                      QIODevice::ungetChar  (QTcpSocket): Called while transaction is in progress
                      QIODevice::ungetChar  (QTcpSocket): Called while transaction is in progress
                      QIODevice::ungetChar  (QTcpSocket): Called while transaction is in progress
                      QIODevice::ungetChar  (QTcpSocket): Called while transaction is in progress
                      QIODevice::ungetChar  (QTcpSocket): Called while transaction is in progress
                      QIODevice::ungetChar  (QTcpSocket): Called while transaction is in progress
                      QIODevice::ungetChar  (QTcpSocket): Called while transaction is in progress
                      QIODevice::ungetChar  (QTcpSocket): Called while transaction is in progress
                      QIODevice::ungetChar  (QTcpSocket): Called while transaction is in progress
                      QIODevice::ungetChar  (QTcpSocket): Called while transaction is in progress
                      Qimage is null!
                      
                      VRoninV Offline
                      VRoninV Offline
                      VRonin
                      wrote on last edited by
                      #11

                      @robcont_ said in TCP connection for file transfer:

                      QIODevice::ungetChar (QTcpSocket): Called while transaction is in progress

                      do you have 2 threads operating on the same socket?

                      "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 1 Reply Last reply
                      0
                      • VRoninV VRonin

                        @robcont_ said in TCP connection for file transfer:

                        QIODevice::ungetChar (QTcpSocket): Called while transaction is in progress

                        do you have 2 threads operating on the same socket?

                        R Offline
                        R Offline
                        robcont_
                        wrote on last edited by
                        #12

                        @VRonin said in TCP connection for file transfer:

                        do you have 2 threads operating on the same socket?

                        No.
                        My VCameraClient is a custom QML components, inherits from QQuickPaintedItem and manages mTcpClient. When the readyRead() signal is fired up, then the newTcpDataRead() slot is triggered. Here datastream is read and the QQuickPaintedItem is repaint through the update() method.

                        1 Reply Last reply
                        0
                        • R robcont_

                          @JonB

                          @VRonin's code looks right to me. Transactions don't care (or know) whether QImages or anything else is being sent.

                          @VRonin's code is very close to what I wrote the first time (please take a look here). It works well with small data transferred (strings, numbers, lists) in a single chunk, but not with "bigger" QImage sent over TCP in many chunks. I followed the Fortune Client example , I read the documentation about QDataStream and transactions and I know it was built to simplified data streaming.
                          This is why I'm not understanding what's going wrong. Any suggestion or sample code is welcome.

                          I looked at the other question. I note you were using out.device()->seek(0);. I don't suppose that has consequences for the transactions? I didn't understand why you are doing that, why do you have to go back and put a size in instead of putting it in in the first place before the data?

                          Because when serializing a QImage the size of eachQByteArray block to be sent is not the same as the image itself. The client side must know exactly how many bytes to read, that is the block size not the image size. Below the log of my server part.

                          CameraServer: written 452690; block 452690; image 921600
                          CameraServer: written 551787; block 551787; image 921600
                          CameraServer: written 550869; block 550869; image 921600
                          CameraServer: written 550516; block 550516; image 921600
                          CameraServer: written 551006; block 551006; image 921600
                          CameraServer: written 550753; block 550753; image 921600
                          CameraServer: written 550669; block 550669; image 921600
                          CameraServer: written 550158; block 550158; image 921600
                          CameraServer: written 549714; block 549714; image 921600
                          CameraServer: written 549828; block 549828; image 921600
                          [...]
                          
                          JonBJ Offline
                          JonBJ Offline
                          JonB
                          wrote on last edited by
                          #13

                          @robcont_

                          Because when serializing a QImage the size of eachQByteArray block to be sent is not the same as the image itself. The client side must know exactly how many bytes to read, that is the block size not the image size.

                          Apart from @VRonin telling you that is not necessary, which I leave you to sort out with him/others. Even if you do need to do it your way, my issue is with your use of out.device()->seek(0); when transactions are involved. I do not know, but I'm wondering whether it might interfere with how they work. I am suggesting that to do it your way you should at least try not having to seek. Instead, serialize it to a buffer and get your size from there. Then build the block to be sent, as count followed by data, but do it left-to-right, no seeking. You should take this with a pinch of salt: if @VRonin says you need not be doing what you are, you should deal with that.

                          R 1 Reply Last reply
                          0
                          • JonBJ JonB

                            @robcont_

                            Because when serializing a QImage the size of eachQByteArray block to be sent is not the same as the image itself. The client side must know exactly how many bytes to read, that is the block size not the image size.

                            Apart from @VRonin telling you that is not necessary, which I leave you to sort out with him/others. Even if you do need to do it your way, my issue is with your use of out.device()->seek(0); when transactions are involved. I do not know, but I'm wondering whether it might interfere with how they work. I am suggesting that to do it your way you should at least try not having to seek. Instead, serialize it to a buffer and get your size from there. Then build the block to be sent, as count followed by data, but do it left-to-right, no seeking. You should take this with a pinch of salt: if @VRonin says you need not be doing what you are, you should deal with that.

                            R Offline
                            R Offline
                            robcont_
                            wrote on last edited by robcont_
                            #14

                            @JonB said in TCP connection for file transfer:

                            Apart from @VRonin telling you that is not necessary, which I leave you to sort out with him/others.

                            I'm not arguing or questioning what @VRonin said. As I said in previous posts, I know that with transactions is not necessary to send the size of the block, in fact if you look at this post I did not.

                            Even if you do need to do it your way, my issue is with your use of out.device()->seek(0); when transactions are involved. I do not know, but I'm wondering whether it might interfere with how they work. I am suggesting that to do it your way you should at least try not having to seek. Instead, serialize it to a buffer and get your size from there. Then build the block to be sent, as count followed by data, but do it left-to-right, no seeking. You should take this with a pinch of salt: if @VRonin says you need not be doing what you are, you should deal with that.

                            I use out.device()->seek(0) in this last solution, which does NOT use transactions. Anyway, I'll try to follow your advice to buffer the stream, get the size from there and finally build the block.

                            Just for note, I tried @VRonin's code as is, but it gives the same output as mine (here).

                            JonBJ 1 Reply Last reply
                            0
                            • R robcont_

                              @JonB said in TCP connection for file transfer:

                              Apart from @VRonin telling you that is not necessary, which I leave you to sort out with him/others.

                              I'm not arguing or questioning what @VRonin said. As I said in previous posts, I know that with transactions is not necessary to send the size of the block, in fact if you look at this post I did not.

                              Even if you do need to do it your way, my issue is with your use of out.device()->seek(0); when transactions are involved. I do not know, but I'm wondering whether it might interfere with how they work. I am suggesting that to do it your way you should at least try not having to seek. Instead, serialize it to a buffer and get your size from there. Then build the block to be sent, as count followed by data, but do it left-to-right, no seeking. You should take this with a pinch of salt: if @VRonin says you need not be doing what you are, you should deal with that.

                              I use out.device()->seek(0) in this last solution, which does NOT use transactions. Anyway, I'll try to follow your advice to buffer the stream, get the size from there and finally build the block.

                              Just for note, I tried @VRonin's code as is, but it gives the same output as mine (here).

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

                              @robcont_
                              I have a tiny/question thought for you (just guessing, I have no evidence, it might be nonsense). From your code:

                                      // serialize
                                      out << qint64(0) << image;
                                      out.device()->seek(0);
                                      out << (qint64)(block.size() - sizeof(qint64));  // the size of the block to be sent
                              

                              You subtract sizeof(qint64) to allow for your original out << qint64(0), right? But how do you know that when serialized a qint64 occupies sizeof(qint64) bytes? Maybe it does, I don't know, but maybe there is some extra serialization info stored there too??

                              Another thought is: forget about your QImage. Practice sending a block of binary data, about the same size as an image, filled with 0, 1, 2, 3, ... 255, 0, 1, ... byte values, and verify you receive exactly that at the other side too? Because whatever your issue is, it should have nothing to do with being a QImage...

                              VRoninV 1 Reply Last reply
                              3
                              • JonBJ JonB

                                @robcont_
                                I have a tiny/question thought for you (just guessing, I have no evidence, it might be nonsense). From your code:

                                        // serialize
                                        out << qint64(0) << image;
                                        out.device()->seek(0);
                                        out << (qint64)(block.size() - sizeof(qint64));  // the size of the block to be sent
                                

                                You subtract sizeof(qint64) to allow for your original out << qint64(0), right? But how do you know that when serialized a qint64 occupies sizeof(qint64) bytes? Maybe it does, I don't know, but maybe there is some extra serialization info stored there too??

                                Another thought is: forget about your QImage. Practice sending a block of binary data, about the same size as an image, filled with 0, 1, 2, 3, ... 255, 0, 1, ... byte values, and verify you receive exactly that at the other side too? Because whatever your issue is, it should have nothing to do with being a QImage...

                                VRoninV Offline
                                VRoninV Offline
                                VRonin
                                wrote on last edited by
                                #16

                                @JonB said in TCP connection for file transfer:

                                Maybe it does

                                It does, but for a more generic case you can use:

                                const qint64 originalPos = out.device()->pos();
                                out << qint64(0);
                                const qint64 sizeOfHeader = out.device()->pos() - originalPos;
                                out << image;
                                out.device()->seek(0);
                                out << static_cast<qint64>(block.size() - sizeOfHeader );
                                

                                "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

                                • Login

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