福星服务器

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

此示例意在与福星客户端示例或阻塞式福星客户端示例一起运行。

Screenshot of the Fortune Server example

它使用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()));

在其构造函数中,我们的 Server 对象调用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对象,并将 bytearray 传递给QDataStream的构造函数。然后我们显式设置QDataStream的协议版本为QDataStream::Qt_5_10,以确保我们可以与来自 Qt 未来版本的客户端进行通信(见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

另请参阅福布斯客户端线程福布斯服务器.

© 2024 Qt公司期权有限公司。本文件中包含的文档贡献由各自所有者拥有版权。本文件提供的文档是根据自由软件基金会发布的GNU自由文档许可协议版1.3的条款许可的。Qt及其相关标志是芬兰及其它国家和地区Qt公司有限责任公司的商标。所有其他商标均为其各自所有者的财产。