>>>
QTcpServer
是 Qt 网络模块中的一个类,用于实现TCP服务器。它允许创建一个服务器,可以接受来自客户端的连接。QTcpServer
是事件驱动的,这意味着它将通过信号和槽机制处理网络事件。 常用函数
QTcpServer(QObject *parent = nullptr)
: 创建一个 QTcpServer
对象。bool listen(const QHostAddress &address, quint16 port)
: 在指定的地址和端口上监听传入的连接。返回值表示监听是否成功。bool isListening() const
: 检查服务器是否正在监听。void close()
: 停止服务器,并关闭所有活动的连接。QTcpSocket *nextPendingConnection()
: 返回下一个待处理的客户端连接(如果有的话)。每次调用后,会将已处理的连接移除。void newConnection()
: 当有新的连接请求时发出此信号。可以连接到一个槽以处理新连接。QList<QTcpSocket*> findChildren< QTcpSocket* >() const
: 获取所有与服务器相关的活动的客户端连接。int maxPendingConnections() const
: 获取允许的最大挂起连接数。incomingConnection(qintptr socketDescriptor)
是 QTcpServer
类中的一个虚拟函数,用于处理新的客户端连接。当服务器接收到新的连接请求时,这个函数会被调用,并传递一个 socketDescriptor
参数,该参数是一个整型值,用于唯一标识新连接的套接字>>>
QTcpSocket
是 Qt 网络模块中的一个类,用于实现网络通信中的 TCP 客户端功能。通过QTcpSocket
,开发者可以方便地与服务器进行数据交换,实现网络应用。以下是QTcpSocket
的一些主要特性和功能:
write()
方法发送数据,通过 read()
或 readAll()
方法接收数据。QTcpSocket
提供了许多信号(例如 connected()
、disconnected()
、readyRead()
等),可以与 Qt 的信号与槽机制结合使用,实现事件驱动的通信。errorOccurred()
信号提示用户发生了什么错误,并提供获取错误信息的方法。QTcpSocket
可以与 QSslSocket
一起使用,支持加密的数据传输。>>>
QThread
提供了一种简单的方式来管理线程的生命周期,包括启动、停止和退出线程。QThread
支持 Qt 的信号与槽机制,允许线程之间进行通信。QObject
派生类的对象移动到线程中,从而使对象在不同的线程上下文中执行。QThread
支持事件循环,可以在独立线程中处理事件,如 GUI 更新或网络事件。常用函数
QThread(QObject *parent = nullptr)
:构造一个 QThread
对象。void start()
:启动线程运行,调用 run()
方法。void quit()
:请求线程退出事件循环。void wait(unsigned long timeout = 0)
:等待线程结束,直到线程完全退出。virtual void run()
:重载此方法来定义线程执行的代码。void moveToThread(QThread *thread)
:将 QObject
派生的对象移动到指定线程中。QThread::currentThread()
:返回当前执行线程的指针。bool isRunning() const
:判断线程是否在运行状态。bool isFinished() const
:判断线程是否已完成执行。void finished()
:线程完成时发出此信号。void started()
:线程启动时发出此信号。>>>
# 设置 CMake 的最低版本要求cmake_minimum_required(VERSION 3.16)# 定义项目名称和支持的语言c++project(threadedfortuneserver LANGUAGES CXX)# 如果没有定义安装目录,则设置默认安装目录if(NOT DEFINED INSTALL_EXAMPLESDIR) set(INSTALL_EXAMPLESDIR "examples")endif()# 设置安装示例的子目录set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/network/threadedfortuneserver")# 查找所需的 Qt 组件find_package(Qt6 REQUIRED COMPONENTS Core Gui Network Widgets)# 设置 Qt 项目的标准配置qt_standard_project_setup()# 添加可执行文件,指定源文件qt_add_executable(threadedfortuneserver dialog.cpp dialog.h # 对话框相关的源文件 fortuneserver.cpp fortuneserver.h # 幸运服务器相关的源文件 fortunethread.cpp fortunethread.h # 幸运线程相关的源文件 main.cpp # 主程序文件)# 设置目标属性set_target_properties(threadedfortuneserver PROPERTIES WIN32_EXECUTABLE TRUE # 在 Windows 系统下创建 Windows 可执行文件 MACOSX_BUNDLE TRUE # 在 MacOS 系统下创建应用程序包)# 链接 Qt 库target_link_libraries(threadedfortuneserver PRIVATE Qt6::Core # 链接 Qt Core 模块 Qt6::Gui # 链接 Qt GUI 模块 Qt6::Network # 链接 Qt 网络模块 Qt6::Widgets # 链接 Qt Widgets 模块)# 安装目标install(TARGETS threadedfortuneserver RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" # 可执行文件安装目录 BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" # 应用程序包安装目录 LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" # 动态库安装目录)
>>>dialog.h
#ifndef DIALOG_H // 检查 DIALOG_H 是否被定义#define DIALOG_H // 定义 DIALOG_H,以防止重复包含头文件#include <QWidget> // 引入 Qt 的 QWidget 类#include "fortuneserver.h" // 引入自定义的 fortuneserver 头文件QT_BEGIN_NAMESPACE // 开始命名空间class QLabel; // 前向声明 QLabel 类class QPushButton; // 前向声明 QPushButton 类QT_END_NAMESPACE // 结束命名空间// Dialog 类,继承自 QWidgetclass Dialog : public QWidget{ Q_OBJECT // 声明该类是 Qt 的一个对象,支持信号和槽机制public: // 构造函数,接收一个 QWidget 指针作为父窗口,默认为 nullptr Dialog(QWidget *parent = nullptr);private: QLabel *statusLabel; // 状态标签指针,用于显示状态信息 QPushButton *quitButton; // 退出按钮指针,用于退出应用 TcpServer server; // TcpServer 对象,用于处理 TCP 连接};#endif // 结束 DIALOG_H 的条件编译
>>>dialog.cpp
#include <QtWidgets> // 引入Qt Widgets模块#include <QtNetwork> // 引入Qt Network模块#include <stdlib.h> // 引入标准库,以使用常见的功能#include "dialog.h" // 引入Dialog类的头文件#include "fortuneserver.h" // 引入Fortune Server类的头文件// Dialog类的构造函数Dialog::Dialog(QWidget *parent) : QWidget(parent) // 调用基类QWidget的构造函数,并传递父窗口参数{ statusLabel = new QLabel; // 创建一个新的QLabel用于显示状态信息 statusLabel->setWordWrap(true); // 启用状态标签的自动换行 quitButton = new QPushButton(tr("Quit")); // 创建一个带有“Quit”文本的退出按钮 quitButton->setAutoDefault(false); // 禁用按钮的自动默认行为 // 尝试启动服务器 if (!server.listen()) { // 如果服务器启动失败,则显示严重错误信息 QMessageBox::critical(this, tr("Qt 历险记 qq交流:906134236"), tr("无法启动服务器: %1.") .arg(server.errorString())); close(); // 关闭对话框 return; // 退出构造函数 } QString ipAddress; // 变量用于存储IP地址 const QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses(); // 获取所有网络地址 // 使用第一个非localhost的IPv4地址 for (const QHostAddress &entry : ipAddressesList) { if (entry != QHostAddress::LocalHost && entry.toIPv4Address()) { // 检查是否为非localhost且是有效的IPv4 ipAddress = entry.toString(); // 存储IP地址 break; // 找到后退出循环 } } // 如果没有找到,使用IPv4 localhost if (ipAddress.isEmpty()) ipAddress = QHostAddress(QHostAddress::LocalHost).toString(); // 如果没有找到非localhost,则设置为localhost // 设置状态标签的文本,显示服务器信息 statusLabel->setText(tr("服务器正在运行\n\nIP: %1\n端口号: %2\n\n" "现在运行tcp服务器示例。") .arg(ipAddress).arg(server.serverPort())); // 将退出按钮的clicked信号连接到对话框的close槽 connect(quitButton, &QPushButton::clicked, this, &Dialog::close); // 创建一个水平布局用于按钮 QHBoxLayout *buttonLayout = new QHBoxLayout; buttonLayout->addStretch(1); // 在按钮前添加可伸缩空间 buttonLayout->addWidget(quitButton); // 将退出按钮添加到布局中 buttonLayout->addStretch(1); // 在按钮后添加可伸缩空间 // 创建一个垂直布局用于主窗口 QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addWidget(statusLabel); // 将状态标签添加到主布局中 mainLayout->addLayout(buttonLayout); // 将按钮布局添加到主布局中 setLayout(mainLayout); // 设置对话框的主布局 setWindowTitle(tr("Qt 历险记 qq交流:906134236")); // 设置窗口标题}
>>>fortuneserver.h
#ifndef FORTUNESERVER_H // 确保该头文件只被包含一次#define FORTUNESERVER_H#include <QStringList> // 引入 QStringList,用于存储字符串列表#include <QTcpServer> // 引入 QTcpServer 类,用于处理 TCP 服务器功能// 定义 TcpServer 类,继承自 QTcpServerclass TcpServer : public QTcpServer{ Q_OBJECT // 表示该类包含 Qt 的信号和槽机制public: // 构造函数,接收一个 QObject 指针作为父对象,默认为 nullptr TcpServer(QObject *parent = nullptr);protected: // 重写 incomingConnection 方法,用于处理新的连接 void incomingConnection(qintptr socketDescriptor) override;private: QStringList fortunes; // 用于存储“运势”字符串的列表};#endif // 结束条件编译指令
>>>fortuneserver.cpp
#include "fortuneserver.h" // 引入自定义的 FortuneServer 头文件#include "fortunethread.h" // 引入自定义的 FortuneThread 头文件#include <QRandomGenerator> // 引入 Qt 随机数生成器#include <stdlib.h> // 引入标准库头文件// TcpServer 类构造函数TcpServer::TcpServer(QObject *parent) : QTcpServer(parent) // 调用基类 QTcpServer 的构造函数并传递父对象{ // 初始化 fortune 列表,存储不同的命运消息(字符串) fortunes << tr("你过着狗一样的生活。别上家具。") << tr("你必须考虑明天。") << tr("你会被一声巨响惊讶。") << tr("再过一个小时你会感到饿。") << tr("你可能有邮件。") << tr("你不能在不伤害永恒的情况下消磨时间。") << tr("计算机并不聪明。它们只是认为自己聪明。");}// 当有新的连接请求时的处理函数void TcpServer::incomingConnection(qintptr socketDescriptor){ // 随机选择一个命运消息 QString fortune = fortunes.at(QRandomGenerator::global()->bounded(fortunes.size())); // 创建一个新的 TcpSocketThread 线程对象,处理该连接 TcpSocketThread *thread = new TcpSocketThread(socketDescriptor, fortune, this); // 连接线程的 finished 信号和 deleteLater 槽,以在线程完成后自动删除对象 connect(thread, &TcpSocketThread::finished, thread, &TcpSocketThread::deleteLater); // 启动线程 thread->start();}
>>>fortunethread.h
#ifndef FORTUNETHREAD_H // 如果没有定义 FORTUNETHREAD_H#define FORTUNETHREAD_H // 定义 FORTUNETHREAD_H#include <QThread> // 引入 QThread 头文件#include <QTcpSocket> // 引入 QTcpSocket 头文件// TcpSocketThread 类,继承自 QThreadclass TcpSocketThread : public QThread{ Q_OBJECT // 宏,支持信号和槽机制public: // 构造函数,接受 socket 描述符和命运消息 TcpSocketThread(qintptr socketDescriptor, const QString &fortune, QObject *parent); // 重写 run() 方法,线程执行的入口 void run() override;signals: // 定义一个信号,用于报告错误 void error(QTcpSocket::SocketError socketError);private: qintptr socketDescriptor; // 保存 socket 描述符 QString text; // 保存命运消息};#endif // 结束条件
>>>fortunethread.cpp
#include "fortunethread.h" // 引入自定义头文件 fortunethread.h#include <QtNetwork> // 引入Qt网络模块// TcpSocketThread 类的构造函数TcpSocketThread::TcpSocketThread(qintptr socketDescriptor, const QString &fortune, QObject *parent) : QThread(parent), socketDescriptor(socketDescriptor), text(fortune){ // 初始化线程,保存套接字描述符和要发送的文本信息}// 重写 run() 方法,线程执行的主要逻辑void TcpSocketThread::run(){ QTcpSocket tcpSocket; // 创建 TCP 套接字对象 // 设置套接字描述符,如果失败则发出错误信号并返回 if (!tcpSocket.setSocketDescriptor(socketDescriptor)) { emit error(tcpSocket.error()); return; } QByteArray block; // 创建一个 QByteArray 用于存储要发送的数据 QDataStream out(&block, QIODevice::WriteOnly); // 创建数据流对象,使用只写模式 out.setVersion(QDataStream::Qt_6_5); // 设置数据流版本 out << text; // 将文本信息写入数据流 tcpSocket.write(block); // 将数据块写入套接字 tcpSocket.disconnectFromHost(); // 断开与主机的连接 tcpSocket.waitForDisconnected(); // 等待断开连接}
>>>
#include <QApplication>#include <QtCore>#include <stdlib.h>#include "dialog.h"int main(int argc, char *argv[]){ QApplication app(argc, argv); Dialog dialog; dialog.show(); return app.exec();}
>>>23种设计模式一网打尽。 项目源码获取,记得转存慢慢看。 通过网盘分享的文件:threadedfortuneserver 链接: https://pan.baidu.com/s/1vy4w2RWfQBBYoffurzZZiw?pwd=hr99 提取码: hr99
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。