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. QTcpSocket in QThread does not emit signals
Qt 6.11 is out! See what's new in the release blog

QTcpSocket in QThread does not emit signals

Scheduled Pinned Locked Moved Solved General and Desktop
3 Posts 2 Posters 1.3k 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.
  • S Offline
    S Offline
    Sasageyo
    wrote on last edited by
    #1

    Hi,

    I am working on a Kahoot like app (Just some question / answers, nothing really out of the ordinary) and at first glances, it seems to be working fine. With two differents projects, the server and the client(s), I use the QTcpSocket class as well as the QTcpServer and QThread in my server-side code.
    From what I have read (even though I am not completely sure), to make multiples clients connect to the server, I needed to add QThread to my project and then put inside my previous code about the QTcpSocket.
    At first my code resemble something llike this :

    • Mainwindow, with labels about the questions, the time remaining etc... ; container of MyServer (subclass of QTcpServer)
    • MyServer, a QTcpServer with QVector<QTcpSocket> clients

    At best, I could test this with only another computer, but now I have access to 3 different Windows 10 computer to test my code.
    It was when I could test it with more than one client that I saw something I can't solve now : I am not able to connect more than one client to my server.
    After some Googling, I found out that I needed to make differents thread to connect multiple clients to one server, so I did.
    Now my code is more something like this :

    • Mainwindow, with MyServer server
    • MyServer with QVector <MyThread*> clients
    • MyThread (subclass of QThread), with QTcpSocket * socket

    Here is my code below :

    • mainwindow.h
    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    #include <QMainWindow>
    #include "myserver.h"
    
    QT_BEGIN_NAMESPACE
    namespace Ui { class MainWindow; }
    QT_END_NAMESPACE
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        MainWindow(QWidget *parent = nullptr);
        ~MainWindow();
    
    public slots:
        void slotDataReceivedFromMyServer(const QByteArray Data, MyThread * source);
        // More stuff
    private:
        Ui::MainWindow * ui;
        MyServer * server;
       // More stuff
    };
    #endif // MAINWINDOW_H
    
    • mainwindow.cpp
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        this->setWindowTitle("Random Titre");
    
        server = new MyServer;
        connect(server, SIGNAL(emitDataReceivedFromMyServer(QByteArray,MyThread *)),this, SLOT(slotDataReceivedFromMyServer(QByteArray, MyThread *)));
        server->StartServer();
        qDebug() << "MainWindow : Done";
    
    }
    void MainWindow::slotDataReceivedFromMyServer(const QByteArray Data, MyThread * source)
    {
        // Here is where I get information like which answer has the client selected (A,B,C,D)
    }
    
    • MyServer.h
    #ifndef MYSERVER_H
    #define MYSERVER_H
    #include <QTcpServer>
    #include <QObject>
    #include <QDebug>
    #include <mythread.h>
    
    class MyServer : public QTcpServer
    {
        Q_OBJECT
    
    public:
        MyServer(QObject *parent=nullptr);
    
        QVector<MyThread*> clients; // Is public for testing, NOTE : do setter and getter
        void StartServer();
    
    signals:
        void emitDataReceivedFromMyServer(const QByteArray, MyThread * source);
        void emitSendMessageFromMyServer(QByteArray);
    
    public slots:
        void slotDataReceivedFromThread(QByteArray, MyThread * source);
        void slotRemoveClient(MyThread* thisThread);
        void slotLostConnectionOnThread();
    
    protected:
        void incomingConnection(qintptr);   //This is where we deal with incoming connections // Internet
    
    private:
        qintptr socketDescriptor; // What is that for ?
    
    };
    #endif // MYSERVER_H
    
    • MyServer.cpp
    #include "myserver.h"
    
    MyServer::MyServer(QObject *parent):
      QTcpServer(parent)
    {
    
    }
    
    void MyServer::StartServer()
    {
        // listen() start the server, 2222, Wifi and Ethernet
        if (!listen(QHostAddress::Any,2222))
        {
            qDebug() << "Something's wrong";
        }
        else
        {
            qDebug() << "MyServeur : Done";
        }
    }
    
    void MyServer::slotRemoveClient(MyThread * thisThread)
    {
        qDebug() << "Deleting  : " << thisThread->getSocketAdresse();
        clients.remove(clients.indexOf(thisThread));
    }
    
    void MyServer::slotLostConnectionOnThread()
    {
        // WIP
    }
    
    void MyServer::slotDataReceivedFromThread(QByteArray Data, MyThread * source)
    {
        emit emitDataReceivedFromMyServer(Data, source); // It goes to Mainwindow
    }
    
    void MyServer::incomingConnection(qintptr socketDescriptor)
    {
        qDebug() << "New Connection incoming, ID : " + QString::number(socketDescriptor);
        MyThread * thread = new MyThread(socketDescriptor,this);
        clients.append(thread); // Keep the new client in an array
        connect(thread,SIGNAL(lostConnection()),this,SLOT(slotLostConnectionOnThread()));
        connect(thread, SIGNAL(emitDataReceivedFromThread(QByteArray,MyThread*)),this, SLOT(slotDataReceivedFromThread(QByteArray,MyThread*)));
        connect(thread, SIGNAL(emitRemoveClient(MyThread*)),this, SLOT(slotRemoveClient(MyThread*)));
        thread->start();    // Which will cause the run() function ??
    }
    
    • MyThread.h
    #ifndef MYTHREAD_H
    #define MYTHREAD_H
    #include <QThread>
    #include <QTcpSocket>
    #include <QDebug>
    #include <QAbstractSocket>
    
    class MyThread : public QThread
    {
        Q_OBJECT
    
    public:
        explicit MyThread(qintptr ID, QObject *parent = nullptr); // Added ID to the constructor (For the socket ID number) // Internet
        void run() override; // NOTE : Override : since run already exist, this one take place and not the original from QTcpSocket
        QString getSocketAdresse();
        void writeData(QByteArray);  
        QString nickname; // Custom name
    
    signals:
        void error(QTcpSocket::SocketError socketerror); 
        void emitDataReceivedFromThread(QByteArray Data, MyThread* fromClient);
        void emitRemoveClient(MyThread*);
        void lostConnection();
    
    public slots:
        void readyRead(); // Everything we receive goes here
        void disconnected();
        void errorCommunication(QAbstractSocket::SocketError);
        void newState(QAbstractSocket::SocketState);
    
    private:
        QTcpSocket * socket; // Here is now QtcpSocket
        qintptr socketDescriptor; // Still don't know what that is // Internet
    };
    #endif // MYTHREAD_H
    

    -MyThread.cpp

    #include "mythread.h"
    
    MyThread::MyThread(qintptr ID, QObject *parent):
      QThread(parent)
    {
        socket = new QTcpSocket(this);
        socket->setSocketDescriptor(ID);
        socket->setSocketOption(QAbstractSocket::KeepAliveOption,true); // Internet
        this->socketDescriptor = ID; // Get the socket ID number // Internet
        qDebug() << "New thread, ID : " + QString::number(ID);
        // setParent(0); // ???
        // moveToThread(this); /// ???
    }
    
    void MyThread::run() // Override : priority
    {
        qDebug() << "Thread starting, ID : " << this->socketDescriptor;
        if (socket->socketDescriptor()!=socketDescriptor) // Checking I guess
        {
            emit emitDataReceivedFromThread("Error", this);
            return;
        }
    
        connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead())); 
        connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
        connect(socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), this, SLOT(erreurComm(QAbstractSocket::SocketError)));
        connect(socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(changementEtat(QAbstractSocket::SocketState)));
        qDebug() << "Connects are done";
    
        // KEEP THIS, Internet
        // This function will cause the thread to stay alive until we tell it to close
        // Otherwise the run() function will end and the thread will be dropped / destroyed
        exec();
    }
    
    QString MyThread::getSocketAdresse()
    {
        return socket->peerAddress().toString();
    }
    
    void MyThread::writeData(QByteArray Data) // Keep that public
    {
        socket->write(Data);
        socket->waitForBytesWritten(); // Is this working ?
        msleep(15); // Just to be sure
    }
    
    void MyThread::readyRead() // We receive data
    {
        QByteArray Data = socket->readAll();
        qDebug() << Data; // Seems fine
        emit emitDataReceivedFromThread(Data, this); // Goes to MyServer
    }
    
    void MyThread::disconnected()
    {
        // emit emitRemoveClient(this);
        emit lostConnection(); // Flag this Thread as disconnected, but don't delete it (keeping scores)
        // socket->deleteLater(); // No idea what it does
        // exit(0); // ?????
    }
    
    void MyThread::errorCommunication(QAbstractSocket::SocketError error)
    {
        qDebug() << "Error occurred : " << erreur;
    }
    
    void MyThread::newState(QAbstractSocket::SocketState state)
    {
        qDebug() << "New state : " << etat;
    }
    

    My problem now is that the signals disconnected, errorOccurred and stateChanged does not seem to be emited at all.
    When a client connect to the server, and the send for exemple the string "This is a test", the slot readyRead work fine and emitDataReceivedFromThread is being done without any kind of issue.
    Same goes if from MainWindow I do writeData("Something"), the client get this string without any kind of issue.
    When I check the debug console, I get this :

    • QObject: Cannot create children for a parent that is in a different thread.
    • (Parent is QNativeSocketEngine(0x11d16d0), parent's thread is MyThread(0x11b3de0), current thread is QThread(0x1d90e0)
    • QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread

    I don't konw what is happening and also don't know how to solve it. Is there an issue with my code or the way I'm thinking that is not compatible with QT?
    Also, when one of the client, which is connected to my Wifi, suddently disconnect from the Wlan, the server does not seem to detect that a client is not here anymore, and so when I call writeData(), it crashes everything.

    Thanks for everybody who will answer this, if you have a solution, or some ready-to-use code or some explaination on what I'm doing wrong, I will gladly take.

    VRoninV 1 Reply Last reply
    0
    • S Sasageyo

      Hi,

      I am working on a Kahoot like app (Just some question / answers, nothing really out of the ordinary) and at first glances, it seems to be working fine. With two differents projects, the server and the client(s), I use the QTcpSocket class as well as the QTcpServer and QThread in my server-side code.
      From what I have read (even though I am not completely sure), to make multiples clients connect to the server, I needed to add QThread to my project and then put inside my previous code about the QTcpSocket.
      At first my code resemble something llike this :

      • Mainwindow, with labels about the questions, the time remaining etc... ; container of MyServer (subclass of QTcpServer)
      • MyServer, a QTcpServer with QVector<QTcpSocket> clients

      At best, I could test this with only another computer, but now I have access to 3 different Windows 10 computer to test my code.
      It was when I could test it with more than one client that I saw something I can't solve now : I am not able to connect more than one client to my server.
      After some Googling, I found out that I needed to make differents thread to connect multiple clients to one server, so I did.
      Now my code is more something like this :

      • Mainwindow, with MyServer server
      • MyServer with QVector <MyThread*> clients
      • MyThread (subclass of QThread), with QTcpSocket * socket

      Here is my code below :

      • mainwindow.h
      #ifndef MAINWINDOW_H
      #define MAINWINDOW_H
      #include <QMainWindow>
      #include "myserver.h"
      
      QT_BEGIN_NAMESPACE
      namespace Ui { class MainWindow; }
      QT_END_NAMESPACE
      
      class MainWindow : public QMainWindow
      {
          Q_OBJECT
      
      public:
          MainWindow(QWidget *parent = nullptr);
          ~MainWindow();
      
      public slots:
          void slotDataReceivedFromMyServer(const QByteArray Data, MyThread * source);
          // More stuff
      private:
          Ui::MainWindow * ui;
          MyServer * server;
         // More stuff
      };
      #endif // MAINWINDOW_H
      
      • mainwindow.cpp
      #include "mainwindow.h"
      #include "ui_mainwindow.h"
      
      MainWindow::MainWindow(QWidget *parent)
          : QMainWindow(parent)
          , ui(new Ui::MainWindow)
      {
          ui->setupUi(this);
          this->setWindowTitle("Random Titre");
      
          server = new MyServer;
          connect(server, SIGNAL(emitDataReceivedFromMyServer(QByteArray,MyThread *)),this, SLOT(slotDataReceivedFromMyServer(QByteArray, MyThread *)));
          server->StartServer();
          qDebug() << "MainWindow : Done";
      
      }
      void MainWindow::slotDataReceivedFromMyServer(const QByteArray Data, MyThread * source)
      {
          // Here is where I get information like which answer has the client selected (A,B,C,D)
      }
      
      • MyServer.h
      #ifndef MYSERVER_H
      #define MYSERVER_H
      #include <QTcpServer>
      #include <QObject>
      #include <QDebug>
      #include <mythread.h>
      
      class MyServer : public QTcpServer
      {
          Q_OBJECT
      
      public:
          MyServer(QObject *parent=nullptr);
      
          QVector<MyThread*> clients; // Is public for testing, NOTE : do setter and getter
          void StartServer();
      
      signals:
          void emitDataReceivedFromMyServer(const QByteArray, MyThread * source);
          void emitSendMessageFromMyServer(QByteArray);
      
      public slots:
          void slotDataReceivedFromThread(QByteArray, MyThread * source);
          void slotRemoveClient(MyThread* thisThread);
          void slotLostConnectionOnThread();
      
      protected:
          void incomingConnection(qintptr);   //This is where we deal with incoming connections // Internet
      
      private:
          qintptr socketDescriptor; // What is that for ?
      
      };
      #endif // MYSERVER_H
      
      • MyServer.cpp
      #include "myserver.h"
      
      MyServer::MyServer(QObject *parent):
        QTcpServer(parent)
      {
      
      }
      
      void MyServer::StartServer()
      {
          // listen() start the server, 2222, Wifi and Ethernet
          if (!listen(QHostAddress::Any,2222))
          {
              qDebug() << "Something's wrong";
          }
          else
          {
              qDebug() << "MyServeur : Done";
          }
      }
      
      void MyServer::slotRemoveClient(MyThread * thisThread)
      {
          qDebug() << "Deleting  : " << thisThread->getSocketAdresse();
          clients.remove(clients.indexOf(thisThread));
      }
      
      void MyServer::slotLostConnectionOnThread()
      {
          // WIP
      }
      
      void MyServer::slotDataReceivedFromThread(QByteArray Data, MyThread * source)
      {
          emit emitDataReceivedFromMyServer(Data, source); // It goes to Mainwindow
      }
      
      void MyServer::incomingConnection(qintptr socketDescriptor)
      {
          qDebug() << "New Connection incoming, ID : " + QString::number(socketDescriptor);
          MyThread * thread = new MyThread(socketDescriptor,this);
          clients.append(thread); // Keep the new client in an array
          connect(thread,SIGNAL(lostConnection()),this,SLOT(slotLostConnectionOnThread()));
          connect(thread, SIGNAL(emitDataReceivedFromThread(QByteArray,MyThread*)),this, SLOT(slotDataReceivedFromThread(QByteArray,MyThread*)));
          connect(thread, SIGNAL(emitRemoveClient(MyThread*)),this, SLOT(slotRemoveClient(MyThread*)));
          thread->start();    // Which will cause the run() function ??
      }
      
      • MyThread.h
      #ifndef MYTHREAD_H
      #define MYTHREAD_H
      #include <QThread>
      #include <QTcpSocket>
      #include <QDebug>
      #include <QAbstractSocket>
      
      class MyThread : public QThread
      {
          Q_OBJECT
      
      public:
          explicit MyThread(qintptr ID, QObject *parent = nullptr); // Added ID to the constructor (For the socket ID number) // Internet
          void run() override; // NOTE : Override : since run already exist, this one take place and not the original from QTcpSocket
          QString getSocketAdresse();
          void writeData(QByteArray);  
          QString nickname; // Custom name
      
      signals:
          void error(QTcpSocket::SocketError socketerror); 
          void emitDataReceivedFromThread(QByteArray Data, MyThread* fromClient);
          void emitRemoveClient(MyThread*);
          void lostConnection();
      
      public slots:
          void readyRead(); // Everything we receive goes here
          void disconnected();
          void errorCommunication(QAbstractSocket::SocketError);
          void newState(QAbstractSocket::SocketState);
      
      private:
          QTcpSocket * socket; // Here is now QtcpSocket
          qintptr socketDescriptor; // Still don't know what that is // Internet
      };
      #endif // MYTHREAD_H
      

      -MyThread.cpp

      #include "mythread.h"
      
      MyThread::MyThread(qintptr ID, QObject *parent):
        QThread(parent)
      {
          socket = new QTcpSocket(this);
          socket->setSocketDescriptor(ID);
          socket->setSocketOption(QAbstractSocket::KeepAliveOption,true); // Internet
          this->socketDescriptor = ID; // Get the socket ID number // Internet
          qDebug() << "New thread, ID : " + QString::number(ID);
          // setParent(0); // ???
          // moveToThread(this); /// ???
      }
      
      void MyThread::run() // Override : priority
      {
          qDebug() << "Thread starting, ID : " << this->socketDescriptor;
          if (socket->socketDescriptor()!=socketDescriptor) // Checking I guess
          {
              emit emitDataReceivedFromThread("Error", this);
              return;
          }
      
          connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead())); 
          connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
          connect(socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), this, SLOT(erreurComm(QAbstractSocket::SocketError)));
          connect(socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(changementEtat(QAbstractSocket::SocketState)));
          qDebug() << "Connects are done";
      
          // KEEP THIS, Internet
          // This function will cause the thread to stay alive until we tell it to close
          // Otherwise the run() function will end and the thread will be dropped / destroyed
          exec();
      }
      
      QString MyThread::getSocketAdresse()
      {
          return socket->peerAddress().toString();
      }
      
      void MyThread::writeData(QByteArray Data) // Keep that public
      {
          socket->write(Data);
          socket->waitForBytesWritten(); // Is this working ?
          msleep(15); // Just to be sure
      }
      
      void MyThread::readyRead() // We receive data
      {
          QByteArray Data = socket->readAll();
          qDebug() << Data; // Seems fine
          emit emitDataReceivedFromThread(Data, this); // Goes to MyServer
      }
      
      void MyThread::disconnected()
      {
          // emit emitRemoveClient(this);
          emit lostConnection(); // Flag this Thread as disconnected, but don't delete it (keeping scores)
          // socket->deleteLater(); // No idea what it does
          // exit(0); // ?????
      }
      
      void MyThread::errorCommunication(QAbstractSocket::SocketError error)
      {
          qDebug() << "Error occurred : " << erreur;
      }
      
      void MyThread::newState(QAbstractSocket::SocketState state)
      {
          qDebug() << "New state : " << etat;
      }
      

      My problem now is that the signals disconnected, errorOccurred and stateChanged does not seem to be emited at all.
      When a client connect to the server, and the send for exemple the string "This is a test", the slot readyRead work fine and emitDataReceivedFromThread is being done without any kind of issue.
      Same goes if from MainWindow I do writeData("Something"), the client get this string without any kind of issue.
      When I check the debug console, I get this :

      • QObject: Cannot create children for a parent that is in a different thread.
      • (Parent is QNativeSocketEngine(0x11d16d0), parent's thread is MyThread(0x11b3de0), current thread is QThread(0x1d90e0)
      • QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread

      I don't konw what is happening and also don't know how to solve it. Is there an issue with my code or the way I'm thinking that is not compatible with QT?
      Also, when one of the client, which is connected to my Wifi, suddently disconnect from the Wlan, the server does not seem to detect that a client is not here anymore, and so when I call writeData(), it crashes everything.

      Thanks for everybody who will answer this, if you have a solution, or some ready-to-use code or some explaination on what I'm doing wrong, I will gladly take.

      VRoninV Offline
      VRoninV Offline
      VRonin
      wrote on last edited by VRonin
      #2

      @Sasageyo said in QTcpSocket in QThread does not emit signals:

      to make multiples clients connect to the server, I needed to add QThread to my project

      Common misconception.
      see https://wiki.qt.io/WIP-How_to_create_a_simple_chat_application for an example of how to manage it without threads (and with them if you really need it)

      You are also are making a very common mistake. QThread is not a thread it's a container for the thread. only run() is the new thread. A slot of QThread will be executed in the thread that created the QThread object. see https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/

      "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
      ~Napoleon Bonaparte

      On a crusade to banish setIndexWidget() from the holy land of Qt

      1 Reply Last reply
      6
      • S Offline
        S Offline
        Sasageyo
        wrote on last edited by
        #3

        Hi again.

        After multiple test and reading from the link you provided, I managed to create the app I wanted, and it work just fine.
        Multiples clients are now connecting just fine, and I can distinctively know which one's which.
        The "simple chat application" was very usefull, I will get it somewhere in a notepad.

        Thanks for your help, I will now make this post as solved.

        1 Reply Last reply
        2

        • Login

        • Login or register to search.
        • First post
          Last post
        0
        • Categories
        • Recent
        • Tags
        • Popular
        • Users
        • Groups
        • Search
        • Get Qt Extensions
        • Unsolved