Threaded Fortune Server Example

Image non disponible

The implementation of this example is similar to that of the Fortune Server example, but here we will implement a subclass of QTcpServer that starts each connection in a different thread.

For this we need two classes: FortuneServer, a QTcpServer subclass, and FortuneThread, which inherits QThread.

 
Sélectionnez
class FortuneServer : public QTcpServer
{
    Q_OBJECT

public:
    FortuneServer(QObject *parent = 0);

protected:
    void incomingConnection(qintptr socketDescriptor) override;

private:
    QStringList fortunes;
};

FortuneServer inherits QTcpServer and reimplements QTcpServer::incomingConnection(). We also use it for storing the list of random fortunes.

 
Sélectionnez
FortuneServer::FortuneServer(QObject *parent)
    : QTcpServer(parent)
{
    fortunes << tr("You've been leading a dog's life. Stay off the furniture.")
             << tr("You've got to think about tomorrow.")
             << tr("You will be surprised by a loud noise.")
             << tr("You will feel hungry again in another hour.")
             << tr("You might have mail.")
             << tr("You cannot kill time without injuring eternity.")
             << tr("Computers are not intelligent. They only think they are.");
}

We use FortuneServer's constructor to simply generate the list of fortunes.

 
Sélectionnez
void FortuneServer::incomingConnection(qintptr socketDescriptor)
{
    QString fortune = fortunes.at(QRandomGenerator::global()->bounded(fortunes.size()));
    FortuneThread *thread = new FortuneThread(socketDescriptor, fortune, this);
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
    thread->start();
}

Our implementation of QTcpServer::incomingConnection() creates a FortuneThread object, passing the incoming socket descriptor and a random fortune to FortuneThread's constructor. By connecting FortuneThread's finished() signal to QObject::deleteLater(), we ensure that the thread gets deleted once it has finished. We can then call QThread::start(), which starts the thread.

 
Sélectionnez
class FortuneThread : public QThread
{
    Q_OBJECT

public:
    FortuneThread(int socketDescriptor, const QString &fortune, QObject *parent);

    void run() override;

signals:
    void error(QTcpSocket::SocketError socketError);

private:
    int socketDescriptor;
    QString text;
};

Moving on to the FortuneThread class, this is a QThread subclass whose job is to write the fortune to the connected socket. The class reimplements QThread::run(), and it has a signal for reporting errors.

 
Sélectionnez
FortuneThread::FortuneThread(int socketDescriptor, const QString &fortune, QObject *parent)