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. Multithreading with QTcpServer
Forum Updated to NodeBB v4.3 + New Features

Multithreading with QTcpServer

Scheduled Pinned Locked Moved Solved General and Desktop
7 Posts 2 Posters 3.4k Views 1 Watching
  • 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.
  • F Offline
    F Offline
    FloatFlower.Huang
    wrote on 20 Nov 2017, 12:07 last edited by
    #1

    I am trying to develop a HTTP server with QTcpServer and QThread, here is my code:

    Server class:

    Server::Server(QObject *parent)
        : QObject(parent)
        , m_server(new QTcpServer(this))
        , m_serverMutex(new QMutex)
        , m_thread1(new WorkerThread(m_server, m_serverMutex, this))
        , m_thread2(new WorkerThread(m_server, m_serverMutex, this))
    {
        connect(this, SIGNAL(startThread()), m_thread1, SLOT(start()));
        connect(this, SIGNAL(startThread()), m_thread2, SLOT(start()));
        connect(m_server, SIGNAL(newConnection()), m_thread1, SLOT(onNewConnection()), Qt::QueuedConnection);
        connect(m_server, SIGNAL(newConnection()), m_thread2, SLOT(onNewConnection()), Qt::QueuedConnection);
    }
    
    void Server::run()
    {
        emit startThread();
        qDebug() << "Start to listen 3000 port";
        m_server->listen(QHostAddress::LocalHost, 3000);
    }
    
    

    Thread class:

    #include "workerthread.h"
    #include <QTcpSocket>
    
    WorkerThread::WorkerThread(QObject *parent = 0)
        : QThread(parent)
    {
    }
    
    WorkerThread::WorkerThread(QTcpServer* server, QMutex *serverMutex, QObject *parent)
        : QThread(parent)
        , m_server(server)
        , m_serverMutex(serverMutex)
    {
    }
    
    void WorkerThread::run()
    {
        qDebug() << "Start thread: " << QThread::currentThreadId();
        exec();
    }
    
    void WorkerThread::onNewConnection()
    {
        qDebug() << "Getting signal from thread: " << QThread::currentThreadId();
        m_serverMutex->lock();
        if (m_server->hasPendingConnections()) {
            qDebug() << "Accept a new connection from thread: " << QThread::currentThreadId();
            QTcpSocket *socket = m_server->nextPendingConnection();
            m_serverMutex->unlock();
            connect(socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
        }
    }
    
    void WorkerThread::onReadyRead()
    {
        QObject* object = sender();
        QTcpSocket *socket = qobject_cast<QTcpSocket*>(object);
        QByteArray data = socket->readAll();
        socket->write("HTTP/1.1 200 OK\n\n");
        socket->close();
    }
    

    This code works when only one thread connect to the QTcpServer, however, when I use two threads to receive the signal it doesn't work.

    At first, my opinion is that make all WorkerThread to compete m_serverMutex, if it compete the mutex successfully, it can get the socket with QTcpServer::nextPendingConnection().

    Why this code doesn't work when using multi-thread?

    J 1 Reply Last reply 20 Nov 2017, 12:21
    0
    • F FloatFlower.Huang
      20 Nov 2017, 12:07

      I am trying to develop a HTTP server with QTcpServer and QThread, here is my code:

      Server class:

      Server::Server(QObject *parent)
          : QObject(parent)
          , m_server(new QTcpServer(this))
          , m_serverMutex(new QMutex)
          , m_thread1(new WorkerThread(m_server, m_serverMutex, this))
          , m_thread2(new WorkerThread(m_server, m_serverMutex, this))
      {
          connect(this, SIGNAL(startThread()), m_thread1, SLOT(start()));
          connect(this, SIGNAL(startThread()), m_thread2, SLOT(start()));
          connect(m_server, SIGNAL(newConnection()), m_thread1, SLOT(onNewConnection()), Qt::QueuedConnection);
          connect(m_server, SIGNAL(newConnection()), m_thread2, SLOT(onNewConnection()), Qt::QueuedConnection);
      }
      
      void Server::run()
      {
          emit startThread();
          qDebug() << "Start to listen 3000 port";
          m_server->listen(QHostAddress::LocalHost, 3000);
      }
      
      

      Thread class:

      #include "workerthread.h"
      #include <QTcpSocket>
      
      WorkerThread::WorkerThread(QObject *parent = 0)
          : QThread(parent)
      {
      }
      
      WorkerThread::WorkerThread(QTcpServer* server, QMutex *serverMutex, QObject *parent)
          : QThread(parent)
          , m_server(server)
          , m_serverMutex(serverMutex)
      {
      }
      
      void WorkerThread::run()
      {
          qDebug() << "Start thread: " << QThread::currentThreadId();
          exec();
      }
      
      void WorkerThread::onNewConnection()
      {
          qDebug() << "Getting signal from thread: " << QThread::currentThreadId();
          m_serverMutex->lock();
          if (m_server->hasPendingConnections()) {
              qDebug() << "Accept a new connection from thread: " << QThread::currentThreadId();
              QTcpSocket *socket = m_server->nextPendingConnection();
              m_serverMutex->unlock();
              connect(socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
          }
      }
      
      void WorkerThread::onReadyRead()
      {
          QObject* object = sender();
          QTcpSocket *socket = qobject_cast<QTcpSocket*>(object);
          QByteArray data = socket->readAll();
          socket->write("HTTP/1.1 200 OK\n\n");
          socket->close();
      }
      

      This code works when only one thread connect to the QTcpServer, however, when I use two threads to receive the signal it doesn't work.

      At first, my opinion is that make all WorkerThread to compete m_serverMutex, if it compete the mutex successfully, it can get the socket with QTcpServer::nextPendingConnection().

      Why this code doesn't work when using multi-thread?

      J Offline
      J Offline
      jsulm
      Lifetime Qt Champion
      wrote on 20 Nov 2017, 12:21 last edited by
      #2

      @FloatFlower.Huang said in Multithreading with QTcpServer:

      void WorkerThread::onNewConnection()
      {
      qDebug() << "Getting signal from thread: " << QThread::currentThreadId();
      m_serverMutex->lock();
      if (m_server->hasPendingConnections()) {
      qDebug() << "Accept a new connection from thread: " << QThread::currentThreadId();
      QTcpSocket *socket = m_server->nextPendingConnection();
      m_serverMutex->unlock();
      connect(socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
      }
      }

      You don't unlock the mutex! Use QMutexLocker - it will unlock mutex automatically when going out of scope.

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

      1 Reply Last reply
      0
      • F Offline
        F Offline
        FloatFlower.Huang
        wrote on 20 Nov 2017, 12:46 last edited by
        #3

        @jsulm
        In my code, even the qDebug() << "Getting signal from thread: " << QThread::currentThreadId(); doesn't print anything, which means it onNewConnection() doesn't receive the signal. Why signal cannot emit to multiple thread?

        J 1 Reply Last reply 20 Nov 2017, 12:47
        0
        • F FloatFlower.Huang
          20 Nov 2017, 12:46

          @jsulm
          In my code, even the qDebug() << "Getting signal from thread: " << QThread::currentThreadId(); doesn't print anything, which means it onNewConnection() doesn't receive the signal. Why signal cannot emit to multiple thread?

          J Offline
          J Offline
          jsulm
          Lifetime Qt Champion
          wrote on 20 Nov 2017, 12:47 last edited by jsulm
          #4

          @FloatFlower.Huang Did you start the threads?
          Also why do you want to send same signal to multiple threads? You should send it to the next free thread.

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

          1 Reply Last reply
          0
          • F Offline
            F Offline
            FloatFlower.Huang
            wrote on 20 Nov 2017, 13:36 last edited by FloatFlower.Huang
            #5

            @jsulm
            Yes, I started them.
            Because QTcpSocket is a non-blocking socket, so one thread can handle lots of sockets. As the result, I want to create 4 threads to compete the incomming socket when the new connection is available.

            J 1 Reply Last reply 20 Nov 2017, 13:49
            0
            • F FloatFlower.Huang
              20 Nov 2017, 13:36

              @jsulm
              Yes, I started them.
              Because QTcpSocket is a non-blocking socket, so one thread can handle lots of sockets. As the result, I want to create 4 threads to compete the incomming socket when the new connection is available.

              J Offline
              J Offline
              jsulm
              Lifetime Qt Champion
              wrote on 20 Nov 2017, 13:49 last edited by
              #6

              @FloatFlower.Huang said in Multithreading with QTcpServer:

              so one thread can handle lots of sockets

              I would actually handle only one connection per thread at a given time.
              And I would not connect each thread to newConnection() signal. Instead I would connect newConnection() signal to a slot in a manager class which then spawns a new thread (or, even better, reuses a free thread from a thread pool) and delegates the connection to that thread.

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

              1 Reply Last reply
              2
              • F Offline
                F Offline
                FloatFlower.Huang
                wrote on 21 Nov 2017, 01:22 last edited by FloatFlower.Huang
                #7

                @jsulm

                If I use socket-pre-thread approach there will a lot of thread when concurrent connections come.
                If I put socket in QRunnable, putting them to QThreadPool and set the max threads to 4. As every socket, I am going to waiting for all data arriving, and handle the request, and then write response to socket.
                And then if I want to send a large file to client, in HTTP, the file should be split into smaller package to send, also, in TCP, we should wait for the signal bytesWritten() emitted and then we can send the next package. If we want to wait the signal, we should create a QEventLoop in QRunnable, each socket will occupy a thread. If there are 4 sockets request a large file and I need to send the file package by package, and the 4 threads will be in used, as the result, the next connection cannot be handle in time.

                But your solution is the best, thank you so much.

                1 Reply Last reply
                0

                1/7

                20 Nov 2017, 12:07

                • Login

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