Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

What is the best approach to handle QTcpSocket (client connection) in a QThread ?



  • Hello,

    I am developing a GUI application wich needs to handle many client connections.
    I have to send queries and read replies.

    The main GUI (a subclass of QMainWindow) instantiate many widgets where each one represents a client connection widget and I have to execute a thread for each client connection.

    My doubt is how to handle client connection usin QThread and what is the best approach to this problem.

    I tried to create a subclass of QThread implementing a QTcpSocket (with slots connected to to connected(), disconnected() and readyRead() signals), and overriding the run() of QThread class.
    To show an example of this description, I post a code snippet:

    class ClientWorker : public QThread
    {
        public:
        
        ClientWorker(void);
        ~ClientWorker(void);
    
        void run() override;
        
        qint32 writeData(QByteArray);
        
        public 
            
            slots:
            void socketConnectedSlot(void);
            void socketDisconnectedSlot(void);
            QByteArray readData(void);
        
        private:
            
            // example address and port
            QString address = "192.168.10.10";
            const qint32 port = 5000;
            
            bool loop;
            QTcpSocket *socket;
    
            bool socketConnect(void);
            void socketClose(void);
    };
    
    ClientWorker::ClientWorker(void)
    {
        socket = new QTcpSocket;
        connect(socket, SIGNAL(connected()), this, SLOT(socketConnectedSlot()));
        connect(socket, SIGNAL(disconnected()), this, SLOT(socketDisconnectedSlot()));
        connect(socket, SIGNAL(readyRead()),this, SLOT(readData()));
    
        socketConnect();
    }
    
    bool ClientWorker::socketConnect(void)
    {   
        qDebug() << "Address " << address << ":" << port << endl;
        socket->connectToHost(address, port);
        return socket->waitForConnected();
    }
    
    void ClientWorker::socketClose(void)
    {   
        socket->close();
    }
    
    void ClientWorker::run(void)
    {   
        while(loop)
        {
            qDebug() << "Writing " << cmd << " to " << address;
    
            // example, send data to server socket
            writeData(cmd);
            this->sleep(1);
        }
    }
    
    void ClientWorker::stop(void)
    {
        qDebug() << "Stopped";
        loop = false;
    
        if(socket->state() == QAbstractSocket::ConnectedState)
            socket->close();
    }
    
    void ClientWorker::socketConnectedSlot()
    {
        qDebug() << "Connected to " << address << ":" << port << endl;
        loop = true;
        this->start();
    }
    
    void ClientWorker::socketDisconnectedSlot()
    {
        qDebug() << "Diconnected";
        stop();
    }
    
    QByteArray ClientWorker::readData(void)
    {   
        // read chunk of data
        QByteArray tmpData = socket->readAll();
        qDebug() << "Read " << tmpData.data() << " from " << address;
    
        return tmpData;
    }
    
    qint32 ClientWorker::writeData(QByteArray data)
    {
        qint32 nwrite = 0;
        
        if(socket->state() == QAbstractSocket::ConnectedState)
        {
            qDebug() << data;
            nwrite = socket->write(data);
            socket->waitForBytesWritten();
        }
            
        return nwrite;
    }
    
    

    I understand that this is not the correct way to handle a threaded connection since it doesn't work very well because the socket signals are not handled correctly.

    So what is the best way to handle client threaded connections using a thread running its own loop while handling socket signals ?
    Could you suggest the best approach to this problem ?

    Thanks



  • A few of us here on the forum are working on a good example to illustrate this, it's still a work in progress but the example is already 100% functional, we just need to simplify it and write the step-by-step.

    You can reach it here https://github.com/VSRonin/ChatExample

    Hopefully in a few weeks the example will be complete.

    P.S.
    You don't really need QThread unless the server must do some intensive operation for each client



  • Hello @VRonin,

    Thank you for your example.

    You don't really need QThread unless the server must do some intensive operation for each client

    I would like to know more about this, because right now I feel like I don't have a clear idea.

    The application is multi-client, I mean that each client connects to a different server, and every 1 or 2 s must send a query and receive the respective reply.
    Of course I must be able to connect or disconnect manually each client from the main GUI, so I cannot freeze it.

    As I understand, without a thread the GUI would freeze, and I don't know how to keep the client sending data in a non threaded loop without freezing the GUI.

    EDIT: perhaps I need to redesign the application, as I see from your ChatServer and ServerWorker classes.

    Thanks



  • The application is multi-client, I mean that each client connects to a different server

    ??? so you mean it is multi-server?

    As I understand, without a thread the GUI would freeze

    Common misunderstanding.

    I would like to know more about this

    Check the QtSimpleChatServer folder it manages multiple clients without blocking. Of course in that example it's just a console application but you are free to change it into a widget application with no changes to the core of the code



  • @VRonin said in What is the best approach to handle QTcpSocket (client connection) in a QThread ?:

    ?? so you mean it is multi-server?

    Well , In my GUI I can add client widgets and each one respective QTcpSocket client connects to a different remote server:

    client0 connects to server0
    client1 connects to server1
    client2 connects to server2
    and so on.

    Check the QtSimpleChatServer folder it manages multiple clients without blocking. Of course in that example it's just a console application but you are free to change it into a widget application with no changes to the core of the code.

    OK. I will.

    Thanks.



  • @simozz
    OK, this is unusual way round! I think @VRonin (and I) assumed your "handle many client connections" meant a server handling many clients. You actually have a "client" application which acts as many clients to many servers.

    I don't know whether you need separate threads or whether it can just act with multiple clients in main GUI thread and just handle each socket through slots...



  • @JonB said in What is the best approach to handle QTcpSocket (client connection) in a QThread ?:

    it can just act with multiple clients in main GUI thread and just handle each socket through slots

    It can. To demonstrate it, In the example, you can easily change https://github.com/VSRonin/ChatExample/blob/master/QtSimpleChatClient/clientmain.cpp adding, just before the return

    with:

    ChatWindow chatWin2;
    chatWin2.show();
    ChatWindow chatWin3;
    chatWin3.show();
    

    To have 3 clients on the same thread and all non blocking.


Log in to reply