多线程福布斯服务器
Threaded Fortune Server示例展示了如何创建一个简单网络服务的服务器,该服务使用线程处理不同客户端的请求。它旨在与Fortune Client示例一起运行。
本示例的实现与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的构造函数只是简单地存储套接字描述符和祝福语文本,以便它们可以在稍后的run()中使用。
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;
与Fortune Server示例类似,我们使用QDataStream将祝福语编码到QByteArray中。
tcpSocket.write(block); tcpSocket.disconnectFromHost(); tcpSocket.waitForDisconnected(); }
但与上一个示例不同,我们最后调用QTcpSocket::waitForDisconnected,这将阻塞调用线程直到套接字断开连接。因为我们在一个分离的线程中运行,所以GUI将保持响应。
© 2024 The Qt Company Ltd. 本文件中包含的文档贡献均为各自所有者的版权。本文档根据自由软件基金会发布的GNU自由文档许可协议版本1.3的条款进行许可。Qt及其相关标志是芬兰以及全球其他国家的The Qt Company Ltd的商标。所有其他商标均为其各自所有者的财产。