>>>
QTcpSocket
是Qt框架中的一个类,用于实现TCP网络通信。它提供了与TCP服务器的连接功能,并允许发送和接收数据。QTcpSocket
是继承自QAbstractSocket
的,因此它具有许多网络套接字的基本功能。 QTcpSocket的主要功能
QSslSocket
进行SSL加密的TCP通信。常用函数
以下是QTcpSocket
的一些常用函数:
QTcpSocket(QObject *parent = nullptr)
: 构造函数。~QTcpSocket()
: 析构函数。void connectToHost(const QString &hostName, quint16 port)
: 连接到指定的主机和端口。void disconnectFromHost()
: 断开与主机的连接。qint64 write(const QByteArray &data)
: 发送数据到远程主机。void readAll()
: 读取所有可用的数据。QByteArray read(qint64 maxSize = 0)
: 读取指定大小的数据。QAbstractSocket::SocketState state() const
: 获取当前套接字的状态。QString errorString() const
: 获取错误信息。void connected()
: 当成功连接到主机时发出此信号。void disconnected()
: 当与主机断开连接时发出此信号。void readyRead()
: 当有新数据可读时发出此信号。void errorOccurred(QAbstractSocket::SocketError socketError)
: 当出现错误时发出此信号。>>>
QDataStream
是Qt框架中的一个类,主要用于在Qt中以流的方式读写二进制数据。它可以处理多种数据类型,如整型、浮点型、字符串等,并且支持对数据的序列化和反序列化。QDataStream
通常与QFile
、QTcpSocket
等类一起使用,以便于文件和网络通信中的数据操作。 QDataStream的主要功能
常用函数
以下是QDataStream
的一些常用函数:
QDataStream(QIODevice *device)
: 创建一个数据流对象,关联到指定的设备(如文件、套接字等)。QDataStream(const QByteArray &array, QIODevice::OpenMode mode = QIODevice::ReadOnly)
: 从字节数组创建数据流。QDataStream &operator<<(const QString &str)
: 将字符串写入数据流。QDataStream &operator<<(int i)
: 将整型数据写入数据流。QDataStream &operator<<(double d)
: 将浮点型数据写入数据流。QDataStream &operator<<(const QByteArray &ba)
: 将字节数组写入数据流。QDataStream &operator<<(const QVariant &var)
: 将变体值写入数据流。QDataStream &operator>>(QString &str)
: 从数据流中读取字符串。QDataStream &operator>>(int &i)
: 从数据流中读取整型数据。QDataStream &operator>>(double &d)
: 从数据流中读取浮点型数据。QDataStream &operator>>(QByteArray &ba)
: 从数据流中读取字节数组。QDataStream &operator>>(QVariant &var)
: 从数据流中读取变体值。bool atEnd() const
: 判断是否到达流的末尾。void setVersion(QDataStream::Version version)
: 设置数据流版本。QDataStream::Version version() const
: 获取当前数据流版本。QDataStream &operator>>(QDataStream &stream)
: 将数据流对象复制到另一个数据流。>>>
cmake_minimum_required(VERSION 3.16) # 设置 CMake 的最低版本要求为 3.16project(fortuneclient LANGUAGES CXX) # 定义项目名称为 fortuneclient,并指定使用的语言为 C++# 如果没有定义 INSTALL_EXAMPLESDIR,则设置其默认值为 "examples"if(NOT DEFINED INSTALL_EXAMPLESDIR) set(INSTALL_EXAMPLESDIR "examples")endif()# 设置安装示例的目录set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/network/fortuneclient")# 查找 Qt6 必需的模块,包括 Core、Gui、Network 和 Widgetsfind_package(Qt6 REQUIRED COMPONENTS Core Gui Network Widgets)# 配置 Qt 标准项目设置qt_standard_project_setup()# 添加可执行文件 fortuneclient,并指定其源文件qt_add_executable(fortuneclient client.cpp client.h # 客户端的源文件 main.cpp # 主程序的源文件)# 设置可执行文件的属性,使其在 Windows 和 macOS 上为特定类型set_target_properties(fortuneclient PROPERTIES WIN32_EXECUTABLE TRUE # 设置为 Windows 下的 GUI 应用程序 MACOSX_BUNDLE TRUE # 设置为 macOS 下的应用程序包)# 链接需要的 Qt 库target_link_libraries(fortuneclient PRIVATE Qt6::Core # 链接 Qt6 Core 模块 Qt6::Gui # 链接 Qt6 Gui 模块 Qt6::Network # 链接 Qt6 Network 模块 Qt6::Widgets # 链接 Qt6 Widgets 模块)# 安装可执行文件及其资源install(TARGETS fortuneclient RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" # 可执行文件安装位置 BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" # 应用程序包安装位置 LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" # 库文件安装位置) |
---|
>>>client.h
#ifndef CLIENT_H // 如果没有定义 CLIENT_H,则包含以下内容#define CLIENT_H#include <QDataStream> // 引入 QDataStream 类,用于数据流的读写#include <QDialog> // 引入 QDialog 基类,用于创建对话框#include <QTcpSocket> // 引入 QTcpSocket 类,用于 TCP 网络通信QT_BEGIN_NAMESPACE // Qt 命名空间的开始class QComboBox; // 前向声明 QComboBox 类class QLabel; // 前向声明 QLabel 类class QLineEdit; // 前向声明 QLineEdit 类class QPushButton; // 前向声明 QPushButton 类class QTcpSocket; // 再次前向声明 QTcpSocket 类QT_END_NAMESPACE // Qt 命名空间的结束// 定义 Client 类,继承自 QDialogclass Client : public QDialog{ Q_OBJECT // 宏,标记该类为 Qt 的元对象系统的一部分public: explicit Client(QWidget *parent = nullptr); // 构造函数,接受父 Widget 指针private slots: void requestNewFortune(); // 请求新的财富(数据) void readFortune(); // 读取财富数据 void displayError(QAbstractSocket::SocketError socketError); // 显示 socket 错误 void enableGetFortuneButton(); // 启用获取财富的按钮private: QComboBox *hostCombo = nullptr; // 主机下拉框指针 QLineEdit *portLineEdit = nullptr; // 端口输入框指针 QLabel *statusLabel = nullptr; // 状态标签指针 QPushButton *getFortuneButton = nullptr; // 获取财富按钮指针 QTcpSocket *tcpSocket = nullptr; // TCP 套接字指针 QDataStream in; // 输入数据流 QString currentFortune; // 当前财富字符串};#endif // 结束条件,避免重复包含
>>>
/*
* 提示:该行代码过长,系统自动注释不进行高亮。一键复制会移除系统注释
* #include <QtWidgets> // 引入 Qt Widgets 模块#include <QtNetwork> // 引入 Qt Network 模块#include "client.h" // 引入 Client 类的头文件//! [0]Client::Client(QWidget *parent) // Client 类的构造函数 : QDialog(parent) // 调用 QDialog 的构造函数,设置父窗口 , hostCombo(new QComboBox) // 创建一个新的 QComboBox 用于选择主机 , portLineEdit(new QLineEdit) // 创建一个新的 QLineEdit 用于输入端口 , getFortuneButton(new QPushButton(tr("获取财富"))) // 创建获取财富按钮,按钮文本为“获取财富” , tcpSocket(new QTcpSocket(this)) // 创建一个新的 TCP 套接字{ //! [0] hostCombo->setEditable(true); // 使主机下拉框可编辑 // 找出这台机器的名称 QString name = QHostInfo::localHostName(); // 获取本地主机名 if (!name.isEmpty()) { hostCombo->addItem(name); // 将主机名添加到下拉框 QString domain = QHostInfo::localDomainName(); // 获取本地主机的域名 if (!domain.isEmpty()) hostCombo->addItem(name + QChar('.') + domain); // 将域名添加到下拉框 } if (name != QLatin1String("localhost")) hostCombo->addItem(QString("localhost")); // 如果不是 localhost,则添加 localhost // 找出这台机器的 IP 地址 const QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses(); // 获取所有地址 // 添加非本地主机地址 for (const QHostAddress &entry : ipAddressesList) { // 遍历所有地址 if (!entry.isLoopback()) // 如果不是回环地址 hostCombo->addItem(entry.toString()); // 将地址添加到下拉框 } // 添加本地主机地址 for (const QHostAddress &entry : ipAddressesList) { if (entry.isLoopback()) // 如果是回环地址 hostCombo->addItem(entry.toString()); // 将地址添加到下拉框 } portLineEdit->setValidator(new QIntValidator(1, 65535, this)); // 设置端口输入框的有效值为 1 到 65535 auto hostLabel = new QLabel(tr("&服务器名称:")); // 创建服务器名称标签 hostLabel->setBuddy(hostCombo); // 将标签与下拉框关联 auto portLabel = new QLabel(tr("服务&器端口:")); // 创建服务器端口标签 portLabel->setBuddy(portLineEdit); // 将标签与端口输入框关联 statusLabel = new QLabel(tr("本示例需要您同时运行 " "财富服务器示例。")); // 创建状态标签,提示需要运行 Fortune 服务器 getFortuneButton->setDefault(true); // 设置获取财富按钮为默认按钮 getFortuneButton->setEnabled(false); // 初始时禁用获取财富按钮 auto quitButton = new QPushButton(tr("退出")); // 创建退出按钮 auto buttonBox = new QDialogButtonBox; // 创建对话框按钮框 buttonBox->addButton(getFortuneButton, QDialogButtonBox::ActionRole); // 添加获取财富按钮 buttonBox->addButton(quitButton, QDialogButtonBox::RejectRole); // 添加退出按钮 //! [1] in.setDevice(tcpSocket); // 设置数据流的设备为 TCP 套接字 in.setVersion(QDataStream::Qt_6_5); // 设置数据流版本 //! [1] // 连接信号与槽 connect(hostCombo, &QComboBox::editTextChanged, this, &Client::enableGetFortuneButton); // 当主机名改变时,启用获取财富按钮 connect(portLineEdit, &QLineEdit::textChanged, this, &Client::enableGetFortuneButton); // 当端口文本改变时,启用获取财富按钮 connect(getFortuneButton, &QAbstractButton::clicked, this, &Client::requestNewFortune); // 当获取财富按钮被点击时,发送请求 connect(quitButton, &QAbstractButton::clicked, this, &QWidget::close); // 当退出按钮被点击时,关闭窗口 //! [2] //! [3] connect(tcpSocket, &QIODevice::readyRead, this, &Client::readFortune); // 当 TCP 套接字准备好读取数据时,读取财富 //! [2] //! [4] connect(tcpSocket, &QAbstractSocket::errorOccurred, this, &Client::displayError); // 当发生错误时,显示错误信息 //! [4] QGridLayout *mainLayout = nullptr; // 主布局指针 // 判断应用程序的显示样式 if (QGuiApplication::styleHints()->showIsFullScreen() || QGuiApplication::styleHints()->showIsMaximized()) { auto outerVerticalLayout = new QVBoxLayout(this); // 创建垂直布局 outerVerticalLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::MinimumExpanding)); // 添加空隙 auto outerHorizontalLayout = new QHBoxLayout; // 创建水平布局 outerHorizontalLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::MinimumExpanding, QSizePolicy::Ignored)); // 添加空隙 auto groupBox = new QGroupBox(QGuiApplication::applicationDisplayName()); // 创建分组框 mainLayout = new QGridLayout(groupBox); // 在分组框中创建网格布局 outerHorizontalLayout->addWidget(groupBox); // 将分组框添加到水平布局 outerHorizontalLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::MinimumExpanding, QSizePolicy::Ignored)); // 添加空隙 outerVerticalLayout->addLayout(outerHorizontalLayout); // 将水平布局添加到垂直布局 outerVerticalLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::MinimumExpanding)); // 添加空隙 } else { mainLayout = new QGridLayout(this); // 默认创建网格布局 } // 将控件添加到主布局中 mainLayout->addWidget(hostLabel, 0, 0); // 添加服务器名称标签 mainLayout->addWidget(hostCombo, 0, 1); // 添加服务器名称下拉框 mainLayout->addWidget(portLabel, 1, 0); // 添加服务器端口标签 mainLayout->addWidget(portLineEdit, 1, 1); // 添加服务器端口输入框 mainLayout->addWidget(statusLabel, 2, 0, 1, 2); // 添加状态标签 mainLayout->addWidget(buttonBox, 3, 0, 1, 2); // 添加按钮框 setWindowTitle(QGuiApplication::applicationDisplayName()); // 设置窗口标题 portLineEdit->setFocus(); // 设置端口输入框为焦点 //! [5]}//! [5]//! [6]void Client::requestNewFortune() // 请求新的财富{ getFortuneButton->setEnabled(false); // 禁用获取财富按钮 tcpSocket->abort(); // 取消当前连接 //! [7] tcpSocket->connectToHost(hostCombo->currentText(), // 连接到指定主机 portLineEdit->text().toInt()); // 连接到指定端口 //! [7]}//! [6]//! [8]void Client::readFortune() // 读取财富数据{ qDebug() << "Incoming data size:" << tcpSocket->bytesAvailable(); QByteArray rawData = tcpSocket->readAll(); // 读取所有可用数据 qDebug() << "Raw data:" << rawData; // 打印原始数据 in.startTransaction(); // 开始事务 QString nextFortune; // 存储下一个财富 in >> nextFortune; // 从数据流中读取财富数据 qDebug() << "nextFortune = " << nextFortune.toUtf8(); if (!in.commitTransaction()) // 提交事务 return; if (nextFortune == currentFortune) { // 如果读取到的财富与当前财富相同 QTimer::singleShot(0, this, &Client::requestNewFortune); // 立即请求新的财富 return; } currentFortune = nextFortune; // 更新当前财富 statusLabel->setText(currentFortune); // 显示当前财富 getFortuneButton->setEnabled(true); // 启用获取财富按钮}//! [8]//! [13]void Client::displayError(QAbstractSocket::SocketError socketError) // 显示错误信息{ switch (socketError) { case QAbstractSocket::RemoteHostClosedError: // 远程主机关闭错误 break; case QAbstractSocket::HostNotFoundError: // 主机未找到错误 QMessageBox::information(this, tr("财富客户端"), // 弹出信息框 tr("未找到主机。请检查 " "主机名和端口设置。")); break; case QAbstractSocket::ConnectionRefusedError: // 连接被拒绝错误 QMessageBox::information(this, tr("财富客户端"), tr("连接被对方拒绝。" "请确保财富服务器正在运行," "并检查主机名和端口设置是否正确。")); break; default: // 其它错误 QMessageBox::information(this, tr("财富客户端"), tr("发生了以下错误: %1.") .arg(tcpSocket->errorString())); // 显示错误信息 } getFortuneButton->setEnabled(true); // 启用获取财富按钮}//! [13]void Client::enableGetFortuneButton() // 启用获取财富按钮{ getFortuneButton->setEnabled(!hostCombo->currentText().isEmpty() && // 只有当主机名和端口不为空时,才启用按钮 !portLineEdit->text().isEmpty());}
*/
>>>
#include <QApplication>#include "client.h"int main(int argc, char *argv[]){ QApplication app(argc, argv); QApplication::setApplicationDisplayName(Client::tr("Qt 历险记 qq:906134236")); Client client; client.show(); return app.exec();}
>>>通过网盘分享的文件:fortuneclient 链接: https://pan.baidu.com/s/1HZlcnzmdRDvUUsDQN-QDDw?pwd=ypkq 提取码: ypkq
>>>
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。