Threaded Fortune Server
Das Beispiel „Threaded Fortune Server“ zeigt, wie man einen Server für einen einfachen Netzwerkdienst erstellt, der Threads verwendet, um Anfragen von verschiedenen Clients zu bearbeiten. Es ist für die Ausführung zusammen mit dem Beispiel „Fortune Client“ vorgesehen.

Die Implementierung dieses Beispiels ähnelt der des „Fortune-Server“-Beispiels, allerdings implementieren wir hier eine Unterklasse von „ QTcpServer “, die jede Verbindung in einem eigenen Thread startet.
Dazu benötigen wir zwei Klassen: „FortuneServer“, eine Unterklasse von „ QTcpServer “, und „FortuneThread“, die von „ QThread “ erbt.
class FortuneServer : public QTcpServer
{
Q_OBJECT
public:
FortuneServer(QObject *parent = nullptr);
protected:
void incomingConnection(qintptr socketDescriptor) override;
private:
QStringList fortunes;
};„FortuneServer“ erbt von „ QTcpServer “ und implementiert „ QTcpServer::incomingConnection()“ neu. Wir nutzen diese Klasse zudem zum Speichern der Liste mit zufälligen Sprüchen.
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.");
}Wir nutzen den Konstruktor von „FortuneServer“, um die Liste der Glückssprüche zu generieren.
void FortuneServer::incomingConnection(qintptr socketDescriptor)
{
QString fortune = fortunes.at(QRandomGenerator::global()->bounded(fortunes.size()));
FortuneThread *thread = new FortuneThread(socketDescriptor, fortune, this);
connect(thread, &FortuneThread::finished, thread, &FortuneThread::deleteLater);
thread->start();
}Unsere Implementierung von „ QTcpServer::incomingConnection()“ erstellt ein „FortuneThread“-Objekt, wobei der Deskriptor des eingehenden Sockets und ein zufälliges Glücksspruch an den Konstruktor von „FortuneThread“ übergeben werden. Indem wir das Signal „finished()“ von „FortuneThread“ mit „ QObject::deleteLater()“ verknüpfen, stellen wir sicher, dass der Thread gelöscht wird, sobald er beendet ist. Anschließend können wir „ QThread::start()“ aufrufen, wodurch der Thread gestartet wird.
class FortuneThread : public QThread
{
Q_OBJECT
public:
FortuneThread(qintptr socketDescriptor, const QString &fortune, QObject *parent);
void run() override;
signals:
void error(QTcpSocket::SocketError socketError);
private:
qintptr socketDescriptor;
QString text;
};Kommen wir nun zur Klasse „FortuneThread“: Dabei handelt es sich um eine Unterklasse von „ QThread “, deren Aufgabe darin besteht, das Sprichwort an den verbundenen Socket zu schreiben. Die Klasse implementiert die Methode „ QThread::run()“ neu und verfügt über ein Signal zur Meldung von Fehlern.
FortuneThread::FortuneThread(qintptr socketDescriptor, const QString &fortune, QObject *parent)
: QThread(parent), socketDescriptor(socketDescriptor), text(fortune)
{
}Der Konstruktor von `FortuneThread` speichert lediglich den Socket-Deskriptor und den „Fortune“-Text, damit diese später für `run()` verfügbar sind.
void FortuneThread::run()
{
QTcpSocket tcpSocket;Als Erstes erstellt unsere Funktion `run()` ein ` QTcpSocket `-Objekt auf dem Stack. Bemerkenswert ist, dass wir dieses Objekt innerhalb des Threads erstellen, wodurch der Socket automatisch der Ereignisschleife des Threads zugeordnet wird. Dies stellt sicher, dass Qt nicht versucht, Ereignisse vom Hauptthread an unseren Socket zu übermitteln, während wir von FortuneThread::run() aus darauf zugreifen.
if (!tcpSocket.setSocketDescriptor(socketDescriptor)) {
emit error(tcpSocket.error());
return;
}Der Socket wird durch den Aufruf von ` QTcpSocket::setSocketDescriptor()` initialisiert, wobei wir unseren Socket-Deskriptor als Argument übergeben. Wir gehen davon aus, dass dies gelingt, aber um ganz sicher zu gehen (auch wenn es unwahrscheinlich ist, dass dem System die Ressourcen ausgehen), fangen wir den Rückgabewert ab und melden etwaige Fehler.
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_6_5);
out << text;Wie im Beispiel „Fortune Server“ kodieren wir das Glücksspruch in einen ` QByteArray ` mithilfe von ` QDataStream`.
tcpSocket.write(block);
tcpSocket.disconnectFromHost();
tcpSocket.waitForDisconnected();
}Im Gegensatz zum vorherigen Beispiel schließen wir den Vorgang jedoch mit dem Aufruf von ` QTcpSocket::waitForDisconnected()` ab, wodurch der aufrufende Thread blockiert wird, bis die Socket-Verbindung getrennt wurde. Da wir in einem separaten Thread arbeiten, bleibt die GUI weiterhin reaktionsfähig.
Siehe auch „Fortune-Server“, „Fortune-Client“ und „Blockierender Fortune-Client“.
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.