【Qt】网络

【Qt】网络

🌈 个人主页:Zfox_
🔥 系列专栏:Qt

目录

一:🔥 Qt 网络概述

和多线程类似, Qt 为了支持跨平台,对网络编程的 API 也进行了重新封装.

💡注意:

实际 Qt 开发中进行网络编程,也不一定使用 Qt 封装的网络 API,也有一定可能使用的是系统原生 API 或者其他第三方框架的 API.

在进行网络编程之前,需要在项目中的 .pro 文件 中添加 network 模块,

  • 添加之后要手动编译一下项目,使 Qt Creator 能够加载对应模块的头文件

二:🔥 UDP Socket

主要的类就两个:QUdpSocketQNetworkDatagram

QUdpSocket 表示一个 UDP 的 socket 文件

名称类型说明对标原生 API
bind(const QHostAddress&, quint16)方法绑定指定端口号bind
receiveDatagram()方法返回 QNetworkDatagram ,读取一个 UDP 数据报recvfrom
writeDatagram(const QNetworkDatagram&)方法发送一个 UDP 数据报sendto
readyRead信号在收到数据并准备就绪后触发无(类似于 IO 多路复用的通知机制)

readyRead :当 socket 收到请求的时候,QUdpSocket 就会触发这个信号,此时就可以在槽函数中完成读取请求的操作了

基于信号槽,就天然达成了 事件驱动 的效果

QNetworkDatagram 表示一个 UDP 数据报

名称类型说明对标原生 API
QNetworkDatagram(const QByteArray&, const QHostAddress&, quint16)构造函数通过 QByteArray,目标 IP 地址,目标端口号 构造一个 UDP 数据报,通常用于发送数据时
data()方法获取数据报内部持有的数据,返回 QByteArray
senderAddress()方法获取数据报中包含的对端的 IP 地址无,recvfrom 包含了该功能
senderPort()方法获取数据报中包含的对端的端口号无,recvfrom 包含了该功能

🦋 代码示例

回显服务器

1)创建界面,包含一个 QListWidget 用来显示消息

image-20250313131823857

2)创建 QUdpSocket 成员

修改 widget.h

class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private: Ui::Widget *ui; QUdpSocket* socket; }; 

修改 widget.cpp,完成 socket 后续的初始化

一般来说,要先连接信号槽,再绑定端口.

如果顺序反过来,可能会出现端口绑定好了之后,请求就过来了,此时还没来得及连接信号槽,那么这个请求就有可能错过了.
Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); // 1. 设置窗⼝标题 this->setWindowTitle("服务器"); // 2. 实例化 socket socket = new QUdpSocket(this); // 3. 连接信号槽, 处理收到的请求 connect(socket, &QUdpSocket::readyRead, this, &Widget::processRequest); // 4. 绑定端⼝ bool ret = socket->bind(QHostAddress::Any, 9090); if (!ret) { QMessageBox::critical(nullptr, "服务器启动出错", socket->errorString()); return; } } 

3)实现 processRequest,完成处理请求的过程

  • 读取请求并解析
  • 根据请求计算响应
  • 把响应写回到客户端
void Widget::processRequest() { // 1. 读取请求 const QNetworkDatagram& requestDatagram = socket->receiveDatagram(); QString request = requestDatagram.data(); // 2. 根据请求计算响应 const QString& response = process(request); // 3. 把响应写回到客⼾端 QNetworkDatagram responseDatagram(response.toUtf8(), requestDatagram.senderAddress(), requestDatagram.senderPort()); socket->writeDatagram(responseDatagram); // 显⽰打印⽇志 QString log = "[" + requestDatagram.senderAddress().toString() + ":" + QString::number(requestDatagram.senderPort()) + "] req: " + request + ", resp: " + response; ui->listWidget->addItem(log); } 

4)实现 process 函数

由于 我们此处是实现回显服务器,所以 process 方法中并没有包含实质性的内容
QString Widget::process(const QString& request) { return request; } 

