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.
  • C Offline
    C Offline
    Cyrille de Brebisson
    wrote on last edited by aha_1980
    #1

    Hello,

    I am working on an app that uses QTcpSockets, and I have some issues...

    The app is using Qsocket write, in a bytesWritten slot to write from a data queue and read of bytesAvailable in the readyRead slot...

    But I have 2 issues:

    1. Data writing seems to block the UI. I think that it is because I do not know how much can be written at a time in the write call. So the write tries to write all it has in buffer, most likely causing a TCP write block.
      When using winsock sockets API, one can use non blocking sockets and WSAEWOULDBLOCK to control this. But what is the QT equivalent?
    2. Nothing seems to happen when the UI is not "up"... ie, when the application is minimized to tray. (note, the application is a Qml app)...

    Any idea as to what I should do to remedies these issues?

    Thanks,
    Cyrille

    1 Reply Last reply
    0
    • 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 Online
                  Christian EhrlicherC Online
                  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 Online
                      Christian EhrlicherC Online
                      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 Online
                            Christian EhrlicherC Online
                            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