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. QTcpServer + QTcpSocket with multi-threading: can never read the whole incoming data
Forum Update on Monday, May 27th 2025

QTcpServer + QTcpSocket with multi-threading: can never read the whole incoming data

Scheduled Pinned Locked Moved Solved General and Desktop
15 Posts 5 Posters 3.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.
  • J.HilkJ J.Hilk

    @Violet-Giraffe
    why don't you overlay your own protocol on top?

    Byte[0] chunkIndex; of Byte[1] totalAmount of Chunks; Byte[2] & Byte[3] bytes to follow; ......

    that way you could send your 100kBytes in nice small 10k byte packages.

    V Offline
    V Offline
    Violet Giraffe
    wrote on last edited by
    #6

    @J.Hilk
    I guess I'll have to, but I expected the sender to implement that behavior already (only without explicit headers). I may need to use Wireshark after all, to double-check whether the data is actually being sent. Thanks for the suggestions.

    1 Reply Last reply
    0
    • V Violet Giraffe

      SOLUTION: I was missing socket.waitForReadyRead() call in my threaded connection handler, which is required, apparently. Thanks to @aha_1980 for the solution.

      I'm experimenting with QTcpServer and QTcpSocket. Eventually, I'll need to receive large chunks of data (and send small chunks in response). I have a Node.js application that sends an ASCII string 100 000 characters long, and QTcpSocket has to receive it. I've tried various approaches, and all of them only read 14 600 bytes. Where is this magic value coming from?

      Here's my server, it's multithreaded by means of my own thread pool class:

      class IndexerServer : public QTcpServer {
      public:
      	IndexerServer();
      	void start(quint16 port);
      protected:
      	void incomingConnection(qintptr handle) override;
      private:
      	CWorkerThreadPool _threadPool;
      };
      
      IndexerServer::IndexerServer() : _threadPool(16, "Indexer server thread pool")
      {
      }
      
      void IndexerServer::start(quint16 port)
      {
      	if (isListening())
      		return;
      
      	if (!listen(QHostAddress::Any, port))
      	{
      		qInfo() << "Starting server on port" << port << "failed:" << errorString();
      		return;
      	}
      
      	qInfo() << "Listening on port" << port;
      }
      
      void IndexerServer::incomingConnection(qintptr handle)
      {
      	if (!handle)
      		return;
      
      	_threadPool.enqueue([this, handle](){
      		qInfo() << "New incoming connection.";
      
      		QTcpSocket socket;
      		socket.setSocketDescriptor(handle);
      		socket.waitForReadyRead();
      
      		QDataStream inStream(&socket);
      		QByteArray data;
      		for (qint64 read = 0; read < 50000;)
      		{
                              const  QByteArray newData = socket.readAll();
      			qInfo() << read;
      			std::this_thread::sleep_for(std::chrono::milliseconds(333));
      		}
      
      // Nope, doesn't work either
      
      //              QByteArray data(50000, Qt::Uninitialized);
      //		do {
      //			inStream.startTransaction();
      //			inStream.readRawData(data.data(), 50000);
      //		} while (!inStream.commitTransaction());
      
      		qInfo() << data.size();
      		qInfo() << QString::fromUtf8(data.data(), 100);
      
      		socket.close();
      	});
      }
      

      I'm only trying to read 50 000 characters which is half of what's being sent, and I always get 14 600 with either method that I try.
      Tried setting the socket read buffer size to 1M, still no luck. What's wrong with this code and how can I read my 100k bytes?

      There is a slight possibility that the Node.js application is not sending the 100k bytes as requested, but there are no errors or exceptions, and I have checked that the Buffer object I'm writing to the socket indeed contains 100k bytes.

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

      @Violet-Giraffe said in QTcpServer + QTcpSocket: can never read more than 14600 bytes:

      14 600 bytes. Where is this magic value coming from?

      I recall this figure is a fundamental TCP max physical packet size, at the lowest level. Nothing to do with Qt, or sockets.

      1 Reply Last reply
      0
      • V Offline
        V Offline
        Violet Giraffe
        wrote on last edited by
        #8

        I fired up Wireshark, and there's something interesting going on. I'm no expert on networking and TCP in particular, but I do think this could be an issue in my TCP server thought, or perhaps even in the Qt TCP layer. Here's what it looks like, you can see that the data was transmitted:

        0_1537701194027_f3e3ef7f-48da-4667-8b43-dda780ff47ef-image.png

        Here's the capture file if someone can be persuaded to look at it: https://mega.nz/#!luoRlRjY!pQG_nr1nIxMkwSx1D4WN9qJjB2e5tkIxgclfhAftRG4
        Transmitter was 192.168.1.2, receiver (the Qt TCP server) is 192.168.1.85.

        On the receiver (Qt TCP socket) end, 1460 bytes was obtained, and then naught more. And here's the specific code I used:

        void IndexerServer::incomingConnection(qintptr handle)
        {
        	if (!handle)
        		return;
        
        	_threadPool.enqueue([this, handle](){
        		qInfo() << "New incoming connection.";
        
        		QTcpSocket socket;
        		socket.setSocketDescriptor(handle);
        		socket.waitForReadyRead();
        
        		QDataStream inStream(&socket);
        		const int dataSize = 100000;
        		QByteArray data;
        		for (qint64 bytesAvailable = socket.bytesAvailable(); data.size() < dataSize; bytesAvailable = socket.bytesAvailable())
        		{
        			if (bytesAvailable > 0)
        			{
        				data.append(socket.readAll());
        				qInfo() << bytesAvailable;
        			}
        
        			std::this_thread::sleep_for(std::chrono::milliseconds(333));
        		}
        
        		qInfo() << data.size();
        		qInfo() << QString::fromUtf8(data.data(), 100);
        		socket.close();
        	});
        }
        

        So what could be wrong, and how to get the data that seems to have been transmitted?

        aha_1980A 1 Reply Last reply
        0
        • V Violet Giraffe

          I fired up Wireshark, and there's something interesting going on. I'm no expert on networking and TCP in particular, but I do think this could be an issue in my TCP server thought, or perhaps even in the Qt TCP layer. Here's what it looks like, you can see that the data was transmitted:

          0_1537701194027_f3e3ef7f-48da-4667-8b43-dda780ff47ef-image.png

          Here's the capture file if someone can be persuaded to look at it: https://mega.nz/#!luoRlRjY!pQG_nr1nIxMkwSx1D4WN9qJjB2e5tkIxgclfhAftRG4
          Transmitter was 192.168.1.2, receiver (the Qt TCP server) is 192.168.1.85.

          On the receiver (Qt TCP socket) end, 1460 bytes was obtained, and then naught more. And here's the specific code I used:

          void IndexerServer::incomingConnection(qintptr handle)
          {
          	if (!handle)
          		return;
          
          	_threadPool.enqueue([this, handle](){
          		qInfo() << "New incoming connection.";
          
          		QTcpSocket socket;
          		socket.setSocketDescriptor(handle);
          		socket.waitForReadyRead();
          
          		QDataStream inStream(&socket);
          		const int dataSize = 100000;
          		QByteArray data;
          		for (qint64 bytesAvailable = socket.bytesAvailable(); data.size() < dataSize; bytesAvailable = socket.bytesAvailable())
          		{
          			if (bytesAvailable > 0)
          			{
          				data.append(socket.readAll());
          				qInfo() << bytesAvailable;
          			}
          
          			std::this_thread::sleep_for(std::chrono::milliseconds(333));
          		}
          
          		qInfo() << data.size();
          		qInfo() << QString::fromUtf8(data.data(), 100);
          		socket.close();
          	});
          }
          

          So what could be wrong, and how to get the data that seems to have been transmitted?

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

          @Violet-Giraffe

          you don't have a waitForReadyRead in your loop? That could prohibit the TCP buffer handling in the background ... I'm not sure.

          if you wanne have a look at some simple example transferring megabytes:

          http://doc.qt.io/qt-5/qtnetwork-loopback-example.html

          Regards

          Qt has to stay free or it will die.

          V 1 Reply Last reply
          2
          • aha_1980A aha_1980

            @Violet-Giraffe

            you don't have a waitForReadyRead in your loop? That could prohibit the TCP buffer handling in the background ... I'm not sure.

            if you wanne have a look at some simple example transferring megabytes:

            http://doc.qt.io/qt-5/qtnetwork-loopback-example.html

            Regards

            V Offline
            V Offline
            Violet Giraffe
            wrote on last edited by
            #10

            @aha_1980 said in QTcpServer + QTcpSocket: can never read the whole incoming data (Updated with new findings on 23.09):

            @Violet-Giraffe

            you don't have a waitForReadyRead in your loop? That could prohibit the TCP buffer handling in the background ... I'm not sure.

            Hmm, you might be right! Simply adding socket.waitForReadyRead(); inside the loop solves the problem. I wish the docs would mention that, I wasted so much time debugging this issue (and looking for the source in the wrong places, e. g. the sender code). The docs only said this method may fail randomly on Windows, so I didn't see any point using it. Meh.

            Thank you!

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

              @Violet-Giraffe said in QTcpServer + QTcpSocket: can never read the whole incoming data (Updated with new findings on 23.09):

              I wish the docs would mention that

              The docs clearly say you should not use blocking calls but signals and slot to get data from a QTcpSocket (or any other Qt class which retrieves data from sockets)

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

              V 1 Reply Last reply
              0
              • Christian EhrlicherC Christian Ehrlicher

                @Violet-Giraffe said in QTcpServer + QTcpSocket: can never read the whole incoming data (Updated with new findings on 23.09):

                I wish the docs would mention that

                The docs clearly say you should not use blocking calls but signals and slot to get data from a QTcpSocket (or any other Qt class which retrieves data from sockets)

                V Offline
                V Offline
                Violet Giraffe
                wrote on last edited by
                #12

                @Christian-Ehrlicher said in QTcpServer + QTcpSocket: can never read the whole incoming data (Updated with new findings on 23.09):

                The docs clearly say you should not use blocking calls but signals and slot to get data from a QTcpSocket (or any other Qt class which retrieves data from sockets)

                "Clearly"? I disagree. Where do the docs say that any kind of blocking use case is prohibited and using signals is mandatory?

                aha_1980A 1 Reply Last reply
                0
                • V Violet Giraffe

                  @Christian-Ehrlicher said in QTcpServer + QTcpSocket: can never read the whole incoming data (Updated with new findings on 23.09):

                  The docs clearly say you should not use blocking calls but signals and slot to get data from a QTcpSocket (or any other Qt class which retrieves data from sockets)

                  "Clearly"? I disagree. Where do the docs say that any kind of blocking use case is prohibited and using signals is mandatory?

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

                  Hi @Violet-Giraffe,

                  I'm glad you solved your issue.

                  Qt is fully event based, so it needs the event loop for correct operation. This might not always and not everywhere be stated, but its just a fundamental fact.

                  There is even a new blog series, where already part one has this topic: https://www.cleanqt.io/blog/crash-course-in-qt-for-c%2B%2B-developers,-part-1

                  In case you use threads, the waitForXxx() functions often do the background processing to keep the event loop alive. (However, it is also possible to use signals&slots in threads ... so many possibilities :))

                  Qt has to stay free or it will die.

                  V 1 Reply Last reply
                  0
                  • aha_1980A aha_1980

                    Hi @Violet-Giraffe,

                    I'm glad you solved your issue.

                    Qt is fully event based, so it needs the event loop for correct operation. This might not always and not everywhere be stated, but its just a fundamental fact.

                    There is even a new blog series, where already part one has this topic: https://www.cleanqt.io/blog/crash-course-in-qt-for-c%2B%2B-developers,-part-1

                    In case you use threads, the waitForXxx() functions often do the background processing to keep the event loop alive. (However, it is also possible to use signals&slots in threads ... so many possibilities :))

                    V Offline
                    V Offline
                    Violet Giraffe
                    wrote on last edited by
                    #14

                    @aha_1980 said in QTcpServer + QTcpSocket: can never read the whole incoming data (Updated with new findings on 23.09):

                    Qt is fully event based, so it needs the event loop for correct operation. This might not always and not everywhere be stated, but its just a fundamental fact.

                    I understand that perfectly, and there is an event loop. I have a QApplication::exec() in main.cpp, and I'm not blocking the main thread that does the processing, I'm only blocking my own worker thread which I expect to only "look" at the state of the program, not affect it so drastically. I don't understand why I can't block my thread and what it is that waitForReadyRead() does. Or, more precisely, if that's how QTcpSocket is designed, and if waitForReadyRead() is the special method to call in this use case for the socket to update/process, I don't understand why this issue is not documented directly. It would only be logical, since QTcpServer does inherently support multithreading and there are multithreading examples for it all over the web (including the official examples). But never mind, I'm glad to put this behind me and move on to implementing the interesting things.

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

                      It is not documented directly because it's an essential part of the Qt design. To handle events Qt needs an eventloop (per thread) - how should a socket event should be retrieved by Qt otherwise when there is no eventloop to retrieve it from the os?
                      http://doc.qt.io/qt-5/threads-qobject.html#per-thread-event-loop

                      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