此时,服务器程序编写完毕。但是直接运行还看不出效果,还需要搭配客户端来使用

回显客户端

1)创建界面.包含一个 QLineEdit,QPushButton,QListwidget

  • 先使用水平布局把 QLineEditQPushButton 放好,并设置这两个控件的垂直方向的 sizePolicyExpanding
  • 再使用垂直布局把 QListwidget 和上面的水平布局放好
  • 设置垂直布局的 layoutStretch 为5,1(当然这个尺寸比例根据个人喜好微调)
image-20250313113607160

2)在 widget.cpp 中,先创建两个全局常量,表示服务器的 IP 和 端口

// 提前定义好服务器的 IP 和 端⼝ const QString& SERVER_IP = "127.0.0.1"; const quint16 SERVER_PORT = 9090; 

3)创建 QUdpsocket 成员
修改 widget.h,定义成员

class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private: Ui::Widget *ui; // 创建 socket 成员 QUdpSocket* socket; }; 

4)给发送按钮 slot 函数,实现发送请求

void Widget::on_pushButton_clicked() { // 1. 获取到输⼊框的内容 const QString& text = ui->lineEdit->text(); // 2. 构造请求数据 QNetworkDatagram requestDatagram(text.toUtf8(), QHostAddress(SERVER_IP), SERVER_PORT); // 3. 发送请求 socket->writeDatagram(requestDatagram); // 4. 消息添加到列表框中 ui->listWidget->addItem("客⼾端说: " + text); // 5. 清空输⼊框 ui->lineEdit->setText(""); } 

5)再次修改 Widget 的构造函数,通过信号槽处理服务器响应

connect(socket, &QUdpSocket::readyRead, this, [=]() { const QNetworkDatagram responseDatagram = socket->receiveDatagram(); QString response = responseDatagram.data(); ui->listWidget->addItem(QString("服务器说: ") + response); }); 

结果如下

image-20250312144439115

三:🔥 TCP Socket

主要的类就两个:QTcpSocketQTcpServer

QTcpSocket 用于监听端口,获取客户端连接

名称类型说明对标原生 API
listen(const QHostAddress&, quint16 port)方法绑定指定地址和端口号,并开始监听bind 和 listen
nextPendingConnection()方法从系统中获取到⼀个已经建立好的 tcp 连接.
返回⼀个 QTcpSocket, 表示这个客户端的连接.
通过这个socket对象完成和客户端 之间的通信.
accept
newConnection信号有新的客户端端建立连接好之后触发无(但类似于 IO 多路复用中的通知机制)

QTcpSocket 用于 客户端 和 服务器之间的数据交互

名称类型说明对标原生 API
readAll()构造函数读取当前接收缓冲区中的所有数据
返回 QByteArray对象
read
write(const QByteArray&)方法把数据写入 socket 中write
deleteLater方法暂时把 socket 对象标记为无效.Qt 会在下个事件循环中析构释放该对 象.无(但类似于 “半自动化的垃圾回收”)
readyRead()信号有数据到达并准备就绪时触发无(但类似于 IO 多路复用中的通知机制)

🦋 代码示例

回显服务器

1)创建界面,包含一个 QListWidget 用来显示消息

image-20250313131823857

2)创建 QTcpSocket 并且初始化

修改 widget.h,添加 QTcpServer 指针成员

class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private: Ui::Widget *ui; QTcpSocket* socket; }; 

修改 widget.cpp,实例化 QTcpServer 并进行后续初始化操作,

  • 设置窗口标题
  • 实例化 TCP server.(父元素设为当前控件,会在父元素销毁时被一起销毁),
  • 通过信号槽,处理客户端建立的新连接
  • 监听端口
Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); // 1. 设置窗⼝标题 this->setWindowTitle("服务器"); // 2. 实例化 Tcp socket tcpsocket = new TcpSocket(this); // 3. 通过信号槽, 处理客⼾端建⽴的新连接. connect(tcpServer, &QTcpServer::newConnection, this, &Widget::processConnection); // 4. 监听端⼝ bool ret = tcpServer->listen(QHostAddress::Any, 9090); if (!ret) { QMessageBox::critical(nullptr, "服务器启动失败!", tcpServer->errorString()); exit(1); } } 

