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. Threaded TCP server for persistent connection

Threaded TCP server for persistent connection

Scheduled Pinned Locked Moved Solved General and Desktop
2 Posts 2 Posters 1.2k 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
    Sentret_C
    wrote on last edited by Sentret_C
    #1

    We are writing an app to receive and store data from IoT devices, which acts as a tcp server. We found some examples including the official threaded fortune server one, but different from those examples, in our case the tcp connection would last forever unless:

    • the tcp client is not our device (no valid response when expected),
    • the device is shut down (maybe out of power),
    • the app is closed (on server maintenance), or
    • the connection is simply lost due to network problem.

    We want to make sure that:

    • the resources are released as soon as possible, and
    • when the connection is closed by the app, it is closed properly (with FIN not RST).

    What's more, the communication class need to interact with the ui to show information to user and respond to change in configuration like request interval.

    We subclassed QTcpServer and:

    void MyServer::incomingConnection(qintptr socketDescriptor)
    {
        auto *worker = new MyWorker(socketDescriptor);
        auto *thread = new MyThread(this);
        worker->moveToThread(thread);
    
        connect(thread , &MyThread::started, worker, &MyWorker::init);
        connect(thread , &MyThread::finished, worker, &MyWorker::deleteLater);
        connect(worker, &MyWorker::showMsg, this, &MyServer::showMsg);
        connect(this, &MyServer::setReqInterval, worker, &MyWorker::setReqInterval);
    
        thread->start();
        emit setReqInterval(reqInterval);
    }
    

    QThread is subclassed to stop the thread on destruction:

    MyThread::~MyThread()
    {
        qDebug("in ~MyThread()");
        quit();
        wait();
    }
    

    Finally, in MyWorker:

    MyWorker::MyWorker(qintptr socketDescriptor, QObject *parent) :
        QObject(parent),
        socket(new QTcpSocket(this))
        connectionName(QString::number(socketDescriptor))
    {
        socket->setSocketDescriptor(socketDescriptor);
        connect(socket, &QTcpSocket::disconnected, this->thread(), &QThread::deleteLater);
    }
    
    void MyWorker::init()
    {
        // make sure the sql connection is created in the correct thread with a unique name
        auto db = QSqlDatabase::addDatabase("QMYSQL", connectionName);
        /*
            set database connection parameters
        */
        connect(socket, &QTcpSocket::readyRead, this, &MyWorker::dataReceived);
        connect(&sendTimer, &QTimer::timeout, this, &MyWorker::sendRequest);
        // sendTimer will be started in setReqInterval()
        recvTimer.setSingleShot(true);
        connect(&recvTimer, &QTimer::timeout, this, &MyWorker::recvTimeout);
        // recvTimer will be started in sendRequest() and stopped in dataReceived() if the data is valid
        sendRequest();
    }
    
    void MyWorker::recvTimeout()
    {
        QString message;
        /*
            construct message
        */
        emit showMsg(message);
        socket->disconnectFromHost();
    }
    

    The code above (modified for brevity so there may be typo) seems to work, but we are not sure if it is done correctly, especially:

    • the QTcpSocket objects are created and initialized (setSocketDescriptor called) in MyWorker constructor, which runs in the ui thread,
    • the worker object is deleted after the thread quits, probably when the thread object is deleted, and
    • we connected the socket's disconnected signal to &QThread::deleteLater of this->thread() in MyWorker constructor (though the debug output shows that ~MyThread() is called as expected), maybe we should change it to the following?
    // in MyServer::incomingConnection
        connect(worker, &MyWorker::destroyed, thread, &MyThread::deleteLater);
    
    // in MyWorker::MyWorker
        connect(socket, &QTcpSocket::disconnected, this, &MyWorker::deleteLater);
    
    1 Reply Last reply
    0
    • VRoninV Offline
      VRoninV Offline
      VRonin
      wrote on last edited by
      #2

      the QTcpSocket objects are created and initialized (setSocketDescriptor called) in MyWorker constructor, which runs in the ui thread

      That's fine, setting the socket descriptor is not an intensive task

      the worker object is deleted after the thread quits, probably when the thread object is deleted

      It's deleted when the thread finishes, not when it is deleted. Qt internals take care of this case, even if technically the thread finished already, Qt will still run any delayed deletes

      we connected the socket's disconnected signal to &QThread::deleteLater of this->thread() in MyWorker constructor

      You normally connect(thread, &MyThread::finished, thread, &MyThread::deleteLater); and then connect a signal to &MyThread::quit. Putting connect(socket, &QTcpSocket::disconnected, this->thread(), &QThread::deleteLater); violates OOD as makes the worker dependent on living in a QThread. The worker should just emit a signal when the sochet is disconnected and you should connect that signal to &MyThread::quit.

      P.S.
      Using 1 thread per client will quickly add too much overhead to your server. If you don't use that many clients you can even not use threads at all. We [users of the forum] recognise Qt examples for TCP are sub-optimal and we are working on a better example: You can have a look at what we have done so far, we have a basic version and a more advanced one.

      "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
      5

      • Login

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