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. Help writing non blocking TCP code
Forum Updated to NodeBB v4.3 + New Features

Help writing non blocking TCP code

Scheduled Pinned Locked Moved Unsolved General and Desktop
13 Posts 3 Posters 1.2k 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.
  • kshegunovK Offline
    kshegunovK Offline
    kshegunov
    Moderators
    wrote on last edited by
    #2

    Have a look here:
    https://wiki.qt.io/WIP-How_to_create_a_simple_chat_application

    Read and abide by the Qt Code of Conduct

    1 Reply Last reply
    2
    • C Offline
      C Offline
      Cyrille de Brebisson
      wrote on last edited by
      #3

      Hello,

      This code uses socketStream << jsonData; to send the data...

      I am assuming that this uses the write function to do the writing...
      This means that if the message is large (10MB, 100MB for example), this call, which is in the UI thread will block the UI...

      This is problematic as my application needs the sending to happen while the rest of the UI stays active...

      In order to do that, my application saves the data to be sent and keep a "next to write" pointer in memory. Something like this (pseudo code written on the fly):

      QByteArray dataToSend; // The data that needs to be sent
      int sendingPos; // pos of the next chunk to send
      
      // Called by the user to initiate a data sending...
      void onUserTellsSystemToSend(QByteArray data)
      {
        dataToSend= data; // make a copy of the data
        sendingPos= socket.write(dataToSend.data(), min(dataToSend.count(), 10*1024)); // send the first 10K.
      }
      
      // This is connected to the socked byteWritten signal to do the rest of the sending ansychrnously
      void onByteWrittenSlot(int NbBytes)
      {
        if (sendingPos>=dataToSend.count()) // Done sending?
          dataToSend.clear;                 // clear the buffer
        else
          sendingPos+= socket.write(dataToSend.data(), min(dataToSend.count()-sendinPos, 10*1024)); // send the next 10kb...
      }
      

      But I think that even then the write in the onByteWrittenSlot function still ends up blocking as the socket inner buffer is full at this time, hence my write blocks the slot and the message queue...

      When using berkley socket in the past, I would mark my socket as non blocking and the write call would return the number of bytes that it could write without blocking, but I have not found how to do that with QT.

      Could someone confirm this?

      Cyrille

      kshegunovK 1 Reply Last reply
      0
      • C Cyrille de Brebisson

        Hello,

        This code uses socketStream << jsonData; to send the data...

        I am assuming that this uses the write function to do the writing...
        This means that if the message is large (10MB, 100MB for example), this call, which is in the UI thread will block the UI...

        This is problematic as my application needs the sending to happen while the rest of the UI stays active...

        In order to do that, my application saves the data to be sent and keep a "next to write" pointer in memory. Something like this (pseudo code written on the fly):

        QByteArray dataToSend; // The data that needs to be sent
        int sendingPos; // pos of the next chunk to send
        
        // Called by the user to initiate a data sending...
        void onUserTellsSystemToSend(QByteArray data)
        {
          dataToSend= data; // make a copy of the data
          sendingPos= socket.write(dataToSend.data(), min(dataToSend.count(), 10*1024)); // send the first 10K.
        }
        
        // This is connected to the socked byteWritten signal to do the rest of the sending ansychrnously
        void onByteWrittenSlot(int NbBytes)
        {
          if (sendingPos>=dataToSend.count()) // Done sending?
            dataToSend.clear;                 // clear the buffer
          else
            sendingPos+= socket.write(dataToSend.data(), min(dataToSend.count()-sendinPos, 10*1024)); // send the next 10kb...
        }
        

        But I think that even then the write in the onByteWrittenSlot function still ends up blocking as the socket inner buffer is full at this time, hence my write blocks the slot and the message queue...

        When using berkley socket in the past, I would mark my socket as non blocking and the write call would return the number of bytes that it could write without blocking, but I have not found how to do that with QT.

        Could someone confirm this?

        Cyrille

        kshegunovK Offline
        kshegunovK Offline
        kshegunov
        Moderators
        wrote on last edited by
        #4

        Correct. However this tutorial also provides a threaded example where the UI thread is kept disentangled from the socket operations.

        Read and abide by the Qt Code of Conduct

        C 1 Reply Last reply
        3
        • kshegunovK kshegunov

          Correct. However this tutorial also provides a threaded example where the UI thread is kept disentangled from the socket operations.

          C Offline
          C Offline
          Cyrille de Brebisson
          wrote on last edited by
          #5

          @kshegunov
          Hello, Sorry, I missed the 2nd part, since they was not much visible code, I did not spot it...

          Anyhow, what you are saying is that, in my case, I have to go threaded to solve my issues? There is no way to change the code in the onByteWrittenSlot to make it work, something like:

          // This is connected to the socked byteWritten signal to do the rest of the sending ansychrnously
          void onByteWrittenSlot(int NbBytes)
          {
            if (sendingPos>=dataToSend.count()) // Done sending?
              dataToSend.clear;                 // clear the buffer
            else {
              int nb= socket.getNumberOfBytesICanWriteWithoutBlocking();
              sendingPos+= socket.write(dataToSend.data(), min(dataToSend.count()-sendinPos, nb)); // send the next  block
            }
          }
          

          Cyrille

          kshegunovK 1 Reply Last reply
          0
          • C Cyrille de Brebisson

            @kshegunov
            Hello, Sorry, I missed the 2nd part, since they was not much visible code, I did not spot it...

            Anyhow, what you are saying is that, in my case, I have to go threaded to solve my issues? There is no way to change the code in the onByteWrittenSlot to make it work, something like:

            // This is connected to the socked byteWritten signal to do the rest of the sending ansychrnously
            void onByteWrittenSlot(int NbBytes)
            {
              if (sendingPos>=dataToSend.count()) // Done sending?
                dataToSend.clear;                 // clear the buffer
              else {
                int nb= socket.getNumberOfBytesICanWriteWithoutBlocking();
                sendingPos+= socket.write(dataToSend.data(), min(dataToSend.count()-sendinPos, nb)); // send the next  block
              }
            }
            

            Cyrille

            kshegunovK Offline
            kshegunovK Offline
            kshegunov
            Moderators
            wrote on last edited by
            #6

            @Cyrille-de-Brebisson said in Help writing non blocking TCP code:

            Anyhow, what you are saying is that, in my case, I have to go threaded to solve my issues?

            You don't "have to", strictly, but if you're working with rather big datasets it's going to be beneficial, so you don't get the network latency to show into the GUI thread.

            There is no way to change the code in the onByteWrittenSlot to make it work, something like

            However you change it it's still going to require time to flush the buffers from the socket layer to the actual network, and from Qt to the socket layer. If the data is large-ish, it can be noticeable, so that's when you'd opt for threads - when you can't tolerate the latency. In most cases you can work with the GUI thread fine, though, I'm not saying you always have to do the threading.

            (Note that Qt already buffers the data for you, so most of what you do with that second buffer isn't necessary)

            Read and abide by the Qt Code of Conduct

            C 1 Reply Last reply
            4
            • kshegunovK kshegunov

              @Cyrille-de-Brebisson said in Help writing non blocking TCP code:

              Anyhow, what you are saying is that, in my case, I have to go threaded to solve my issues?

              You don't "have to", strictly, but if you're working with rather big datasets it's going to be beneficial, so you don't get the network latency to show into the GUI thread.

              There is no way to change the code in the onByteWrittenSlot to make it work, something like

              However you change it it's still going to require time to flush the buffers from the socket layer to the actual network, and from Qt to the socket layer. If the data is large-ish, it can be noticeable, so that's when you'd opt for threads - when you can't tolerate the latency. In most cases you can work with the GUI thread fine, though, I'm not saying you always have to do the threading.

              (Note that Qt already buffers the data for you, so most of what you do with that second buffer isn't necessary)

              C Offline
              C Offline
              Cyrille de Brebisson
              wrote on last edited by
              #7

              Hello,

              @kshegunov said in Help writing non blocking TCP code:

              Note that Qt already buffers the data for you, so most of what you do with that second buffer isn't necessary)

              Does this mean that if I do a socket.write(QByteArray), regardless of the size of the byteArray, it will write the whole thing at once (ie: write will return the count of the QByteArray) as QT will buffer the array (this is assuming of course that they are no errors)?

              When is onByteWrittenSlot called? Once the whole data that was sent to write is finally fully passed through to the native network layer? or would writing 10MB to a socket cause multiple signals?

              If I reuse the above 10MB example.
              If I have a 10MB ByteArray can I do a single socket.write(array) and will I get a single onByteWrittenSlot signal in return?

              Cyrille

              kshegunovK 1 Reply Last reply
              0
              • Christian EhrlicherC Offline
                Christian EhrlicherC Offline
                Christian Ehrlicher
                Lifetime Qt Champion
                wrote on last edited by
                #8

                @Cyrille-de-Brebisson said in Help writing non blocking TCP code:

                When is onByteWrittenSlot called?

                Is perfectly documented in the signal documentation:

                This signal is emitted every time a payload of data has been written to the device's current write channel. The bytes argument is set to the number of bytes that were written in this payload.

                Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                Visit the Qt Academy at https://academy.qt.io/catalog

                C 1 Reply Last reply
                3
                • Christian EhrlicherC Christian Ehrlicher

                  @Cyrille-de-Brebisson said in Help writing non blocking TCP code:

                  When is onByteWrittenSlot called?

                  Is perfectly documented in the signal documentation:

                  This signal is emitted every time a payload of data has been written to the device's current write channel. The bytes argument is set to the number of bytes that were written in this payload.

                  C Offline
                  C Offline
                  Cyrille de Brebisson
                  wrote on last edited by
                  #9

                  Hello,

                  @Christian-Ehrlicher said in Help writing non blocking TCP code:

                  This signal is emitted every time a payload of data has been written to the device's current write channel. The bytes argument is set to the number of bytes that were written in this payload.

                  yep, I read that, what I do not know is if a "payload of data" is the equivalent of one write call or something else...

                  Cyrille

                  Christian EhrlicherC 1 Reply Last reply
                  0
                  • C Cyrille de Brebisson

                    Hello,

                    @Christian-Ehrlicher said in Help writing non blocking TCP code:

                    This signal is emitted every time a payload of data has been written to the device's current write channel. The bytes argument is set to the number of bytes that were written in this payload.

                    yep, I read that, what I do not know is if a "payload of data" is the equivalent of one write call or something else...

                    Cyrille

                    Christian EhrlicherC Offline
                    Christian EhrlicherC Offline
                    Christian Ehrlicher
                    Lifetime Qt Champion
                    wrote on last edited by Christian Ehrlicher
                    #10

                    @Cyrille-de-Brebisson It's OS-dependent and should not matter at all. The important thing is you get a progress.

                    Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                    Visit the Qt Academy at https://academy.qt.io/catalog

                    1 Reply Last reply
                    2
                    • C Cyrille de Brebisson

                      Hello,

                      @kshegunov said in Help writing non blocking TCP code:

                      Note that Qt already buffers the data for you, so most of what you do with that second buffer isn't necessary)

                      Does this mean that if I do a socket.write(QByteArray), regardless of the size of the byteArray, it will write the whole thing at once (ie: write will return the count of the QByteArray) as QT will buffer the array (this is assuming of course that they are no errors)?

                      When is onByteWrittenSlot called? Once the whole data that was sent to write is finally fully passed through to the native network layer? or would writing 10MB to a socket cause multiple signals?

                      If I reuse the above 10MB example.
                      If I have a 10MB ByteArray can I do a single socket.write(array) and will I get a single onByteWrittenSlot signal in return?

                      Cyrille

                      kshegunovK Offline
                      kshegunovK Offline
                      kshegunov
                      Moderators
                      wrote on last edited by
                      #11

                      @Cyrille-de-Brebisson said in Help writing non blocking TCP code:

                      If I have a 10MB ByteArray can I do a single socket.write(array) and will I get a single onByteWrittenSlot signal in return?

                      No you may get multiple, as Christian wrote, it still shouldn't matter.

                      Read and abide by the Qt Code of Conduct

                      1 Reply Last reply
                      1
                      • C Offline
                        C Offline
                        Cyrille de Brebisson
                        wrote on last edited by
                        #12

                        Hello,

                        What maters to me is that I would like, if possible, to not block the GUI...

                        At the moment, my socket.write calls seems to do so :-(

                        I would rather, if possible, avoid threads.

                        So, here is another formulation of the question.
                        Is there a way for me to know how many data can be "in the QT side of the pipe" so that I am not causing stalls in my write calls?

                        Then, I can monitor the differential bettwen the "byte written" signal data and what I sent through write to "throttle" my writes and stay bellow this limit. Limit which might vary per OS/network channel of course.

                        Cyrille

                        1 Reply Last reply
                        0
                        • Christian EhrlicherC Offline
                          Christian EhrlicherC Offline
                          Christian Ehrlicher
                          Lifetime Qt Champion
                          wrote on last edited by
                          #13

                          @Cyrille-de-Brebisson said in Help writing non blocking TCP code:

                          At the moment, my socket.write calls seems to do so :-(

                          But not because of the write() call since this is done async as already explained. Please provide a minimal example to reproduce the issue you're seeing.

                          Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                          Visit the Qt Academy at https://academy.qt.io/catalog

                          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