3)继续修改 widget.cpp,实现处理连接的具体方法 processconnection

  • 获取到新的连接对应的 socket.
  • 通过信号槽,处理收到请求的情况
  • 通过信号槽,处理断开连接的情况
void Widget::processConnection() { // 1. 获取到新的连接对应的 socket. QTcpSocket* clientSocket = tcpServer->nextPendingConnection(); QString log = QString("[") + clientSocket->peerAddress().toString() + ":" + QString::number(clientSocket->peerPort()) + "] 客⼾端上线!"; ui->listWidget->addItem(log); // 2. 通过信号槽, 处理收到请求的情况 connect(clientSocket, &QTcpSocket::readyRead, this, [=](){ // a) 读取请求 QString request = clientSocket->readAll(); // b) 根据请求处理响应 const QString& response = process(request); // c) 把响应写回客⼾端 clientSocket->write(response.toUtf8()); QString log = QString("[") + clientSocket->peerAddress().toString() + ":" + QString::number(clientSocket->peerPort()) + "] req: " + request + ", resp: " + response; ui->listWidget->addItem(log); }); // 3. 通过信号槽, 处理断开连接的情况 connect(clientSocket, &QTcpSocket::disconnected, this, [=]() { QString log = QString("[") + clientSocket->peerAddress().toString() + ":" + QString::number(clientSocket->peerPort()) + "] 客⼾端下线!"; ui->listWidget->addItem(log); // 删除 clientSocket clientSocket->deleteLater(); }); } 

4)实现 process 函数

由于 我们此处是实现回显服务器,所以 process 方法中并没有包含实质性的内容
QString Widget::process(const QString& request) { return request; } 

此时,服务器程序编写完毕。但是直接运行还看不出效果,还需要搭配客户端来使用

回显客户端

1)创建界面.包含一个 QLineEdit,QPushButton,QListwidget

  • 先使用水平布局把 QLineEditQPushButton 放好,并设置这两个控件的垂直方向的 sizePolicyExpanding
  • 再使用垂直布局把 QListwidget 和上面的水平布局放好
  • 设置垂直布局的 layoutStretch 为5,1(当然这个尺寸比例根据个人喜好微调)
image-20250313113607160

2)创建QTcpSocket 并实例化,修改widget.h创建成员

class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private: Ui::Widget *ui; // 创建 QTcpsocket QTcpSocket* socket; }; 

修改 widget.cpp,对 QTcpSocket 进行实例化,

  • 设置窗口标题
  • 实例化 socket 对象(父元素设为当前控件,会在父元素销毁时被一起销毁)
  • 和服务器建立连接
  • 等待并确认连接是否出错
Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); // 1. 设置窗⼝标题. this->setWindowTitle("客⼾端"); // 2. 实例化 socket 对象. socket = new QTcpSocket(this); // 3. 和服务器建⽴连接. socket->connectToHost("127.0.0.1", 9090); // 4. 等待并确认连接是否出错. if (!socket->waitForConnected()) { QMessageBox::critical(nullptr, "连接服务器出错!", socket->errorString()); exit(1); } } 

3)修改widget.cpp,给按钮增加点击的slot函数,实现发送请求给服务器

void Widget::on_pushButton_clicked() { // 获取输⼊框的内容 const QString& text = ui->lineEdit->text(); // 清空输⼊框内容 ui->lineEdit->setText(""); // 把消息显⽰到界⾯上 ui->listWidget->addItem(QString("客⼾端说: ") + text); // 发送消息给服务器 socket->write(text.toUtf8()); } 

4)再次修改 Widget 的构造函数,通过信号槽处理服务器响应

