Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. General talk
  3. Qt 6
  4. Sending Large file over QTcpSocket
Forum Updated to NodeBB v4.3 + New Features

Sending Large file over QTcpSocket

Scheduled Pinned Locked Moved Unsolved Qt 6
18 Posts 4 Posters 1.8k Views 2 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.
  • S SlayH

    @JonB The client does receive it in chunks cause my packets are 100 bytes and I just sent a file of 150 and it did send 2 packets. This is the statement printed in the terminal.

    ╭─    ~/Documents/server---clients/build/clients/client.app/Contents/MacOS    main !19 ?5 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── SEGV ✘  51s   10:25:45 PM  ─╮
    ╰─ /Users/test/Documents/server---clients/build/clients/client.app/Contents/MacOS/client ─╯
    2024-03-23 22:26:40.916 client[33849:346985] TSM AdjustCapsLockLEDForKeyTransitionHandling - _ISSetPhysicalKeyboardCapsLockLED Inhibit
    Data received
    Data received

    This is the modified code.

    code_text```
    code_text
    
    
    
    QList<QByteArray> data;
        while (_socket->bytesAvailable())
        {
            data << _socket->readAll();
            qDebug() << "Data received";
        }
    
        _protocol->load_data(data);```
    code_text
    
    S Offline
    S Offline
    SlayH
    wrote on last edited by SlayH
    #8

    @JonB Yeah You are right. I should have embedded the stream with an end file marker or how many packets there are. Gonna try to do it now.

    JonBJ 1 Reply Last reply
    0
    • JonBJ JonB

      @Ronel_qtmaster said in Sending Large file over QTcpSocket:

      Then from the server you write progressively the received data to the file untill it stops sending

      And how would that know "when it stops sending"? To send e.g. a file you need some kind of "total bytes" or equivalent, or a unique "end of file" marker, in the protocol you stream.

      Ronel_qtmasterR Offline
      Ronel_qtmasterR Offline
      Ronel_qtmaster
      wrote on last edited by Ronel_qtmaster
      #9

      @JonB that is why i suggested upload as the first solution because it uses a boundary at the beginning
      @SlayH this is an exemple for uploading an image and text

      QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);

      QHttpPart textPart;
      textPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name="text""));
      textPart.setBody("my text");

      QHttpPart imagePart;
      imagePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
      imagePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name="image""));
      QFile *file = new QFile("image.jpg");
      file->open(QIODevice::ReadOnly);
      imagePart.setBodyDevice(file);
      file->setParent(multiPart); // we cannot delete the file now, so delete it with the multiPart

      multiPart->append(textPart);
      multiPart->append(imagePart);

      QUrl url("http://my.server.tld");
      QNetworkRequest request(url);

      QNetworkAccessManager manager;
      QNetworkReply *reply = manager.post(request, multiPart);
      multiPart->setParent(reply); // delete the multiPart with the reply

      JonBJ 1 Reply Last reply
      0
      • S SlayH

        @JonB Yeah You are right. I should have embedded the stream with an end file marker or how many packets there are. Gonna try to do it now.

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

        @SlayH said in Sending Large file over QTcpSocket:

        with an end file marker

        How are you going to do that when sending packets which contain any pattern of binary bytes read from a file? I think you will need to precede by a byte count (or packet count or some kind of "special/empty" packet at the endif you really wish, but as I said I don't think your packet-ization achieves anything at all or what you might think it achieves).

        Also, as I said earlier. I assume your ready_read() is (supposed to be) a slot for readyRead() signal? Then as long as you have a pattern like

            while (_socket->bytesAvailable())
                data << _socket->readAll();
        

        and assume (as you do) that data will be some kind of "complete set of data or packets" then your algorithm is fatally flawed. Might work for a bit/some cases, might not. You are assuming a relationship which does not exist, such as that for each _socket->write(packet) you will receive some single read, which is not at all true. This is partly why giving up on packets and just sending a byte count followed by a stream of binary bytes would be simpler.

        S 1 Reply Last reply
        0
        • Ronel_qtmasterR Ronel_qtmaster

          @JonB that is why i suggested upload as the first solution because it uses a boundary at the beginning
          @SlayH this is an exemple for uploading an image and text

          QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);

          QHttpPart textPart;
          textPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name="text""));
          textPart.setBody("my text");

          QHttpPart imagePart;
          imagePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
          imagePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name="image""));
          QFile *file = new QFile("image.jpg");
          file->open(QIODevice::ReadOnly);
          imagePart.setBodyDevice(file);
          file->setParent(multiPart); // we cannot delete the file now, so delete it with the multiPart

          multiPart->append(textPart);
          multiPart->append(imagePart);

          QUrl url("http://my.server.tld");
          QNetworkRequest request(url);

          QNetworkAccessManager manager;
          QNetworkReply *reply = manager.post(request, multiPart);
          multiPart->setParent(reply); // delete the multiPart with the reply

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

          @Ronel_qtmaster
          What makes you think the OP has any kind of HTTP server here? I don't see that he has indicated any such thing?

          Ronel_qtmasterR 1 Reply Last reply
          0
          • JonBJ JonB

            @Ronel_qtmaster
            What makes you think the OP has any kind of HTTP server here? I don't see that he has indicated any such thing?

            Ronel_qtmasterR Offline
            Ronel_qtmasterR Offline
            Ronel_qtmaster
            wrote on last edited by
            #12

            @JonB it is just an exemple.If he has a QTcpServer listening to 127.0.01 and port 455 for exemple, he can change the url to QUrl("Http://127.0.0.1:455"), which will reach the tcpserver listening

            JonBJ 1 Reply Last reply
            0
            • Ronel_qtmasterR Ronel_qtmaster

              @JonB it is just an exemple.If he has a QTcpServer listening to 127.0.01 and port 455 for exemple, he can change the url to QUrl("Http://127.0.0.1:455"), which will reach the tcpserver listening

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

              @Ronel_qtmaster
              And this QTcpServer will be able to service HTTP requests, so that you can send your file with QHttpMultiPart which is what you are advocating? Without any Q[Abstract]HttpServer? I must be misunderstanding something then.

              Ronel_qtmasterR 1 Reply Last reply
              0
              • JonBJ JonB

                @SlayH said in Sending Large file over QTcpSocket:

                with an end file marker

                How are you going to do that when sending packets which contain any pattern of binary bytes read from a file? I think you will need to precede by a byte count (or packet count or some kind of "special/empty" packet at the endif you really wish, but as I said I don't think your packet-ization achieves anything at all or what you might think it achieves).

                Also, as I said earlier. I assume your ready_read() is (supposed to be) a slot for readyRead() signal? Then as long as you have a pattern like

                    while (_socket->bytesAvailable())
                        data << _socket->readAll();
                

                and assume (as you do) that data will be some kind of "complete set of data or packets" then your algorithm is fatally flawed. Might work for a bit/some cases, might not. You are assuming a relationship which does not exist, such as that for each _socket->write(packet) you will receive some single read, which is not at all true. This is partly why giving up on packets and just sending a byte count followed by a stream of binary bytes would be simpler.

                S Offline
                S Offline
                SlayH
                wrote on last edited by SlayH
                #14

                @JonB Yeah ready_read() is a slot for readyRead(). I did think that for each _socket->write(packet) there will be an emitted signal for readRead() but You told me it isn't the case.``` If I am supposed to send a byte count followed by a stream of binary bytes, how would it be then ???
                code_text

                JonBJ 1 Reply Last reply
                0
                • S SlayH

                  @JonB Yeah ready_read() is a slot for readyRead(). I did think that for each _socket->write(packet) there will be an emitted signal for readRead() but You told me it isn't the case.``` If I am supposed to send a byte count followed by a stream of binary bytes, how would it be then ???
                  code_text

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

                  @SlayH said in Sending Large file over QTcpSocket:

                  I did think that for each _socket->write(packet) there will be an emitted signal for readRead()

                  That's what I tried to say at the outset, because so many people assume it. It is not the case, at all sorts of levels in the handling.

                  I'm not going to write full code. In outline all you have to do is

                  int size = ...;
                  sendsocket->write(&size, sizeof(size));
                  sendsocket->write(fileContent, size);
                  

                  at sender side.

                  At receiver side, read that initial size and then keep writing received bytes to file till that many bytes have been read. All reads go through onReadyRead slot, but you can only assume that will receive 1 or more bytes any time it's called. You need to receive at least sizeof(size) bytes (allow for accumulating that many bytes over multiple calls to onReadyRead() in e.g. a class member buffer), all subsequent bytes can go to output file counting up/down to that many.

                  You may want to think about how to send that int (do you care about byte-order for cross-platform?). You may find QDataStream's Using Read Transactions useful if you don't want to write your own stuff. (You may only want to use that for the leading int. For the "potentially large" amount of data which follows for the file content you will not want to read all of that into memory/a variable, rather only "chunks" at a time from whatever happens to have arrived there, immediately copied out to destination file.)

                  S 1 Reply Last reply
                  1
                  • JonBJ JonB

                    @SlayH said in Sending Large file over QTcpSocket:

                    I did think that for each _socket->write(packet) there will be an emitted signal for readRead()

                    That's what I tried to say at the outset, because so many people assume it. It is not the case, at all sorts of levels in the handling.

                    I'm not going to write full code. In outline all you have to do is

                    int size = ...;
                    sendsocket->write(&size, sizeof(size));
                    sendsocket->write(fileContent, size);
                    

                    at sender side.

                    At receiver side, read that initial size and then keep writing received bytes to file till that many bytes have been read. All reads go through onReadyRead slot, but you can only assume that will receive 1 or more bytes any time it's called. You need to receive at least sizeof(size) bytes (allow for accumulating that many bytes over multiple calls to onReadyRead() in e.g. a class member buffer), all subsequent bytes can go to output file counting up/down to that many.

                    You may want to think about how to send that int (do you care about byte-order for cross-platform?). You may find QDataStream's Using Read Transactions useful if you don't want to write your own stuff. (You may only want to use that for the leading int. For the "potentially large" amount of data which follows for the file content you will not want to read all of that into memory/a variable, rather only "chunks" at a time from whatever happens to have arrived there, immediately copied out to destination file.)

                    S Offline
                    S Offline
                    SlayH
                    wrote on last edited by
                    #16

                    @JonB Thanks. I'm gonna try it.

                    1 Reply Last reply
                    0
                    • SGaistS Offline
                      SGaistS Offline
                      SGaist
                      Lifetime Qt Champion
                      wrote on last edited by
                      #17

                      Hi,

                      Since you are using QDataStream, you can use transactions.

                      Interested in AI ? www.idiap.ch
                      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                      1 Reply Last reply
                      0
                      • JonBJ JonB

                        @Ronel_qtmaster
                        And this QTcpServer will be able to service HTTP requests, so that you can send your file with QHttpMultiPart which is what you are advocating? Without any Q[Abstract]HttpServer? I must be misunderstanding something then.

                        Ronel_qtmasterR Offline
                        Ronel_qtmasterR Offline
                        Ronel_qtmaster
                        wrote on last edited by
                        #18

                        @JonB Yes exactly.The only thing is that he will have to remove the request headers from the sent packet, and put the original data in a file.

                        In a nutshell, when sending files with upload, the request headers are sent with the file data.You just need to separate both and keep the essential part

                        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