财富服务器

演示如何为网络服务创建服务器。

本示例旨在与财富客户端示例或阻塞财富客户端示例同时运行。

财富服务器示例截图

它使用QTcpServer 接受传入的 TCP 连接,并使用基于QDataStream 的简单数据传输协议向连接的客户端(来自富贵客户端示例)写入富贵,然后关闭连接。

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;
};

服务器使用一个只有一个插槽的简单类来实现,用于处理传入的连接。

    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()));

在构造函数中,我们的服务器对象会调用QTcpServer::listen() 来设置QTcpServer ,以便在任意端口上监听所有地址。然后在标签中显示QTcpServer 选定的端口,以便用户知道财富客户端应该连接到哪个端口。

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

我们的服务器会生成一个随机运势列表,发送给连接的客户端。

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

当客户端连接到我们的服务器时,QTcpServer 将发出QTcpServer::newConnection() 。反过来,这将调用我们的 sendFortune() 槽:

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

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

这个槽的目的是从我们的财富列表中随机选择一行,使用QDataStream 将其编码为QByteArray ,然后写入连接的套接字。这是使用QTcpSocket 传输二进制数据的常用方法。首先,我们创建一个QByteArray 和一个QDataStream 对象,将字节数组传递给QDataStream 的构造函数。然后,我们显式地将QDataStream 的协议版本设置为QDataStream::Qt_5_10 ,以确保我们能与未来版本的 Qt XML 客户端通信(请参阅QDataStream::setVersion() )。我们继续以流方式输入随机财富。

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

然后,我们调用QTcpServer::nextPendingConnection() 返回代表连接服务器端的QTcpSocket 。通过将QTcpSocket::disconnected() 连接到QObject::deleteLater() ,我们可以确保套接字在断开连接后被删除。

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

我们使用QTcpSocket::write() 写入已编码的财富值,最后调用QTcpSocket::disconnectFromHost() ,在QTcpSocket 完成向网络写入财富值后关闭连接。由于QTcpSocket 是异步工作的,因此数据将在该函数返回后写入,控制权回到 Qt 的事件循环。然后,套接字将关闭,进而导致QObject::deleteLater() 删除套接字。

示例项目 @ code.qt.io

另请参阅 " 财富客户端 ""线程财富服务器"。

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