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 5.0k 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 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