线程财富服务器
Threaded Fortune Server 示例展示了如何为简单的网络服务创建服务器,该服务使用线程处理来自不同客户端的请求。本示例旨在与富勤客户端示例同时运行。
本示例的实现与富勤服务器示例类似,但在这里我们将实现一个QTcpServer 的子类,它可以在不同的线程中启动每个连接。
为此,我们需要两个类:FortuneServer 是QTcpServer 的子类,FortuneThread 继承于QThread 。
class FortuneServer : public QTcpServer { Q_OBJECT public: FortuneServer(QObject *parent = nullptr); protected: void incomingConnection(qintptr socketDescriptor) override; private: QStringList fortunes; };
FortuneServer 继承了QTcpServer 并重新实现了QTcpServer::incomingConnection() 。我们还用它来存储随机财富列表。
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."); }
我们使用 FortuneServer 的构造函数简单地生成财富列表。
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(); }
我们对QTcpServer::incomingConnection() 的实现是创建一个 FortuneThread 对象,将传入的套接字描述符和随机幸运值传递给 FortuneThread 的构造函数。通过将 FortuneThread 的 finished() 信号连接到QObject::deleteLater() ,我们可以确保线程一旦结束就会被删除。然后我们就可以调用QThread::start() 来启动线程了。
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; };
接下来是 FortuneThread 类,它是QThread 的子类,任务是将财富信息写入连接的套接字。该类重新实现了QThread::run() ,并有一个报错信号。
FortuneThread::FortuneThread(qintptr socketDescriptor, const QString &fortune, QObject *parent) : QThread(parent), socketDescriptor(socketDescriptor), text(fortune) { }
FortuneThread 的构造函数只需存储套接字描述符和财富文本,以便稍后运行()时使用。
void FortuneThread::run() { QTcpSocket tcpSocket;
我们的 run() 函数要做的第一件事就是在堆栈上创建一个QTcpSocket 对象。值得注意的是,我们是在线程内创建该对象,这会自动将套接字与线程的事件循环关联起来。这确保了当我们通过 FortuneThread::run() 访问套接字时,Qt 不会尝试从主线程向套接字发送事件。
if (!tcpSocket.setSocketDescriptor(socketDescriptor)) { emit error(tcpSocket.error()); return; }
通过调用QTcpSocket::setSocketDescriptor() 并将套接字描述符作为参数传递,套接字被初始化。我们希望这样做会成功,但为了确保万无一失(虽然可能性不大,但系统可能会耗尽资源),我们会捕捉返回值并报告任何错误。
QByteArray block; QDataStream out(&block, QIODevice::WriteOnly); out.setVersion(QDataStream::Qt_6_5); out << text;
与财富服务器示例一样,我们使用QDataStream 将财富编码为QByteArray 。
tcpSocket.write(block); tcpSocket.disconnectFromHost(); tcpSocket.waitForDisconnected(); }
但与前一个示例不同的是,我们最后会调用QTcpSocket::waitForDisconnected() 来阻塞调用线程,直到套接字断开连接。由于我们是在单独的线程中运行,因此图形用户界面将保持响应。
© 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.