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 won't receive client data on connected QTcpSocket
Forum Updated to NodeBB v4.3 + New Features

QTcpServer won't receive client data on connected QTcpSocket

Scheduled Pinned Locked Moved Solved General and Desktop
24 Posts 4 Posters 2.8k 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.
  • D Offline
    D Offline
    dmitttri
    wrote on last edited by dmitttri
    #1

    Hi everyone!
    First of all, thanks a lot for all the great effort and support available on this forum.

    I am trying to write a very simple TCP client/server example, and I based my work on existing Qt examples: localfortuneclient and threadedfortuneserver.

    My approach is very simple (at this point):

    • start a listening server on the localhost address
    • on each incoming connection, start a dedicated worker thread, and pass provided socket descriptor (so worker thread can receive/send data)
    • right now it should just receive one client message (a string) and print it
    • start client which will connect to the server, and send one string message

    So far I got these results:

    • client starts, connects to the server and writes one string (to the QTcpSocket object), and write method seems to be fine (returns correct number of written bytes)
    • server runs, listen on incoming connections, once newconnection is established, starts a thread (which is supposed to receive some client data), but server socket read always returns zero, no data is being received

    I will gladly copy in all source code (it's very simple), but let me first try to just copy in server relevant code. My SimpleServer inherits QTcpServer and overrides icommingConnection method:

    void SimpleServer::incomingConnection(qintptr socketDescriptor)
    {
        qDebug() << "New incoming connection";
    
        ServerWorkerThread *thread = new ServerWorkerThread(socketDescriptor, this);
        connect(thread, &ServerWorkerThread::finished, thread, &ServerWorkerThread::deleteLater);
        thread->start();
    }
    

    ServerWorkingThread inherits QThread and overrides run method, which initialize a new QTcpSocket using the provided socketDescriptor, and then tries to read data. read always return 0, my thread max running time expires (5 seconds) and no data was received.

    void ServerWorkerThread::run()
    {
        bool workerThreadShouldRun = true;
        QTcpSocket tcpSocket;
    
        if (!tcpSocket.setSocketDescriptor(this->socketDescriptor))
        {
            qDebug() << THREAD_ID << "setSocketDescriptor fail";
            return;
        }
    
        qDebug() << THREAD_ID << "Socket info:" << tcpSocket.state() << tcpSocket.openMode();
        qDebug() << THREAD_ID << "Awaiting client message";
    
        QTime workerThreadTimeoutTime = QTime::currentTime().addSecs(THREAD_MAX_RUNNING_TIME_S);
        while (workerThreadShouldRun)
        {
            QByteArray buffer = tcpSocket.read(MAX_RECEIVE_BUFFER_SIZE);
            if (buffer.size() > 0)
            {
                qDebug() << THREAD_ID 
                         << "Received client message:" << QString(buffer.data())
                         << buffer.size() << "bytes";
    
                workerThreadShouldRun = false;
            }
            
            if (QTime::currentTime() > workerThreadTimeoutTime)
            {
                qDebug() << THREAD_ID
                         << "Thread max running time expired";
                workerThreadShouldRun = false;
            }
            this->msleep(100);
        }
        qDebug() << THREAD_ID << "Thread exit";
    }
    

    Obviously I am doing something wrong, and it would be great if someone can provide hints on why read method may fail, although client side seems to send data correctly.

    NOTE: Socket info shows that socket is connected and is in Read/Write mode.

    This is the client method to send data, where write is successful:

    bool SimpleClient::pokeServer (const char *pokeMsg)
    {
        if (!this->isConnected())
        {
            return false;
        }
    
        int bytesWritten = this->socket->write(pokeMsg);
        if (bytesWritten != strlen(pokeMsg))
        {
            qDebug() << "Socket write error" << strlen(pokeMsg) << bytesWritten;
            return false;
        }
        
        qDebug() << "Sent to server: " << pokeMsg;
        return true;
    }
    

    Thanks in advance!

    Christian EhrlicherC 1 Reply Last reply
    0
    • D dmitttri

      @dmitttri

      For the sake of completeness of this post, I am providing very simple TCP client/server example with client sending data, and server receiving it.

      Server side is not implemented with threads, and will serve me as the starting point to properly implement threaded server, based on all recommendations I got up to now.

      CLIENT SIDE

      Simple Client.h

      #ifndef SIMPLECLIENT_H
      #define SIMPLECLIENT_H
      
      #include <QTcpSocket>
      #include <QAbstractSocket>
      
      #define SOCKET_OPERATION_TIMEOUT_MS 3000
      
      class SimpleClient
      {
      public:
          SimpleClient() {};
      
          bool connectToHost(QString serverIP, qint16 serverPort)
          {
      
              this->socket = new QTcpSocket;
              socket->connectToHost(QHostAddress(serverIP), serverPort);
      
              qDebug() << "Connecting to" << serverIP << ":" << serverPort;
              socket->connectToHost(QHostAddress(serverIP), serverPort);
      
              if (!socket->waitForConnected(SOCKET_OPERATION_TIMEOUT_MS))
              {
                  qDebug() << "Error, connection timeout, server not accessible.";
                  return false;
              }
              qDebug() << "Connected";
              return true;
          }
      
          bool write(const char *data, int len)
          {
              if (socket->state() != QAbstractSocket::ConnectedState)
              {
                  qDebug() << "Write error, client not connected";
                  return false;
              }
      
              int bytesWritten = this->socket->write(data, len);
              qDebug() << "Written" << bytesWritten << "bytes";
      
              if(!this->socket->waitForBytesWritten())
              {
                  qDebug() << "Write error";
                  return false;
              }
              qDebug() << "Write success";
              return true;
          }
      
          void disconnectFromHost()
          {
              if (socket->state() == QAbstractSocket::ConnectedState)
              {
                  this->socket->disconnectFromHost();
                  qDebug() << "Disconnected";
              }
          }
      
      private:
          QTcpSocket *socket = nullptr;
      };
      
      #endif // SIMPLECLIENT_H
      

      MainClient.cpp

      #include <QThread>
      #include <QDebug>
      #include "SimpleClient.h"
      
      int main(int argc, char *argv[])
      {
          SimpleClient client;
      
          client.connectToHost("127.0.0.1", 9000);
          client.write("Hello Server", sizeof("Hello Server"));
      
          // NOTE: It's fine to sleep for some time now, we don't have GUI
          // or any networking async operations, required to be handled by the event loop
          QThread::sleep(2);
          client.disconnectFromHost();
      
          return 0;
      }
      

      SERVER SIDE (not threaded)

      SimpleServer.h

      #ifndef SIMPLESERVER_H
      #define SIMPLESERVER_H
      
      #include <QDebug>
      #include <QTcpServer>
      #include <QTcpSocket>
      
      class SimpleServer : public QObject
      {
          Q_OBJECT;
      
      public:
          SimpleServer() {};
      
          bool start(QString serverIP, qint16 serverPort)
          {
              tcpServer = new QTcpServer;
      
              connect (tcpServer, &QTcpServer::newConnection, this, &SimpleServer::onNewConnection);
      
              qDebug() << "Awaiting for new connections "
                       << "IP" << serverIP
                       << "PORT" << serverPort;
      
              tcpServer->listen(QHostAddress(serverIP), serverPort);
              return true;
          }
      
      private slots:
          void onNewConnection()
          {
              qDebug() << "New connection";
      
              QTcpSocket *socket = tcpServer->nextPendingConnection();
              connect(socket, &QAbstractSocket::disconnected, socket, &QObject::deleteLater);
      
              qDebug() << "Socket info:" << socket->state() << socket->openMode();
              socket->waitForReadyRead();
      
              int bytesAvailable = socket->bytesAvailable();
              qDebug() << "Received" << bytesAvailable << "bytes";
          }
          
      private:
          QTcpServer *tcpServer = nullptr;
      };
      
      #endif // SIMPLESERVER_H
      

      MainServer.cpp

      #include <QCoreApplication>
      #include <QtCore>
      
      #include "SimpleServer.h"
      
      
      int main(int argc, char *argv[])
      {
          QCoreApplication app(argc, argv);
      
          SimpleServer server;
          server.start("127.0.0.1", 9000);
      
          return app.exec();
      }
      
      D Offline
      D Offline
      dmitttri
      wrote on last edited by dmitttri
      #24

      @dmitttri

      [SOLVED]
      I am posting the solution for the original post:

      1. Client had an issue, after socket write call it's required to call sync waitForBytesWritten, which will process actual socket writing
      2. Server had an issue, in the run method, we can't just call socket read, it's required to call waitForReadyRead which takes care to process socket and fill it with incoming data.

      Thanks everyone for their suggestions and help!

      I am also posting working sample code, which is only meant for demo purposes, to show a simple synchronous approach to TCP client and server

      DEMO TCP CLIENT AND SERVER WITH THREADS

      MainClient.cpp

      #include "SimpleClient.h"
      
      int main(int argc, char *argv[])
      {
          SimpleClient client;
      
          if (!client.connectToServer("127.0.0.1", 9000))
          {
              return -1;
          }
      
          if (!client.pokeServer("Hello Server"))
          {
              return -1;
          }
      
          return 0;
      }
      

      SImpleClient.h

      #ifndef SIMPLECLIENT_H
      #define SIMPLECLIENT_H
      
      #include <QTcpSocket>
      #include <QAbstractSocket>
      
      #define SOCKET_OPERATION_TIMEOUT_MS 3000
      
      class SimpleClient
      {
      public:
          SimpleClient();
      
          bool connectToServer(QString serverIP, qint16 serverPort);
          int  pokeServer(const char *pokeMsg);
      
      private:
          QTcpSocket *socket = nullptr;
      };
      
      #endif // SIMPLECLIENT_H
      

      SImpleClient.cpp

      #include <QByteArray>
      #include "SimpleClient.h"
      
      
      SimpleClient::SimpleClient()
      {
          this->socket = new QTcpSocket;
      }
      
      bool SimpleClient::connectToServer(QString serverIP, qint16 serverPort)
      {    
          qDebug() << "Connecting to" << serverIP << ":" << serverPort;
      
          socket->connectToHost(QHostAddress(serverIP), serverPort);
      
          if (!socket->waitForConnected(SOCKET_OPERATION_TIMEOUT_MS))
          {
              qDebug() << socket->errorString();
              return false;
          }
      
          qDebug() << "Connected";
          return true;
      }
      
      
      int SimpleClient::pokeServer (const char *pokeMsg)
      {
          qDebug() << "Sending :" << QString(pokeMsg);
      
          this->socket->write(pokeMsg, strlen(pokeMsg));
      
          if (!this->socket->waitForBytesWritten(SOCKET_OPERATION_TIMEOUT_MS))
          {
              qDebug() << socket->errorString();
              return false;
          }
      
          if (!this->socket->waitForReadyRead(SOCKET_OPERATION_TIMEOUT_MS))
          {
              qDebug() << this->socket->errorString();
              return false;
          }
      
          QByteArray serverReply = this->socket->readAll();
          QString replyString(serverReply.data());
      
          qDebug() << "Received:" << replyString;
          qDebug() << "Success";
          return true;
      }
      

      MainServer.cpp

      #include <QCoreApplication>
      #include <QtCore>
      
      #include "SimpleServer.h"
      
      
      int main(int argc, char *argv[])
      {
          QCoreApplication app(argc, argv);
      
          SimpleServer server;
          server.start("127.0.0.1", 9000);
      
          return app.exec();
      }
      

      SimpleServer.h

      #ifndef SIMPLESERVER_H
      #define SIMPLESERVER_H
      
      #include <QDebug>
      #include <QTcpServer>
      
      class SimpleServer : public QTcpServer
      {
          Q_OBJECT;
      
      public:
          SimpleServer(QObject *parent = nullptr);
      
          bool start(QString serverIP, qint16 serverPort);
      
      protected:
          void incomingConnection(qintptr socketDescriptor) override; \
      };
      
      #endif // SIMPLESERVER_H
      

      SimpleServer.cpp

      #include <QHostAddress>
      
      #include "SimpleServer.h"
      #include "ServerJobThread.h"
      
      
      SimpleServer::SimpleServer(QObject *parent)
          : QTcpServer(parent) {}
      
      
      bool SimpleServer::start(QString serverIP, qint16 serverPort)
      {
          qDebug() << "Awaiting for new connections "
                   << "IP" << serverIP
                   << "PORT" << serverPort;
      
          this->listen(QHostAddress(serverIP), serverPort);
          return true;
      }
      
      
      void SimpleServer::incomingConnection(qintptr socketDescriptor)
      {
          qDebug() << "New incoming connection";
      
          ServerJobThread *thread = new ServerJobThread(socketDescriptor, this);
          connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
          thread->start();
      }
      

      ServerJobThread.h

      #ifndef SERVERJOBTHREAD_H
      #define SERVERJOBTHREAD_H
      
      #include <QThread>
      #include <QTcpSocket>
      
      class ServerJobThread : public QThread
      {
          Q_OBJECT
      
      public:
          ServerJobThread(qintptr socketDescriptor, QObject *parent);
      
          void run() override;
      
      private:
          qintptr socketDescriptor;
      };
      
      #endif // SERVERJOBTHREAD_H
      

      ServerJobThread.cpp

      #include <QByteArray>
      #include <QTime>
      
      #include "ServerJobThread.h"
      
      #define SOCKET_OPERATION_TIMEOUT_MS 3000
      #define THREAD_MAX_RUNNING_TIME_S      5
      
      #define THREAD_ID this->currentThreadId()
      
      ServerJobThread::ServerJobThread(qintptr socketDescriptor, QObject *parent)
          : QThread(parent)
      {
          this->socketDescriptor = socketDescriptor;
      }
      
      
      void ServerJobThread::run()
      {
          bool workerThreadShouldRun = true;
          QTcpSocket tcpSocket;
      
          if (!tcpSocket.setSocketDescriptor(this->socketDescriptor))
          {
              qDebug() << THREAD_ID << "setSocketDescriptor fail";
              return;
          }
      
          QTime workerThreadTimeoutTime = QTime::currentTime().addSecs(THREAD_MAX_RUNNING_TIME_S);
          while (workerThreadShouldRun)
          {
              if (tcpSocket.bytesAvailable() == 0)
              {
                  tcpSocket.waitForReadyRead(SOCKET_OPERATION_TIMEOUT_MS);
              }
              else
              {
                  QByteArray buffer = tcpSocket.readAll();
                  if (buffer.size() > 0)
                  {
                      qDebug() << THREAD_ID
                               << "Received:" << QString(buffer.data());
      
                      qDebug() << THREAD_ID
                               << "Sending :" << QString("Hello Client");
      
                      tcpSocket.write("Hello Client");
                      tcpSocket.waitForBytesWritten(SOCKET_OPERATION_TIMEOUT_MS);
      
                      workerThreadShouldRun = false;
                  }
      
                  if (QTime::currentTime() > workerThreadTimeoutTime)
                  {
                      qDebug() << THREAD_ID
                               << "Thread max running time expired";
                      workerThreadShouldRun = false;
                  }
              }
          }
          qDebug() << THREAD_ID << "Thread finished";
      }
      

      CMakeLists.txt

      cmake_minimum_required(VERSION 3.14)
      
      project(Simple-TCP-Client-Server LANGUAGES CXX)
      
      set(CMAKE_AUTOUIC ON)
      set(CMAKE_AUTOMOC ON)
      set(CMAKE_AUTORCC ON)
      
      set(CMAKE_CXX_STANDARD 17)
      set(CMAKE_CXX_STANDARD_REQUIRED ON)
      
      find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core Network)
      find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS core Network)
      
      add_executable(Server
          ServerJobThread.h
          ServerJobThread.cpp
          SimpleServer.h
          SimpleServer.cpp
          MainServer.cpp
      )
      target_link_libraries(Server Qt6::Core Qt6::Network)
      
      add_executable(Client
          SimpleClient.h
          SimpleClient.cpp
          MainClient.cpp
      )
      target_link_libraries(Client Qt6::Core Qt6::Network)
      

      CLIENT STDOUT

      $ ./Client
      Connecting to "127.0.0.1" : 9000
      Connected
      Sending : "Hello Server"
      Received: "Hello Client"
      Success
      

      SERVER STDOUT

      $ ./Server
      Awaiting for new connections  IP "127.0.0.1" PORT 9000
      New incoming connection
      0x9a60 Received: "Hello Server"
      0x9a60 Sending : "Hello Client"
      0x9a60 Thread finished
      
      1 Reply Last reply
      0
      • D dmitttri

        Hi everyone!
        First of all, thanks a lot for all the great effort and support available on this forum.

        I am trying to write a very simple TCP client/server example, and I based my work on existing Qt examples: localfortuneclient and threadedfortuneserver.

        My approach is very simple (at this point):

        • start a listening server on the localhost address
        • on each incoming connection, start a dedicated worker thread, and pass provided socket descriptor (so worker thread can receive/send data)
        • right now it should just receive one client message (a string) and print it
        • start client which will connect to the server, and send one string message

        So far I got these results:

        • client starts, connects to the server and writes one string (to the QTcpSocket object), and write method seems to be fine (returns correct number of written bytes)
        • server runs, listen on incoming connections, once newconnection is established, starts a thread (which is supposed to receive some client data), but server socket read always returns zero, no data is being received

        I will gladly copy in all source code (it's very simple), but let me first try to just copy in server relevant code. My SimpleServer inherits QTcpServer and overrides icommingConnection method:

        void SimpleServer::incomingConnection(qintptr socketDescriptor)
        {
            qDebug() << "New incoming connection";
        
            ServerWorkerThread *thread = new ServerWorkerThread(socketDescriptor, this);
            connect(thread, &ServerWorkerThread::finished, thread, &ServerWorkerThread::deleteLater);
            thread->start();
        }
        

        ServerWorkingThread inherits QThread and overrides run method, which initialize a new QTcpSocket using the provided socketDescriptor, and then tries to read data. read always return 0, my thread max running time expires (5 seconds) and no data was received.

        void ServerWorkerThread::run()
        {
            bool workerThreadShouldRun = true;
            QTcpSocket tcpSocket;
        
            if (!tcpSocket.setSocketDescriptor(this->socketDescriptor))
            {
                qDebug() << THREAD_ID << "setSocketDescriptor fail";
                return;
            }
        
            qDebug() << THREAD_ID << "Socket info:" << tcpSocket.state() << tcpSocket.openMode();
            qDebug() << THREAD_ID << "Awaiting client message";
        
            QTime workerThreadTimeoutTime = QTime::currentTime().addSecs(THREAD_MAX_RUNNING_TIME_S);
            while (workerThreadShouldRun)
            {
                QByteArray buffer = tcpSocket.read(MAX_RECEIVE_BUFFER_SIZE);
                if (buffer.size() > 0)
                {
                    qDebug() << THREAD_ID 
                             << "Received client message:" << QString(buffer.data())
                             << buffer.size() << "bytes";
        
                    workerThreadShouldRun = false;
                }
                
                if (QTime::currentTime() > workerThreadTimeoutTime)
                {
                    qDebug() << THREAD_ID
                             << "Thread max running time expired";
                    workerThreadShouldRun = false;
                }
                this->msleep(100);
            }
            qDebug() << THREAD_ID << "Thread exit";
        }
        

        Obviously I am doing something wrong, and it would be great if someone can provide hints on why read method may fail, although client side seems to send data correctly.

        NOTE: Socket info shows that socket is connected and is in Read/Write mode.

        This is the client method to send data, where write is successful:

        bool SimpleClient::pokeServer (const char *pokeMsg)
        {
            if (!this->isConnected())
            {
                return false;
            }
        
            int bytesWritten = this->socket->write(pokeMsg);
            if (bytesWritten != strlen(pokeMsg))
            {
                qDebug() << "Socket write error" << strlen(pokeMsg) << bytesWritten;
                return false;
            }
            
            qDebug() << "Sent to server: " << pokeMsg;
            return true;
        }
        

        Thanks in advance!

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

        As always when a thread is used for an async Qt class - why do you need a thread at all?
        Apart from this you should use the worker thread approach and properly connect QTcpSocket::readyRead() to receive data instead blocking the event loop and the wondering why nothing happens.

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

        D 1 Reply Last reply
        1
        • Christian EhrlicherC Christian Ehrlicher

          As always when a thread is used for an async Qt class - why do you need a thread at all?
          Apart from this you should use the worker thread approach and properly connect QTcpSocket::readyRead() to receive data instead blocking the event loop and the wondering why nothing happens.

          D Offline
          D Offline
          dmitttri
          wrote on last edited by dmitttri
          #3

          @Christian-Ehrlicher said in QTcpServer won't receive client data on connected QTcpSocket:

          Hi Christian, thanks for your answer.

          As always when a thread is used for an async Qt class - why do you need a thread at all?

          Simply because there will be multiple clients, requesting longer jobs to be done in parallel by the server (remote project building). This is a very common server design decision.

          Apart from this you should use the worker thread approach and properly connect QTcpSocket::readyRead() to receive data instead blocking the event loop and the wondering why nothing happens.

          I have tried the approach with QTcpSocket::readyRead() and the outcome was the same. Connected slot never get called.

          When you say blocking the even loop, what do you exactly mean? tcpSocket.read will block until MAX_RECEIVE_BUFFER_SIZE is being received? I have tried to wait exactly number of bytes sent by the client, and it still won't receive anything. read always returns 0, and do not block, this is what I observed by testing the server side. Even if it blocks until requested number of bytes arrive, that's perfectly fine for my use case, I will just change the thread timeout approach.

          My example server code is based on the Qt official example threadedfortuneserver, with the only difference that Qt example just sends some data once client connects, and do not try to receive any data.

          I still don't understand your suggestions, are developers supposed to avoid QTcpSocket's read method, and using signals/slots is absolutely required?

          Thanks in advance!

          Christian EhrlicherC jeremy_kJ 2 Replies Last reply
          0
          • D dmitttri

            @Christian-Ehrlicher said in QTcpServer won't receive client data on connected QTcpSocket:

            Hi Christian, thanks for your answer.

            As always when a thread is used for an async Qt class - why do you need a thread at all?

            Simply because there will be multiple clients, requesting longer jobs to be done in parallel by the server (remote project building). This is a very common server design decision.

            Apart from this you should use the worker thread approach and properly connect QTcpSocket::readyRead() to receive data instead blocking the event loop and the wondering why nothing happens.

            I have tried the approach with QTcpSocket::readyRead() and the outcome was the same. Connected slot never get called.

            When you say blocking the even loop, what do you exactly mean? tcpSocket.read will block until MAX_RECEIVE_BUFFER_SIZE is being received? I have tried to wait exactly number of bytes sent by the client, and it still won't receive anything. read always returns 0, and do not block, this is what I observed by testing the server side. Even if it blocks until requested number of bytes arrive, that's perfectly fine for my use case, I will just change the thread timeout approach.

            My example server code is based on the Qt official example threadedfortuneserver, with the only difference that Qt example just sends some data once client connects, and do not try to receive any data.

            I still don't understand your suggestions, are developers supposed to avoid QTcpSocket's read method, and using signals/slots is absolutely required?

            Thanks in advance!

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

            @dmitttri said in QTcpServer won't receive client data on connected QTcpSocket:

            I have tried the approach with QTcpSocket::readyRead() and the outcome was the same. Connected slot never get called.

            Pleas show your code. Let the QThread run an event loop so Qt can properly receive the data from the os.

            I still don't understand your suggestions, are developers supposed to avoid QTcpSocket's read method, and using signals/slots is absolutely required?

            I never said you should not use read() (how else would you read data from the socket?) but you have to give Qt a chance to process the data and retrieve it from the os.

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

            D 3 Replies Last reply
            1
            • D dmitttri

              @Christian-Ehrlicher said in QTcpServer won't receive client data on connected QTcpSocket:

              Hi Christian, thanks for your answer.

              As always when a thread is used for an async Qt class - why do you need a thread at all?

              Simply because there will be multiple clients, requesting longer jobs to be done in parallel by the server (remote project building). This is a very common server design decision.

              Apart from this you should use the worker thread approach and properly connect QTcpSocket::readyRead() to receive data instead blocking the event loop and the wondering why nothing happens.

              I have tried the approach with QTcpSocket::readyRead() and the outcome was the same. Connected slot never get called.

              When you say blocking the even loop, what do you exactly mean? tcpSocket.read will block until MAX_RECEIVE_BUFFER_SIZE is being received? I have tried to wait exactly number of bytes sent by the client, and it still won't receive anything. read always returns 0, and do not block, this is what I observed by testing the server side. Even if it blocks until requested number of bytes arrive, that's perfectly fine for my use case, I will just change the thread timeout approach.

              My example server code is based on the Qt official example threadedfortuneserver, with the only difference that Qt example just sends some data once client connects, and do not try to receive any data.

              I still don't understand your suggestions, are developers supposed to avoid QTcpSocket's read method, and using signals/slots is absolutely required?

              Thanks in advance!

              jeremy_kJ Offline
              jeremy_kJ Offline
              jeremy_k
              wrote on last edited by
              #5

              @dmitttri said in QTcpServer won't receive client data on connected QTcpSocket:

              @Christian-Ehrlicher said in QTcpServer won't receive client data on connected QTcpSocket:

              Hi Christian, thanks for your answer.

              As always when a thread is used for an async Qt class - why do you need a thread at all?

              Simply because there will be multiple clients, requesting longer jobs to be done in parallel by the server (remote project building). This is a very common server design decision.

              Is the build (dependency walking, compilation, linking, etc) performed in process, or is it invoking external programs?

              Asking a question about code? http://eel.is/iso-c++/testcase/

              D 1 Reply Last reply
              0
              • Christian EhrlicherC Christian Ehrlicher

                @dmitttri said in QTcpServer won't receive client data on connected QTcpSocket:

                I have tried the approach with QTcpSocket::readyRead() and the outcome was the same. Connected slot never get called.

                Pleas show your code. Let the QThread run an event loop so Qt can properly receive the data from the os.

                I still don't understand your suggestions, are developers supposed to avoid QTcpSocket's read method, and using signals/slots is absolutely required?

                I never said you should not use read() (how else would you read data from the socket?) but you have to give Qt a chance to process the data and retrieve it from the os.

                D Offline
                D Offline
                dmitttri
                wrote on last edited by
                #6

                @Christian-Ehrlicher said in QTcpServer won't receive client data on connected QTcpSocket:

                Thanks for your patience and assistance.

                Pleas show your code. Let the QThread run an event loop so Qt can properly receive the data from the os.

                Yes, seems it's better to copy the complete code, most likely there will be obvious issues with managing QThread. Seems I don't get the part with running QThread in an event loop. My (still shallow) understanding of Qt event processing is that the thread execution can't directly affect the main event loop (in terms of blocking it), which should execute in the main process.

                SERVER SIDE

                MainServer.cpp

                #include <QCoreApplication>
                #include <QtCore>
                
                #include "SimpleServer.h"
                
                
                int main(int argc, char *argv[])
                {
                    QCoreApplication app(argc, argv);
                
                    SimpleServer server;
                    server.start("127.0.0.1", 9000);
                
                    return app.exec();
                }
                

                SimpleServer.h

                #ifndef SIMPLESERVER_H
                #define SIMPLESERVER_H
                
                #include <QDebug>
                #include <QTcpServer>
                
                class SimpleServer : public QTcpServer
                {
                    Q_OBJECT;
                
                public:
                    SimpleServer(QObject *parent = nullptr);
                
                    bool start(QString serverIP, qint16 serverPort);
                
                protected:
                    void incomingConnection(qintptr socketDescriptor) override; \
                };
                
                #endif // SIMPLESERVER_H
                

                SimpleServer.cpp

                #include <QTcpSocket>
                #include <QHostAddress>
                
                #include "SimpleServer.h"
                #include "ServerJobThread.h"
                
                
                SimpleServer::SimpleServer(QObject *parent)
                    : QTcpServer(parent) {}
                
                
                bool SimpleServer::start(QString serverIP, qint16 serverPort)
                {
                    qDebug() << "Awaiting for new connections "
                             << "IP" << serverIP
                             << "PORT" << serverPort;
                
                    this->listen(QHostAddress(serverIP), serverPort);
                    return true;
                }
                
                
                void SimpleServer::incomingConnection(qintptr socketDescriptor)
                {
                    qDebug() << "New incoming connection";
                
                    ServerJobThread *thread = new ServerJobThread(socketDescriptor, this);
                    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
                    thread->start();
                }
                

                ServerJobThread.h

                #ifndef SERVERJOBTHREAD_H
                #define SERVERJOBTHREAD_H
                
                #include <QThread>
                #include <QTcpSocket>
                
                class ServerJobThread : public QThread
                {
                    Q_OBJECT
                
                public:
                    ServerJobThread(qintptr socketDescriptor, QObject *parent);
                
                    void run() override;
                
                private:
                    qintptr socketDescriptor;
                };
                
                #endif // SERVERJOBTHREAD_H
                

                ServerJobThread.cpp

                #include <QByteArray>
                #include <QTime>
                
                #include "ServerJobThread.h"
                
                #define THREAD_MAX_RUNNING_TIME_S 5
                #define THREAD_ID this->currentThreadId()
                
                #define MAX_RECEIVE_BUFFER_SIZE  1024
                
                ServerJobThread::ServerJobThread(qintptr socketDescriptor, QObject *parent)
                    : QThread(parent)
                {
                    this->socketDescriptor = socketDescriptor;
                }
                
                
                void ServerJobThread::run()
                {
                    bool workerThreadShouldRun = true;
                    QTcpSocket tcpSocket;
                
                    if (!tcpSocket.setSocketDescriptor(this->socketDescriptor))
                    {
                        qDebug() << THREAD_ID << "setSocketDescriptor fail";
                        return;
                    }
                
                    qDebug() << THREAD_ID << "Socket info:" << tcpSocket.state() << tcpSocket.openMode();
                    qDebug() << THREAD_ID << "Awaiting client message";
                
                    QTime workerThreadTimeoutTime = QTime::currentTime().addSecs(THREAD_MAX_RUNNING_TIME_S);
                    while (workerThreadShouldRun)
                    {
                        QByteArray buffer = tcpSocket.read(MAX_RECEIVE_BUFFER_SIZE);
                        if (buffer.size() > 0)
                        {
                            qDebug() << THREAD_ID 
                                     << "Received client message:" << QString(buffer.data())
                                     << buffer.size() << "bytes";
                
                            workerThreadShouldRun = false;
                        }
                        
                        if (QTime::currentTime() > workerThreadTimeoutTime)
                        {
                            qDebug() << THREAD_ID
                                     << "Thread max running time expired";
                            workerThreadShouldRun = false;
                        }
                        this->msleep(100);
                    }
                    qDebug() << THREAD_ID << "Thread exit";
                }
                

                CLIENT SIDE

                MainClient.cpp

                #include <QThread>
                #include <QDebug>
                #include "SimpleClient.h"
                
                int main(int argc, char *argv[])
                {
                    SimpleClient client;
                
                    if(!client.connectToServer("127.0.0.1", 9000))
                    {
                        return -1;
                    }
                
                    client.pokeServer("POKE");
                
                    QThread::sleep(2);
                    client.disconnectFromServer();
                
                    qDebug() << "Client exit";
                    return 0;
                }
                

                SimpleClient.h

                #ifndef SIMPLECLIENT_H
                #define SIMPLECLIENT_H
                
                #include <QTcpSocket>
                #include <QAbstractSocket>
                
                #define SOCKET_OPERATION_TIMEOUT_MS 3000
                
                class SimpleClient
                {
                public:
                    SimpleClient();
                
                    bool connectToServer(QString serverIP, qint16 serverPort);
                    bool isConnected();
                    void disconnectFromServer();
                
                    bool pokeServer(const char *pokeMsg);
                
                private:
                    QTcpSocket *socket = nullptr;
                };
                
                #endif // SIMPLECLIENT_H
                

                SimpleClient.cpp

                #include <QByteArray>
                #include "SimpleClient.h"
                
                
                SimpleClient::SimpleClient()
                {
                    this->socket = new QTcpSocket;
                }
                
                bool SimpleClient::connectToServer(QString serverIP, qint16 serverPort)
                {
                    if (!this->socket)
                    {
                        qDebug() << "Error, socket not initialized.";
                        return false;
                    }
                    qDebug() << "Connecting to" << serverIP << ":" << serverPort;
                
                    socket->connectToHost(QHostAddress(serverIP), serverPort);
                
                    if (!socket->waitForConnected(SOCKET_OPERATION_TIMEOUT_MS))
                    {
                        qDebug() << "Error, connection timeout, server not accessible.";
                        return false;
                    }
                
                    qDebug() << "Connected";
                    return true;
                }
                
                bool SimpleClient::isConnected()
                {
                    return (this->socket->state() == QAbstractSocket::ConnectedState);
                }
                
                void SimpleClient::disconnectFromServer()
                {
                    if (this->socket)
                    {
                        if (this->isConnected())
                        {
                            this->socket->disconnectFromHost();
                        }
                    }
                }
                
                bool SimpleClient::pokeServer (const char *pokeMsg)
                {
                    if (!this->isConnected())
                    {
                        return false;
                    }
                
                    int bytesWritten = this->socket->write(pokeMsg);
                    if (bytesWritten != strlen(pokeMsg))
                    {
                        qDebug() << "Socket write error" << strlen(pokeMsg) << bytesWritten;
                        return false;
                    }
                    
                    qDebug() << "Sent to server: " << pokeMsg;
                    return true;
                }
                

                SERVER STDOUT

                $ ./Server
                Awaiting for new connections  IP "127.0.0.1" PORT 9000
                New incoming connection
                0x4b58 Socket info: QAbstractSocket::ConnectedState OpenMode( "ReadOnly|WriteOnly" )
                0x4b58 Awaiting client message
                0x4b58 Thread max running time expired
                0x4b58 Thread exit
                

                CLIENT STDOUT

                $ ./Client
                Connecting to "127.0.0.1" : 9000
                Connected
                Sent to server:  POKE
                Client exit
                
                1 Reply Last reply
                0
                • jeremy_kJ jeremy_k

                  @dmitttri said in QTcpServer won't receive client data on connected QTcpSocket:

                  @Christian-Ehrlicher said in QTcpServer won't receive client data on connected QTcpSocket:

                  Hi Christian, thanks for your answer.

                  As always when a thread is used for an async Qt class - why do you need a thread at all?

                  Simply because there will be multiple clients, requesting longer jobs to be done in parallel by the server (remote project building). This is a very common server design decision.

                  Is the build (dependency walking, compilation, linking, etc) performed in process, or is it invoking external programs?

                  D Offline
                  D Offline
                  dmitttri
                  wrote on last edited by
                  #7

                  @jeremy_k said in QTcpServer won't receive client data on connected QTcpSocket:

                  @dmitttri said in QTcpServer won't receive client data on connected QTcpSocket:

                  @Christian-Ehrlicher said in QTcpServer won't receive client data on connected QTcpSocket:

                  Hi Christian, thanks for your answer.

                  As always when a thread is used for an async Qt class - why do you need a thread at all?

                  Simply because there will be multiple clients, requesting longer jobs to be done in parallel by the server (remote project building). This is a very common server design decision.

                  Hi Jeremy!

                  Is the build (dependency walking, compilation, linking, etc) performed in process, or is it invoking external programs?

                  Basically it will be a multi step job:

                  • client send a request for a remote job
                  • client uploads project archive to the server
                  • server executes external build script
                  • server packs building results (and logs) into another archive and sends it back to the client
                  jeremy_kJ 1 Reply Last reply
                  0
                  • D dmitttri

                    @jeremy_k said in QTcpServer won't receive client data on connected QTcpSocket:

                    @dmitttri said in QTcpServer won't receive client data on connected QTcpSocket:

                    @Christian-Ehrlicher said in QTcpServer won't receive client data on connected QTcpSocket:

                    Hi Christian, thanks for your answer.

                    As always when a thread is used for an async Qt class - why do you need a thread at all?

                    Simply because there will be multiple clients, requesting longer jobs to be done in parallel by the server (remote project building). This is a very common server design decision.

                    Hi Jeremy!

                    Is the build (dependency walking, compilation, linking, etc) performed in process, or is it invoking external programs?

                    Basically it will be a multi step job:

                    • client send a request for a remote job
                    • client uploads project archive to the server
                    • server executes external build script
                    • server packs building results (and logs) into another archive and sends it back to the client
                    jeremy_kJ Offline
                    jeremy_kJ Offline
                    jeremy_k
                    wrote on last edited by
                    #8

                    @dmitttri said in QTcpServer won't receive client data on connected QTcpSocket:

                    @jeremy_k said in QTcpServer won't receive client data on connected QTcpSocket:

                    @dmitttri said in QTcpServer won't receive client data on connected QTcpSocket:

                    @Christian-Ehrlicher said in QTcpServer won't receive client data on connected QTcpSocket:

                    Hi Christian, thanks for your answer.

                    As always when a thread is used for an async Qt class - why do you need a thread at all?

                    Simply because there will be multiple clients, requesting longer jobs to be done in parallel by the server (remote project building). This is a very common server design decision.

                    Hi Jeremy!

                    Is the build (dependency walking, compilation, linking, etc) performed in process, or is it invoking external programs?

                    Basically it will be a multi step job:

                    • client send a request for a remote job
                    • client uploads project archive to the server
                    • server executes external build script
                    • server packs building results (and logs) into another archive and sends it back to the client

                    This sounds reasonable for a single thread handling multiple clients. Doing so will reduce the code complexity, and may result in better performance than running a thread per client. If there are ever so many (N) clients that a single thread can't handle them, a second thread can be added to handle another N clients. It may be easier to instead execute an additional instance of the server.

                    • Use the QTcpServer::newConnection() signal rather than subclassing QTcpServer.
                    • If the uploaded project is really large, read data in chunks in order to reduce latency for other clients. Chances are good that the network stack is going to cause this to happen anyway.
                    • Use QProcess to execute the external build script. Connect to the appropriate signals to get output and exit status.
                    • Do the same for the archiving step if it uses an external program. If it is library or application code, use a QRunnable.

                    Asking a question about code? http://eel.is/iso-c++/testcase/

                    D 1 Reply Last reply
                    0
                    • jeremy_kJ jeremy_k

                      @dmitttri said in QTcpServer won't receive client data on connected QTcpSocket:

                      @jeremy_k said in QTcpServer won't receive client data on connected QTcpSocket:

                      @dmitttri said in QTcpServer won't receive client data on connected QTcpSocket:

                      @Christian-Ehrlicher said in QTcpServer won't receive client data on connected QTcpSocket:

                      Hi Christian, thanks for your answer.

                      As always when a thread is used for an async Qt class - why do you need a thread at all?

                      Simply because there will be multiple clients, requesting longer jobs to be done in parallel by the server (remote project building). This is a very common server design decision.

                      Hi Jeremy!

                      Is the build (dependency walking, compilation, linking, etc) performed in process, or is it invoking external programs?

                      Basically it will be a multi step job:

                      • client send a request for a remote job
                      • client uploads project archive to the server
                      • server executes external build script
                      • server packs building results (and logs) into another archive and sends it back to the client

                      This sounds reasonable for a single thread handling multiple clients. Doing so will reduce the code complexity, and may result in better performance than running a thread per client. If there are ever so many (N) clients that a single thread can't handle them, a second thread can be added to handle another N clients. It may be easier to instead execute an additional instance of the server.

                      • Use the QTcpServer::newConnection() signal rather than subclassing QTcpServer.
                      • If the uploaded project is really large, read data in chunks in order to reduce latency for other clients. Chances are good that the network stack is going to cause this to happen anyway.
                      • Use QProcess to execute the external build script. Connect to the appropriate signals to get output and exit status.
                      • Do the same for the archiving step if it uses an external program. If it is library or application code, use a QRunnable.
                      D Offline
                      D Offline
                      dmitttri
                      wrote on last edited by
                      #9

                      @jeremy_k said in QTcpServer won't receive client data on connected QTcpSocket:

                      This sounds reasonable for a single thread handling multiple clients. Doing so will reduce the code complexity, and may result in better performance than running a thread per client. If there are ever so many (N) clients that a single thread can't handle them, a second thread can be added to handle another N clients. It may be easier to instead execute an additional instance of the server.

                      Thanks for the suggestion. This is a bit off-topic. The decision of multiple threads vs single thread is mostly like a decision about scheduler policy fair scheduling vs round robin. The server I am working on won't just do remote building, there will be other jobs of variable duration. Handing in one thread may impose delays for shorter jobs in case of a pending longer job. The other question may be what happens if one job get stuck? Will a single thread server get stuck too, preventing other jobs being executed? For example, while uploading a file from a connected client, if client gets suddenly disconnected, or ends up in long delays with reaching server, what server can do about it and make other jobs running?

                      There are pros and cons for the threaded approach, and I settled down with the multiple threads, for now.

                      jeremy_kJ 1 Reply Last reply
                      0
                      • D dmitttri

                        @jeremy_k said in QTcpServer won't receive client data on connected QTcpSocket:

                        This sounds reasonable for a single thread handling multiple clients. Doing so will reduce the code complexity, and may result in better performance than running a thread per client. If there are ever so many (N) clients that a single thread can't handle them, a second thread can be added to handle another N clients. It may be easier to instead execute an additional instance of the server.

                        Thanks for the suggestion. This is a bit off-topic. The decision of multiple threads vs single thread is mostly like a decision about scheduler policy fair scheduling vs round robin. The server I am working on won't just do remote building, there will be other jobs of variable duration. Handing in one thread may impose delays for shorter jobs in case of a pending longer job. The other question may be what happens if one job get stuck? Will a single thread server get stuck too, preventing other jobs being executed? For example, while uploading a file from a connected client, if client gets suddenly disconnected, or ends up in long delays with reaching server, what server can do about it and make other jobs running?

                        There are pros and cons for the threaded approach, and I settled down with the multiple threads, for now.

                        jeremy_kJ Offline
                        jeremy_kJ Offline
                        jeremy_k
                        wrote on last edited by
                        #10

                        @dmitttri said in QTcpServer won't receive client data on connected QTcpSocket:

                        @jeremy_k said in QTcpServer won't receive client data on connected QTcpSocket:

                        This sounds reasonable for a single thread handling multiple clients. Doing so will reduce the code complexity, and may result in better performance than running a thread per client. If there are ever so many (N) clients that a single thread can't handle them, a second thread can be added to handle another N clients. It may be easier to instead execute an additional instance of the server.

                        Thanks for the suggestion. This is a bit off-topic. The decision of multiple threads vs single thread is mostly like a decision about scheduler policy fair scheduling vs round robin. The server I am working on won't just do remote building, there will be other jobs of variable duration. Handing in one thread may impose delays for shorter jobs in case of a pending longer job. The other question may be what happens if one job get stuck? Will a single thread server get stuck too, preventing other jobs being executed? For example, while uploading a file from a connected client, if client gets suddenly disconnected, or ends up in long delays with reaching server, what server can do about it and make other jobs running?

                        I'll preface this by stating that this sounds like a common misunderstanding for programmers who are unfamiliar with asynchronous or non-blocking I/O.

                        Presuming that all of these jobs are running in external processes: The ability for any job to impede another really comes down to the amount of output the jobs generate and rate at which jobs arrive and complete. There should be no blocking waits. Jobs and clients will be scheduled for compute time as they generate data.

                        If a job is "stuck" in that the external process stops responding, it also stops generating data for the server to process. If the client stops mid-upload, the server is likewise not impeded. The interim overhead on the server is the space to buffer a partial upload (presumably flushed to disk anyway) or output, and the open connection. Neither changes with 1 versus many threads.

                        There are pros and cons for the threaded approach, and I settled down with the multiple threads, for now.

                        Sure, it's your program. You are hopefully now aware that adding threads adds complexity with limited prospects for improved performance in the described use case.

                        Asking a question about code? http://eel.is/iso-c++/testcase/

                        D 1 Reply Last reply
                        0
                        • jeremy_kJ jeremy_k

                          @dmitttri said in QTcpServer won't receive client data on connected QTcpSocket:

                          @jeremy_k said in QTcpServer won't receive client data on connected QTcpSocket:

                          This sounds reasonable for a single thread handling multiple clients. Doing so will reduce the code complexity, and may result in better performance than running a thread per client. If there are ever so many (N) clients that a single thread can't handle them, a second thread can be added to handle another N clients. It may be easier to instead execute an additional instance of the server.

                          Thanks for the suggestion. This is a bit off-topic. The decision of multiple threads vs single thread is mostly like a decision about scheduler policy fair scheduling vs round robin. The server I am working on won't just do remote building, there will be other jobs of variable duration. Handing in one thread may impose delays for shorter jobs in case of a pending longer job. The other question may be what happens if one job get stuck? Will a single thread server get stuck too, preventing other jobs being executed? For example, while uploading a file from a connected client, if client gets suddenly disconnected, or ends up in long delays with reaching server, what server can do about it and make other jobs running?

                          I'll preface this by stating that this sounds like a common misunderstanding for programmers who are unfamiliar with asynchronous or non-blocking I/O.

                          Presuming that all of these jobs are running in external processes: The ability for any job to impede another really comes down to the amount of output the jobs generate and rate at which jobs arrive and complete. There should be no blocking waits. Jobs and clients will be scheduled for compute time as they generate data.

                          If a job is "stuck" in that the external process stops responding, it also stops generating data for the server to process. If the client stops mid-upload, the server is likewise not impeded. The interim overhead on the server is the space to buffer a partial upload (presumably flushed to disk anyway) or output, and the open connection. Neither changes with 1 versus many threads.

                          There are pros and cons for the threaded approach, and I settled down with the multiple threads, for now.

                          Sure, it's your program. You are hopefully now aware that adding threads adds complexity with limited prospects for improved performance in the described use case.

                          D Offline
                          D Offline
                          dmitttri
                          wrote on last edited by dmitttri
                          #11

                          @jeremy_k said in QTcpServer won't receive client data on connected QTcpSocket:

                          Sure, it's your program. You are hopefully now aware that adding threads adds complexity with limited prospects for improved performance in the described use case.

                          Sure Jeremy, have no worries about my design decisions, I'll be perfectly fine even if I may be wrong form time to time.

                          I would prefer to get back to the original issue.

                          1 Reply Last reply
                          0
                          • Christian EhrlicherC Christian Ehrlicher

                            @dmitttri said in QTcpServer won't receive client data on connected QTcpSocket:

                            I have tried the approach with QTcpSocket::readyRead() and the outcome was the same. Connected slot never get called.

                            Pleas show your code. Let the QThread run an event loop so Qt can properly receive the data from the os.

                            I still don't understand your suggestions, are developers supposed to avoid QTcpSocket's read method, and using signals/slots is absolutely required?

                            I never said you should not use read() (how else would you read data from the socket?) but you have to give Qt a chance to process the data and retrieve it from the os.

                            D Offline
                            D Offline
                            dmitttri
                            wrote on last edited by dmitttri
                            #12

                            @Christian-Ehrlicher said in QTcpServer won't receive client data on connected QTcpSocket:

                            Pleas show your code. Let the QThread run an event loop so Qt can properly receive the data from the os.

                            Hm, now I am starting to understand your point. By default QThread run method will just perform exec(), which is what you refer to running Qt event loop in a thread. This is why QThread doc page offers Worker/Controller example.

                            This may be actually what's wrong with my code above. Inheriting QThread and overriding run actually works only if we'll do something unrelated with Qt event loop (like processing an image form a RAM located buffer).

                            Let me try to re implement my simple example and use Worker approach.

                            1 Reply Last reply
                            0
                            • Christian EhrlicherC Christian Ehrlicher

                              @dmitttri said in QTcpServer won't receive client data on connected QTcpSocket:

                              I have tried the approach with QTcpSocket::readyRead() and the outcome was the same. Connected slot never get called.

                              Pleas show your code. Let the QThread run an event loop so Qt can properly receive the data from the os.

                              I still don't understand your suggestions, are developers supposed to avoid QTcpSocket's read method, and using signals/slots is absolutely required?

                              I never said you should not use read() (how else would you read data from the socket?) but you have to give Qt a chance to process the data and retrieve it from the os.

                              D Offline
                              D Offline
                              dmitttri
                              wrote on last edited by dmitttri
                              #13

                              @Christian-Ehrlicher said in QTcpServer won't receive client data on connected QTcpSocket:

                              Pleas show your code. Let the QThread run an event loop so Qt can properly receive the data from the os.

                              Ok, now I tried approach with worker object, following the documentation link you kindly provided. Result is the same, server side simply don't receive any data on the connected socket.

                              @Christian-Ehrlicher Can you check the following code in which QThread runs an event loop?

                              SERVER SIDE

                              MainServer.cpp

                              #include <QCoreApplication>
                              #include <QtCore>
                              
                              #include "SimpleServer.h"
                              
                              
                              int main(int argc, char *argv[])
                              {
                                  QCoreApplication app(argc, argv);
                              
                                  SimpleServer server;
                                  server.start("127.0.0.1", 9000);
                              
                                  return app.exec();
                              }
                              

                              SimpleServer.h

                              #ifndef SIMPLESERVER_H
                              #define SIMPLESERVER_H
                              
                              #include <QDebug>
                              #include <QTcpServer>
                              
                              class SimpleServer : public QTcpServer
                              {
                                  Q_OBJECT;
                              
                              public:
                                  SimpleServer(QObject *parent = nullptr);
                              
                                  bool start(QString serverIP, qint16 serverPort);
                              
                              protected:
                                  void incomingConnection(qintptr socketDescriptor) override; \
                              };
                              
                              #endif // SIMPLESERVER_H
                              

                              SimpleServer.cpp

                              #include <QTcpSocket>
                              #include <QHostAddress>
                              
                              #include "SimpleServer.h"
                              #include "ServerWorkerThread.h"
                              
                              
                              SimpleServer::SimpleServer(QObject *parent)
                                  : QTcpServer(parent) {}
                              
                              
                              bool SimpleServer::start(QString serverIP, qint16 serverPort)
                              {
                                  qDebug() << "Awaiting for new connections "
                                           << "IP" << serverIP
                                           << "PORT" << serverPort;
                              
                                  this->listen(QHostAddress(serverIP), serverPort);
                                  return true;
                              }
                              
                              void SimpleServer::incomingConnection(qintptr socketDescriptor)
                              {
                                  qDebug() << "New incoming connection";
                              
                                  ServerWorkerThread *workerThread = new ServerWorkerThread();
                                  workerThread->start(socketDescriptor);
                              }
                              

                              ServerWorkerThread.h

                              #ifndef SERVERWORKERTHREAD_H
                              #define SERVERWORKERTHREAD_H
                              
                              #include <QThread>
                              #include <QTcpSocket>
                              
                              class Worker : public QObject
                              {
                                  Q_OBJECT
                              
                              public slots:
                                  void doWork(qintptr socketDescriptor);
                              
                              signals:
                                  void resultReady();
                              };
                              
                              class ServerWorkerThread : public QObject
                              {
                                  Q_OBJECT
                                  QThread workerThread;
                              public:
                                  ServerWorkerThread()
                                  {
                                      Worker *worker = new Worker;
                                      worker->moveToThread(&workerThread);
                                      connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
                                      connect(this, &ServerWorkerThread::operate, worker, &Worker::doWork);
                                      connect(worker, &Worker::resultReady, this, &ServerWorkerThread::handleResults);
                                      workerThread.start();
                                  }
                                  ~ServerWorkerThread()
                                  {
                                      workerThread.quit();
                                      workerThread.wait();
                                  }
                              
                                  void start(qintptr socketDecriptor)
                                  {
                                      emit this->operate(socketDecriptor);
                                  }
                              
                              public slots:
                                  void handleResults();
                              signals:
                                  void operate(qintptr socketDescriptor);
                              };
                              
                              #endif // SERVERWORKERTHREAD_H
                              

                              ServerWorkerThread.cpp

                              #include <QByteArray>
                              #include <QTime>
                              
                              #include "ServerWorkerThread.h"
                              
                              #define WORKER_THREAD_MAX_RUNNING_TIME_S 5
                              
                              
                              void Worker::doWork(qintptr socketDescriptor)
                              {
                                  bool workerThreadShouldRun = true;
                                  QTcpSocket tcpSocket;
                              
                                  if (!tcpSocket.setSocketDescriptor(socketDescriptor))
                                  {
                                      qDebug() << "setSocketDescriptor fail";
                                      return;
                                  }
                              
                                  qDebug() << "Socket info:" << tcpSocket.state() << tcpSocket.openMode();
                                  qDebug() << "Awaiting client message";
                              
                                  QTime workerThreadTimeoutTime = QTime::currentTime().addSecs(WORKER_THREAD_MAX_RUNNING_TIME_S);
                                  while (workerThreadShouldRun)
                                  {
                                      qint64 bytesAvailable = tcpSocket.bytesAvailable();
                                      if(bytesAvailable > 0)
                                      {
                                          qDebug() << "Received bytes" << bytesAvailable;
                              
                                          QByteArray buffer = tcpSocket.readAll();
                                          if (buffer.size() > 0)
                                          {
                                              qDebug() << "Received client message:" << QString(buffer.data())
                                                       << buffer.size() << "bytes";
                              
                                              workerThreadShouldRun = false;
                                          }
                                      }
                                      
                                      if (QTime::currentTime() > workerThreadTimeoutTime)
                                      {
                                          qDebug() << "Worker max running time expired";
                                          workerThreadShouldRun = false;
                                      }
                                      QThread::msleep(100);
                                  }
                                  qDebug() << "Worker exit";
                                  emit this->resultReady();
                              }
                              
                              void ServerWorkerThread::handleResults()
                              {
                              }
                              

                              Client side remains the same..

                              SERVER STDOUT

                              $ ./Server
                              Awaiting for new connections  IP "127.0.0.1" PORT 9000
                              New incoming connection
                              Socket info: QAbstractSocket::ConnectedState OpenMode( "ReadOnly|WriteOnly" )
                              Awaiting client message
                              Worker max running time expired
                              Worker exit
                              

                              CLIENT STDOUT

                              $ ./Client
                              Connecting to "127.0.0.1" : 9000
                              Connected
                              Sent to server:  POKE
                              Client exit
                              
                              jsulmJ 1 Reply Last reply
                              0
                              • D dmitttri

                                @Christian-Ehrlicher said in QTcpServer won't receive client data on connected QTcpSocket:

                                Pleas show your code. Let the QThread run an event loop so Qt can properly receive the data from the os.

                                Ok, now I tried approach with worker object, following the documentation link you kindly provided. Result is the same, server side simply don't receive any data on the connected socket.

                                @Christian-Ehrlicher Can you check the following code in which QThread runs an event loop?

                                SERVER SIDE

                                MainServer.cpp

                                #include <QCoreApplication>
                                #include <QtCore>
                                
                                #include "SimpleServer.h"
                                
                                
                                int main(int argc, char *argv[])
                                {
                                    QCoreApplication app(argc, argv);
                                
                                    SimpleServer server;
                                    server.start("127.0.0.1", 9000);
                                
                                    return app.exec();
                                }
                                

                                SimpleServer.h

                                #ifndef SIMPLESERVER_H
                                #define SIMPLESERVER_H
                                
                                #include <QDebug>
                                #include <QTcpServer>
                                
                                class SimpleServer : public QTcpServer
                                {
                                    Q_OBJECT;
                                
                                public:
                                    SimpleServer(QObject *parent = nullptr);
                                
                                    bool start(QString serverIP, qint16 serverPort);
                                
                                protected:
                                    void incomingConnection(qintptr socketDescriptor) override; \
                                };
                                
                                #endif // SIMPLESERVER_H
                                

                                SimpleServer.cpp

                                #include <QTcpSocket>
                                #include <QHostAddress>
                                
                                #include "SimpleServer.h"
                                #include "ServerWorkerThread.h"
                                
                                
                                SimpleServer::SimpleServer(QObject *parent)
                                    : QTcpServer(parent) {}
                                
                                
                                bool SimpleServer::start(QString serverIP, qint16 serverPort)
                                {
                                    qDebug() << "Awaiting for new connections "
                                             << "IP" << serverIP
                                             << "PORT" << serverPort;
                                
                                    this->listen(QHostAddress(serverIP), serverPort);
                                    return true;
                                }
                                
                                void SimpleServer::incomingConnection(qintptr socketDescriptor)
                                {
                                    qDebug() << "New incoming connection";
                                
                                    ServerWorkerThread *workerThread = new ServerWorkerThread();
                                    workerThread->start(socketDescriptor);
                                }
                                

                                ServerWorkerThread.h

                                #ifndef SERVERWORKERTHREAD_H
                                #define SERVERWORKERTHREAD_H
                                
                                #include <QThread>
                                #include <QTcpSocket>
                                
                                class Worker : public QObject
                                {
                                    Q_OBJECT
                                
                                public slots:
                                    void doWork(qintptr socketDescriptor);
                                
                                signals:
                                    void resultReady();
                                };
                                
                                class ServerWorkerThread : public QObject
                                {
                                    Q_OBJECT
                                    QThread workerThread;
                                public:
                                    ServerWorkerThread()
                                    {
                                        Worker *worker = new Worker;
                                        worker->moveToThread(&workerThread);
                                        connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
                                        connect(this, &ServerWorkerThread::operate, worker, &Worker::doWork);
                                        connect(worker, &Worker::resultReady, this, &ServerWorkerThread::handleResults);
                                        workerThread.start();
                                    }
                                    ~ServerWorkerThread()
                                    {
                                        workerThread.quit();
                                        workerThread.wait();
                                    }
                                
                                    void start(qintptr socketDecriptor)
                                    {
                                        emit this->operate(socketDecriptor);
                                    }
                                
                                public slots:
                                    void handleResults();
                                signals:
                                    void operate(qintptr socketDescriptor);
                                };
                                
                                #endif // SERVERWORKERTHREAD_H
                                

                                ServerWorkerThread.cpp

                                #include <QByteArray>
                                #include <QTime>
                                
                                #include "ServerWorkerThread.h"
                                
                                #define WORKER_THREAD_MAX_RUNNING_TIME_S 5
                                
                                
                                void Worker::doWork(qintptr socketDescriptor)
                                {
                                    bool workerThreadShouldRun = true;
                                    QTcpSocket tcpSocket;
                                
                                    if (!tcpSocket.setSocketDescriptor(socketDescriptor))
                                    {
                                        qDebug() << "setSocketDescriptor fail";
                                        return;
                                    }
                                
                                    qDebug() << "Socket info:" << tcpSocket.state() << tcpSocket.openMode();
                                    qDebug() << "Awaiting client message";
                                
                                    QTime workerThreadTimeoutTime = QTime::currentTime().addSecs(WORKER_THREAD_MAX_RUNNING_TIME_S);
                                    while (workerThreadShouldRun)
                                    {
                                        qint64 bytesAvailable = tcpSocket.bytesAvailable();
                                        if(bytesAvailable > 0)
                                        {
                                            qDebug() << "Received bytes" << bytesAvailable;
                                
                                            QByteArray buffer = tcpSocket.readAll();
                                            if (buffer.size() > 0)
                                            {
                                                qDebug() << "Received client message:" << QString(buffer.data())
                                                         << buffer.size() << "bytes";
                                
                                                workerThreadShouldRun = false;
                                            }
                                        }
                                        
                                        if (QTime::currentTime() > workerThreadTimeoutTime)
                                        {
                                            qDebug() << "Worker max running time expired";
                                            workerThreadShouldRun = false;
                                        }
                                        QThread::msleep(100);
                                    }
                                    qDebug() << "Worker exit";
                                    emit this->resultReady();
                                }
                                
                                void ServerWorkerThread::handleResults()
                                {
                                }
                                

                                Client side remains the same..

                                SERVER STDOUT

                                $ ./Server
                                Awaiting for new connections  IP "127.0.0.1" PORT 9000
                                New incoming connection
                                Socket info: QAbstractSocket::ConnectedState OpenMode( "ReadOnly|WriteOnly" )
                                Awaiting client message
                                Worker max running time expired
                                Worker exit
                                

                                CLIENT STDOUT

                                $ ./Client
                                Connecting to "127.0.0.1" : 9000
                                Connected
                                Sent to server:  POKE
                                Client exit
                                
                                jsulmJ Offline
                                jsulmJ Offline
                                jsulm
                                Lifetime Qt Champion
                                wrote on last edited by
                                #14

                                @dmitttri said in QTcpServer won't receive client data on connected QTcpSocket:

                                while (workerThreadShouldRun)
                                {

                                You're blocking Qt event loop again.
                                You should use signals/slots instead. There is readyRead signal which you should use.

                                https://forum.qt.io/topic/113070/qt-code-of-conduct

                                D 1 Reply Last reply
                                0
                                • jsulmJ jsulm

                                  @dmitttri said in QTcpServer won't receive client data on connected QTcpSocket:

                                  while (workerThreadShouldRun)
                                  {

                                  You're blocking Qt event loop again.
                                  You should use signals/slots instead. There is readyRead signal which you should use.

                                  D Offline
                                  D Offline
                                  dmitttri
                                  wrote on last edited by
                                  #15

                                  @jsulm said in QTcpServer won't receive client data on connected QTcpSocket:

                                  You're blocking Qt event loop again.
                                  You should use signals/slots instead. There is readyRead signal which you should use.

                                  Hi, thanks for your kind answer!

                                  I don't get this point with blocking the Qt event loop, by doing my own processing in a dedicated thread. I mean, threads are meant to be used with some kind of while loop until the job is done. doWork is implemented according to the Qt documentation, which states:

                                  public slots:
                                      void doWork(const QString &parameter) {
                                          QString result;
                                          /* ... here is the expensive or blocking operation ... */
                                          emit resultReady(result);
                                      }
                                  

                                  doWork in my case should communicate with the connected client, perform some dedicated job and then exit. Are you suggesting to use readyRead signal handler to process incoming data, and call doWork from it, taking care that doWork do not loop, but finish soon as possible? In such case my yet to come processing state machine would end up in readyRead handler, and there will be mutiple doWork methods doWork1, doWork2, which implements job steps. I can try such approach

                                  I am sorry for asking such questions, but this is somehow fundamental for me to understand why and how my thread handler manage to stops main Qt event loop, which executes in the main program process.

                                  I have already used thread with a Qt GUI application, and always had this pattern of while (threadShoudRun) and never had issues with event loop and GUI processing. Why this time it happens to be so problematic to run a thread processing loop?

                                  Are there any other Qt examples of a multi threaded TCP server, other than just fortune examples?

                                  Christian EhrlicherC jsulmJ 2 Replies Last reply
                                  0
                                  • D dmitttri

                                    @jsulm said in QTcpServer won't receive client data on connected QTcpSocket:

                                    You're blocking Qt event loop again.
                                    You should use signals/slots instead. There is readyRead signal which you should use.

                                    Hi, thanks for your kind answer!

                                    I don't get this point with blocking the Qt event loop, by doing my own processing in a dedicated thread. I mean, threads are meant to be used with some kind of while loop until the job is done. doWork is implemented according to the Qt documentation, which states:

                                    public slots:
                                        void doWork(const QString &parameter) {
                                            QString result;
                                            /* ... here is the expensive or blocking operation ... */
                                            emit resultReady(result);
                                        }
                                    

                                    doWork in my case should communicate with the connected client, perform some dedicated job and then exit. Are you suggesting to use readyRead signal handler to process incoming data, and call doWork from it, taking care that doWork do not loop, but finish soon as possible? In such case my yet to come processing state machine would end up in readyRead handler, and there will be mutiple doWork methods doWork1, doWork2, which implements job steps. I can try such approach

                                    I am sorry for asking such questions, but this is somehow fundamental for me to understand why and how my thread handler manage to stops main Qt event loop, which executes in the main program process.

                                    I have already used thread with a Qt GUI application, and always had this pattern of while (threadShoudRun) and never had issues with event loop and GUI processing. Why this time it happens to be so problematic to run a thread processing loop?

                                    Are there any other Qt examples of a multi threaded TCP server, other than just fortune examples?

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

                                    I already told you why an event loop is needed - to get the tcp data from the os into the QTcpSocket buffer so you can read it.

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

                                    D 1 Reply Last reply
                                    1
                                    • D dmitttri

                                      @jsulm said in QTcpServer won't receive client data on connected QTcpSocket:

                                      You're blocking Qt event loop again.
                                      You should use signals/slots instead. There is readyRead signal which you should use.

                                      Hi, thanks for your kind answer!

                                      I don't get this point with blocking the Qt event loop, by doing my own processing in a dedicated thread. I mean, threads are meant to be used with some kind of while loop until the job is done. doWork is implemented according to the Qt documentation, which states:

                                      public slots:
                                          void doWork(const QString &parameter) {
                                              QString result;
                                              /* ... here is the expensive or blocking operation ... */
                                              emit resultReady(result);
                                          }
                                      

                                      doWork in my case should communicate with the connected client, perform some dedicated job and then exit. Are you suggesting to use readyRead signal handler to process incoming data, and call doWork from it, taking care that doWork do not loop, but finish soon as possible? In such case my yet to come processing state machine would end up in readyRead handler, and there will be mutiple doWork methods doWork1, doWork2, which implements job steps. I can try such approach

                                      I am sorry for asking such questions, but this is somehow fundamental for me to understand why and how my thread handler manage to stops main Qt event loop, which executes in the main program process.

                                      I have already used thread with a Qt GUI application, and always had this pattern of while (threadShoudRun) and never had issues with event loop and GUI processing. Why this time it happens to be so problematic to run a thread processing loop?

                                      Are there any other Qt examples of a multi threaded TCP server, other than just fortune examples?

                                      jsulmJ Offline
                                      jsulmJ Offline
                                      jsulm
                                      Lifetime Qt Champion
                                      wrote on last edited by
                                      #17

                                      @dmitttri said in QTcpServer won't receive client data on connected QTcpSocket:

                                      threads are meant to be used with some kind of while loop until the job is done

                                      That's what Qt event loop is for...

                                      https://forum.qt.io/topic/113070/qt-code-of-conduct

                                      D 1 Reply Last reply
                                      0
                                      • Christian EhrlicherC Christian Ehrlicher

                                        I already told you why an event loop is needed - to get the tcp data from the os into the QTcpSocket buffer so you can read it.

                                        D Offline
                                        D Offline
                                        dmitttri
                                        wrote on last edited by dmitttri
                                        #18

                                        @Christian-Ehrlicher said in QTcpServer won't receive client data on connected QTcpSocket:

                                        I already told you why an event loop is needed - to get the tcp data from the os into the QTcpSocket buffer so you can read it.

                                        Sure thanks, but it don't really provide an explanation how to tell a new thread, run in an event loop so your tcp socket can get chance to read data.

                                        I thought it was about worker thread article.

                                        As explained there, in case of the Worker object approach, run method just runs exec() and this is should enable thread to run an event loop, while doWork is meant to do the thread processing job.

                                        Other valid approach (also explained there) is to override run method and do the threaded work there. This was my original approach also posted above. Which does not work.

                                        So I tried both options, posted the code, and with the short hints you and other members provided, I still could not understand the culprit and get it work. But this is related to my very low Qt coverage.

                                        Thanks for your help, I will figure out what I am doing wrong, and I will take care to post the proper solution.

                                        1 Reply Last reply
                                        0
                                        • jsulmJ jsulm

                                          @dmitttri said in QTcpServer won't receive client data on connected QTcpSocket:

                                          threads are meant to be used with some kind of while loop until the job is done

                                          That's what Qt event loop is for...

                                          D Offline
                                          D Offline
                                          dmitttri
                                          wrote on last edited by dmitttri
                                          #19

                                          @jsulm said in QTcpServer won't receive client data on connected QTcpSocket:

                                          @dmitttri said in QTcpServer won't receive client data on connected QTcpSocket:

                                          threads are meant to be used with some kind of while loop until the job is done

                                          That's what Qt event loop is for...

                                          Hm, this is what I may be missing, as someone not really familiar with Qt.

                                          Threads Events QObjects

                                          In particular, under Per-thread event loop there is an explanation of what I couldn't understand up to now. Apart of the Main Qt event loop, there are Per-thread event loops and specially networking classes are required to explicitly run such loop.

                                          jsulmJ 1 Reply Last reply
                                          0
                                          • D dmitttri

                                            @jsulm said in QTcpServer won't receive client data on connected QTcpSocket:

                                            @dmitttri said in QTcpServer won't receive client data on connected QTcpSocket:

                                            threads are meant to be used with some kind of while loop until the job is done

                                            That's what Qt event loop is for...

                                            Hm, this is what I may be missing, as someone not really familiar with Qt.

                                            Threads Events QObjects

                                            In particular, under Per-thread event loop there is an explanation of what I couldn't understand up to now. Apart of the Main Qt event loop, there are Per-thread event loops and specially networking classes are required to explicitly run such loop.

                                            jsulmJ Offline
                                            jsulmJ Offline
                                            jsulm
                                            Lifetime Qt Champion
                                            wrote on last edited by
                                            #20

                                            @dmitttri Please read https://wiki.qt.io/QThreads_general_usage

                                            https://forum.qt.io/topic/113070/qt-code-of-conduct

                                            D 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