// 处理服务器返回的响应. connect(socket, &QTcpSocket::readyRead, this, [=]() { QString response = socket->readAll(); qDebug() << response; ui->listWidget->addItem(QString("服务器说: ") + response); }); 

先启动服务器,再启动客⼾端(可以启动多个),最终执行效果:

  • 由于我们使用信号槽处理同⼀个客户端的多个请求,不涉及到循环,也就不会使客户端之间相互影响 了.
image-20250313135437206

三:🔥 Http Client

进行 Qt 开发时,和服务器之间的通信很多时候也会用到 HTTP 协议.

  • 通过 HTTP 从服务器获取数据
  • 通过 HTTP 向服务器提交数据,

🦋 API 概述

关键类主要是三个,QNetworkAccessManagerQNetworkRequestQNetworkReply

QNetworkAccessManager 提供了HTTP的核心操作,

方法说明
get(const QNetworkRequest&)发起一个 HTTP GET 请求,返回 QNetworkReply 对象
post(const QNetworkRequest&, const QByteArray&)发起一个 HTTP POST 请求。返回 QNetworkReply 对象

QNetworkRequest 表示⼀个HTTP请求(不含body).

  • 如果需要发送⼀个带有body的请求(比如post),会在 QNetworkAccessManager 的 post方法 中通过单独的参数来传入 body
方法说明
QNetworkRequest(const QUrl &)通过 URL 构造 HTTP 请求
setHeader(QNetworkRequest::KnowHeaders header, const QVariant &value)设置请求头

其中的 QNetworkRequest::KnownHeaders 是⼀个枚举类型,常用取值:

取值说明
ContentTypeHeader描述 body 类型
ContentLengthHeader描述 body 长度
LocationHeader用于重定向报文中指定重定向地址(响应中使用,请求用不到)
CookieHeader设置 Cookie
UserAgenHeader设置 User-Agent

QNetworkReply 表示⼀个HTTP响应。这个类同时也是 QIODevice 的⼦类

方法说明
error()获取出错状态
errorString()获取出错原因的文本
readAll()读取响应 body
header(QNetworkRequest::KnownHeaders header)读取响应指定 header 的值

此外:QNetworkReply 还有⼀个重要的信号 finished 会在客户端收到完整的响应数据之后触发.

🦋 代码示例

1)创建界面:包含一个 QLineEdit,QPushButton、QPlainTextEidt

  • 先使用水平布局把 QLineEditQPushButton 放好,并设置这两个控件的垂直方向的 sizePolicyExpanding
  • 再使用垂直布局把 QPlainTextEidt 放好(QPlainTextEdit 的 readOnly 设为 true)
  • 设置垂直布局的 layoutStretch 为5,1(当然这个尺寸比例根据个人喜好微调)
image-20250313113607160
此处建议使用 QPlainTextEdit,而不是 QTextEdit,主要因为 QTextEdit 要进行 富文本解析,如果得到的HTTP响应体积很大,就会导致界面渲染缓慢甚至被卡住

2)修改 widget.h ,创建 QNetworkAccessManager 属性

class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private: Ui::Widget *ui; QNetworkAccessManager* manager; }; 

3)修改 widget.cpp 创建实例

Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); // 实例化属性 manager = new QNetworkAccessManager(this); } 

4)编写按钮的 slot 函数,实现发送 HTTP 请求功能

