Fortune Server

Ce exemple montre comment créer un serveur pour un service réseau.

Cet exemple est destiné à être exécuté en parallèle de l'exemple « Fortune Client » ou de l'exemple « Blocking Fortune Client ».

Capture d'écran de l'exemple du serveur Fortune

Il utilise la fonction « QTcpServer » pour accepter les connexions TCP entrantes, ainsi qu’un protocole de transfert de données simple basé sur « QDataStream » pour envoyer une citation au client qui se connecte (issu de l’exemple « Fortune Client »), avant de fermer la connexion.

class Server : public QDialog
{
    Q_OBJECT

public:
    explicit Server(QWidget *parent = nullptr);

private slots:
    void sendFortune();

private:
    void initServer();

    QLabel *statusLabel = nullptr;
    QTcpServer *tcpServer = nullptr;
    QList<QString> fortunes;
};

Le serveur est implémenté à l’aide d’une classe simple ne comportant qu’un seul slot, destiné à gérer les connexions entrantes.

    tcpServer = new QTcpServer(this);
    if (!tcpServer->listen()) {
        QMessageBox::critical(this, tr("Fortune Server"),
                              tr("Unable to start the server: %1.")
                              .arg(tcpServer->errorString()));
        close();
        return;
    }
    QString ipAddress;
    const QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();
    // use the first non-localhost IPv4 address
    for (const QHostAddress &entry : ipAddressesList) {
        if (entry != QHostAddress::LocalHost && entry.toIPv4Address()) {
            ipAddress = entry.toString();
            break;
        }
    }
    // if we did not find one, use IPv4 localhost
    if (ipAddress.isEmpty())
        ipAddress = QHostAddress(QHostAddress::LocalHost).toString();
    statusLabel->setText(tr("The server is running on\n\nIP: %1\nport: %2\n\n"
                            "Run the Fortune Client example now.")
                         .arg(ipAddress).arg(tcpServer->serverPort()));

Dans son constructeur, notre objet Server appelle la méthode QTcpServer::listen() pour configurer un QTcpServer afin d’écouter sur toutes les adresses, sur un port arbitraire. Il affiche ensuite l’ QTcpServer du port sélectionné dans une étiquette, afin que l’utilisateur sache à quel port le client « fortune » doit se connecter.

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.");

Notre serveur génère une liste de citations aléatoires qu’il peut envoyer aux clients qui se connectent.

connect(tcpServer, &QTcpServer::newConnection, this, &Server::sendFortune);

Lorsqu’un client se connecte à notre serveur, QTcpServer émet QTcpServer::newConnection(). Cela déclenche à son tour notre slot sendFortune() :

void Server::sendFortune()
{
    QByteArray block;
    QDataStream out(&block, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_6_5);

    out << fortunes[QRandomGenerator::global()->bounded(fortunes.size())];

L’objectif de ce slot est de sélectionner une ligne aléatoire dans notre liste de citations, de l’encoder en un QByteArray à l’aide de QDataStream, puis de l’écrire sur le socket de connexion. Il s’agit d’une méthode courante pour transférer des données binaires à l’aide de QTcpSocket. Nous créons d’abord un objet QByteArray et un objet QDataStream, en transmettant le bytearray au constructeur de QDataStream. Nous définissons ensuite explicitement la version du protocole de QDataStream sur QDataStream::Qt_5_10 afin de garantir la compatibilité avec les clients des futures versions de Qt (voir QDataStream::setVersion()). Nous poursuivons en transmettant en continu une citation aléatoire.

    QTcpSocket *clientConnection = tcpServer->nextPendingConnection();
    connect(clientConnection, &QAbstractSocket::disconnected,
            clientConnection, &QObject::deleteLater);

Nous appelons ensuite ` QTcpServer::nextPendingConnection()`, qui renvoie l’objet ` QTcpSocket ` représentant le côté serveur de la connexion. En reliant ` QTcpSocket::disconnected()` à ` QObject::deleteLater()`, nous nous assurons que le socket sera supprimé après la déconnexion.

    clientConnection->write(block);
    clientConnection->disconnectFromHost();
}

La citation codée est écrite à l’aide de ` QTcpSocket::write()`, puis nous appelons enfin ` QTcpSocket::disconnectFromHost()`, qui fermera la connexion une fois que ` QTcpSocket ` aura fini d’écrire la citation sur le réseau. Comme ` QTcpSocket ` fonctionne de manière asynchrone, les données seront écrites après le retour de cette fonction, et le contrôle reviendra à la boucle d’événements de Qt. Le socket se fermera alors, ce qui entraînera sa suppression par la fonction QObject::deleteLater().

Exemple de projet sur code.qt.io

Voir également Client Fortune et Serveur Fortune multithread.

© 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.