void Widget::on_pushButton_clicked() { // 1. 获取输入到输入框的 URL,构造 QURL 对象 QUrl url(ui->lineEdit->text()); // 2. 构造 HTTP 请求对象 QNetworkRequest request(url); // 3. 发送 GET 请求 QNetworkReply* response = manager->get(request); // 4. 通过信号槽处理 connect(response, &QNetworkReply::finished, this, [=](){ if(response->error() == QNetworkReply::NoError){ // 响应正确 QString html(response->readAll()); ui->plainTextEdit->setPlainText(html); } else{ ui->plainTextEdit->setPlainText(response->errorString()); } response->deleteLater(); }); } 

执行程序,观察效果

image-20250313170451801

四:🔥 【Qt】音视频

🔥 在Qt中,视频播放的功能主要是通过 QMediaPlayer 类和 QVideoWidget 类来实现。在使用这两个类时要添加对应的模块 multimediamultimediawidgets

核心 API 概述

名称作用
setMedia()设置当前媒体源
setVideoOutput()QVideoWidget 视频输出附加到媒体播放器,如果媒体播放器已经添加了视频输出,将更换一个新的

代码示例

首先在 .pro 文件中添加 multimedia 和 multimediawidgets 两个模块;如下图示:

image-20250313193115412
/********************************* widget.h *********************************/ #ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QHBoxLayout> //⽔平布局 #include <QVBoxLayout> //垂直布局 #include <QVideoWidget> //显⽰视频 #include <QMediaPlayer> //播放声⾳ #include <QPushButton> //按钮 #include <QStyle> //设置图标 #include <QFileDialog> //选择⽂件/⽂件夹 class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); public slots: void chooseVideo(); private: QMediaPlayer *mediaPlayer; QVideoWidget *videoWidget; QVBoxLayout *vbox; //创建两个按钮:选择视频按钮和开播放按钮 QPushButton *chooseBtn,*playBtn; }; #endif // WIDGET_H /********************************* widget.cpp *********************************/ #include "widget.h" #include <QMediaPlayer> #include <QSlider> Widget::Widget(QWidget *parent) : QWidget(parent) { //对象实例化 mediaPlayer = new QMediaPlayer(this); videoWidget = new QVideoWidget(this); //设置播放画⾯的窗⼝ videoWidget->setMinimumSize(600,600); //实例化窗⼝布局---垂直布局 this->vbox = new QVBoxLayout(this); this->setLayout(this->vbox); //实例化选择视频按钮 chooseBtn = new QPushButton("选择视频",this); //实例化播放按钮 playBtn = new QPushButton(this); //设置图标代替⽂件 playBtn->setIcon(this->style()->standardIcon(QStyle::SP_MediaPlay)); //实例化⼀个⽔平布局,将以上控件放⼊⽔平布局中 QHBoxLayout *hbox = new QHBoxLayout; //添加控件 hbox->addWidget(chooseBtn); hbox->addWidget(playBtn); //将播放窗⼝和⽔平布局都添加到垂直布局中 vbox->addWidget(videoWidget); //布局中添加布局 vbox->addLayout(hbox); //将选择视频对应的按钮和槽函数进⾏关联 connect(chooseBtn,&QPushButton::clicked,this,&Widget::chooseVideo); } void Widget::chooseVideo() { //选择视频,返回⼀个播放视频的名字 QString name = QFileDialog::getSaveFileName(this,"选择视频",".","WMV(*.wmv)"); //设置媒体声⾳ mediaPlayer->setMedia(QUrl(name)); //输出视频画⾯ mediaPlayer->setVideoOutput(videoWidget); //播放 mediaPlayer->play(); } Widget::~Widget() { } 

五:🔥 共勉

😋 以上就是我对 【Qt】网络 的理解, 觉得这篇博客对你有帮助的,可以点赞收藏关注支持一波~ 😉

Read more

OpenClaw横空出世:星标榜第一的AI Agent框架凭什么引爆2026?

OpenClaw横空出世:星标榜第一的AI Agent框架凭什么引爆2026?

欢迎文末添加好友交流,共同进步! “ 俺はモンキー・D・ルフィ。海贼王になる男だ!” * 一、现象级爆火:GitHub年度最热AI项目 * 二、OpenClaw是什么? * 核心定位 * 三、OpenClaw凭什么成为新标杆? * 3.1 自托管部署:数据主权回归 * 3.2 无代码革命:人人都是开发者 * 3.3 微内核架构:优雅且强大 * 3.4 多智能体协同 * 四、技术架构深度解析 * 4.1 核心组件 * 4.2 2026.3.7重大更新 * 五、与主流框架对比 * 5.1 OpenClaw vs LangChain * 5.2 OpenClaw vs

腾讯游戏 2026 年 Q1 财报解读:AI 赋能下的新增长曲线

腾讯游戏 2026 年 Q1 财报解读:AI 赋能下的新增长曲线

引言 2026 年 3 月,腾讯控股发布 2026 年第一季度财报。游戏业务作为腾讯的现金牛,本季度表现亮眼,总收入达到 580 亿元,同比增长 22%。其中,AI 技术的深度应用成为增长的关键驱动力。 一、核心数据概览 1. 整体业绩 * 游戏总收入:580 亿元,同比增长 22% * 国内游戏:320 亿元,同比增长 12% * 海外游戏:260 亿元,同比增长 38% * 净利润:185 亿元,同比增长 35% 2. 用户数据 * 《王者荣耀》日活突破 1.5 亿,创历史新高

告别项目混乱!2026开工季:DooTask如何用“轻量化+AI”破解开发团队协同困局

告别项目混乱!2026开工季:DooTask如何用“轻量化+AI”破解开发团队协同困局

告别项目混乱!2026开工季:DooTask如何用“轻量化+AI”破解开发团队协同困局 在软件开发领域,迭代进度失控、跨岗位沟通断层、需求变更响应滞后是困扰团队的三大痛点。传统项目管理工具功能冗余、学习成本高,而DooTask凭借“轻量化+精准协同”的设计理念,成为开发团队突破效率瓶颈的利器。本文将结合DooTask最新功能升级解析其如何助力团队实现需求同步、迭代跟踪与跨岗协同的闭环管理。 一、需求同步:从“信息孤岛”到“全局透明” 痛点场景:需求变更引发连锁反应 传统模式下,产品经理通过文档或口头传达需求,开发者需反复确认细节,测试人员可能因信息滞后漏测关键功能。 DooTask解决方案:需求看板+智能关联 AI需求解析:Dootask引入先进的自然语言处理(NLP)技术,能够自动分析需求文档中的关键信息,如功能描述、性能指标、界面要求等,并生成结构化的需求模型。同时,AI还可以对需求进行语义理解,识别潜在的风险点和模糊表述,及时提醒产品经理进行澄清,避免后续开发过程中的误解。 智能关联机制:需求任务能够自动推送相关负责人,

AutoGPT+Python:让AI智能体自动完成复杂任务的终极指南

AutoGPT+Python:让AI智能体自动完成复杂任务的终极指南

AutoGPT+Python:让AI智能体自动完成复杂任务的终极指南 引言:在人工智能迈向自主化的新阶段,AutoGPT作为基于大语言模型(LLM)的自主智能体代表,正掀起一场让AI自己思考、自主执行的技术革命。当它遇上Python的全栈生态与极致灵活性,开发者不再只是调用AI接口,而是能深度定制专属智能体——让AI听懂自然语言、拆解复杂目标、调用外部工具、联网检索信息、迭代优化结果,独立完成从市场调研、内容创作、代码开发到自动化运维的全流程任务。 本文从核心原理、本地部署、Python实战、插件扩展、生产优化五大维度,手把手带你从0到1搭建可落地、可监控、可进化的AI智能体系统,不管是AI爱好者、全栈开发者还是创业者,都能靠这份指南,掌握下一代人机协作的核心生产力。 一、先搞懂:AutoGPT到底是什么? 传统ChatGPT类模型是被动应答,你问一句它答一句,需要人工一步步引导;而AutoGPT是自主智能体,你只给它一个最终目标,它就能自己完成: * 任务拆解:把复杂目标拆成可执行子步骤 * 自主决策:判断下一步该做什么、调用什么工具 * 记忆管理:短期记忆存上下文