Qt-系统相关(2)多线程网络

Qt多线程

在 Qt 中,多线程的处理⼀般是通过 QThread类 来实现。
QThread 代表⼀个在应⽤程序中可以独⽴控制的线程,也可以和进程中的其他线程共享数据。
QThread 对象管理程序中的⼀个控制线程。

QThread 常⽤ API:

 

使用线程 

关于创建线程的步骤:

1. ⾃定义⼀个类,继承于 QThread,并且只有⼀个线程处理函数(和主线程不是同⼀个线程),这个线程处理函数主要就是重写⽗类中的 run() 函数。
2. 线程处理函数⾥⾯写⼊需要执⾏的复杂数据处理;
3. 启动线程不能直接调⽤ run() 函数,需要使⽤对象来调⽤ start() 函数实现线程启动;
4. 线程处理函数执⾏结束后可以定义⼀个信号来告诉主线程;
5. 最后关闭线程。

用多线程实现定时器功能

 

创建一个新的类:

记得勾选下面的 add Q_OBJECT 

然后重写这个类的run函数

也定义了一个信号

然后在Widget构造函数中初始化,还有定义槽函数

 执行结果:

关于这个start函数,这个才是真正调用系统API创建线程,新的线程创建出来后,会自动的执行run函数。

可以使用一个wait,让一个线程等待另一个线程的结束。

另外之前也说过,只有主线程才能针对界面的控件进行状态的修改。

理解Qt的多线程 

我们之前学过的多线程,是站在服务器的角度上来看待的,对于服务器来说:多线程最主要的目的就是要充分利用多核CPU的计算资源。

而对于客户端来说,多线程仍然非常有意义,但是与服务器的侧重点不同。

对于普通用户来说,“使用体验”是非常重要的话题。

客户端上的程序很少会使用多线程把计算资源吃完。

相比之下,客户端的多线程主要是通过多线程的方式来执行一些耗时的IO操作,这样可以避免主线程被卡死,造成不好的用户体验。比如我们用迅雷下载文件,当文件很大,要20分钟才能下载完,那么在下载的过程中,用户的界面不可能得一直阻塞住吧?

因此,我们可以使用一个单独的新线程来处理这种IO密集的操作。

线程安全问题 

谈到线程,始终绕不开的就是线程安全问题。

在Qt中实现线程互斥和同步常⽤的类有: 

互斥锁:QMutex、QMutexLocker
条件变量:QWaitCondition
信号量:QSemaphore
读写锁:QReadLocker、QWriteLocker、QReadWriteLock

简单使用互斥锁 

场景:两个线程对一个变量进行++,每个线程执行5000次。

重写run函数

 初始化操作

结果:

 对于Qt的互斥锁

条件变量 

在 Qt 中,专⻔提供了 QWaitCondition类 来解决像上述这样的问题。
特点:QWaitCondition 是 Qt 框架提供的条件变量类,⽤于线程之间的消息通信和同步。

使用示例:

QMutex mutex;
QWaitCondition condition;
//在等待线程中
mutex.lock();
//检查条件是否满⾜,若不满⾜则等待
while (!conditionFullfilled()) 
{condition.wait(&mutex); //等待条件满⾜并释放锁
}
//条件满⾜后继续执⾏
//...
mutex.unlock();
//在改变条件的线程中
mutex.lock();
//改变条件
changeCondition();
condition.wakeAll(); //唤醒等待的线程
mutex.unlock();

信号量 

特点:QSemaphore 是 Qt 框架提供的计数信号量类,⽤于控制同时访问共享资源的线程数量。
⽤途:限制并发线程数量,⽤于解决⼀些资源有限的问题。

示例:

QSemaphore semaphore(2); //同时允许两个线程访问共享资源
//在需要访问共享资源的线程中
semaphore.acquire(); //尝试获取信号量,若已满则阻塞
//访问共享资源
//...
semaphore.release(); //释放信号量
//在另⼀个线程中进⾏类似操作

Qt网络 

 和多线程类似, Qt 为了⽀持跨平台, 对⽹络编程的 API 也进⾏了重新封装

在进⾏⽹络编程之前, 需要在项⽬中的 .pro ⽂件中添加 network 模块.
添加之后要⼿动编译⼀下项⽬, 使 Qt Creator 能够加载对应模块的头⽂件.

UDP Socket 

主要的类有两个. QUdpSocket QNetworkDatagram 

QUdpSocket 表⽰⼀个 UDP 的 socket ⽂件。 

QNetworkDatagram 表⽰⼀个 UDP 数据报 

UDP回显服务器 

一般一个正经的服务器是很少会带有图形化界面的,一般都是命令行。

服务器部分 

 用一个listWidget来显示信息

 初始化部分:

主要执行逻辑:

客户端部分 

界面部分

初始化代码:

按钮对应的槽函数实现:

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

 

用lambda表达式的方式

客户端演示:

服务器演示:

我们也可以启动多个客户端向服务器发起请求。 

关于这里面的一些细节 

在传参的时候关于什么时候用 引用类型,什么时候用值类型:

大的原则上是尽量使用引用类型。

但是有些时候,比如不同类型相互转换的时候,大概率使用值类型

两个问题:

这个Udp服务器是否能放到Linux云服务上呢?

大概率不行。这取决于这个云服务器是否安装了图形化界面,Qt程序需要依赖图形化界面来运行。

能否用现在的Udp客户端连接云服务器上linux的Udp服务器?

是可以的。

一般的商业公司都不会用Qt编写服务器,但是会用Qt编写客户端。 

 

TCPSocket

 核⼼类是两个: QTcpServer QTcpSocket

QTcpServer ⽤于监听端⼝, 和获取客⼾端连接. 

 关于QTcpServer:

 

QTcpSocket ⽤⼾客⼾端和服务器之间的数据交互 

 关于QTcpSocket:

QByteArray ⽤于表⽰⼀个字节数组. 可以很⽅便的和 QString 进⾏相互转换.
例如:
使⽤ QString 的构造函数即可把 QByteArray 转成 QString.
使⽤ QString 的 toUtf8 函数即可把 QString 转成 QByteArray

 

 TCP回显服务器

服务器部分 

 初始化:

 处理新连接的槽函数:

这里跟UDP就有明显不同了,主要是对连接的处理

void Widget::processConnection()
{// 注意和UDP的区别// 1.先获取新连接对应的socketQTcpSocket* clientSocket = server->nextPendingConnection();// 构建日志QString log = "客户端:" + clientSocket->peerAddress().toString() + ":" + QString::number(clientSocket->peerPort()) + "上线了";ui->listWidget->addItem(log);// 2.设置连接可读就绪的槽函数connect(clientSocket,&QTcpSocket::readyRead,clientSocket,[=](){// 读取请求QString request = clientSocket->readAll();// 构建响应QString response = prase(request);// 返回响应clientSocket->write(response.toUtf8());// 打印日志QString log = "客户端:" + clientSocket->peerAddress().toString() + ":" + QString::number(clientSocket->peerPort()) + " 说: " + response;ui->listWidget->addItem(log);});// 3.设置连接断开时的槽函数connect(clientSocket,&QTcpSocket::disconnected,clientSocket,[=](){// 打印日志QString log = "客户端:" + clientSocket->peerAddress().toString() + ":" + QString::number(clientSocket->peerPort()) + "下线了";ui->listWidget->addItem(log);clientSocket->deleteLater(); // 下一个事件循环再删除});
}QString Widget::prase(QString &str)
{return str;
}

客户端部分 

客户端界面:

 

 初始化:

Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);this->setWindowTitle("Tcp客户端");socket = new QTcpSocket(this);socket->connectToHost(ip,port); // 和服务器建立连接// 等待连接是否出错if(!socket->waitForConnected()){QMessageBox::critical(this,"连接出错",socket->errorString());exit(1);}// 处理连接可读就绪槽函数connect(socket,&QTcpSocket::readyRead,socket,[=](){QString response = socket->readAll();// 这里省略了解析过程QString log = "服务器说: " + response;ui->listWidget->addItem(log);});
}

 按钮槽函数的设计

void Widget::on_pushButton_clicked()
{QString text = ui->lineEdit->text();if(text.isEmpty()) return;ui->lineEdit->clear();socket->write(text.toUtf8());// 打印日志QString log = "客户端说: " + text;ui->listWidget->addItem(log);
}

演示效果:

服务器:

这里也是支持多个客户端同时连接的。

客户端:

 服务器能发送响应,客户端也能接收响应。

关于这里的一些细节

在TCP服务器处理请求这里,还是不够严谨的,因为TCP是字节流传输的,所以会存在数据“粘包”问题,这里我们并没有对其进行处理。这里严谨的做法应该是:将数据放到一个大的接收缓冲区中,然后约定好应用层协议的格式(报文定长,特殊字符等等)。

关于服务器那里,对于每一个客户端上线时,都会创建一个socket,随着客户端越来越多,如果这个socket不释放的话,就会造成内存泄漏,还有更严重的文件描述符泄漏。

我们可以通过delete手动释放,但是我们要考虑这个delete一定得被执行到,不会被return 异常这些情况而导致没有执行到。

Qt给了一种“半自动”的垃圾回收机制,

上述这个操作,不是立即销毁clientSocket,而是告诉Qt在下一轮事件循环中,再进行上述的销毁操作。

 

 HTTP Client

Qt提供了HTTP客户但,但是没有提供HTTP服务器的库。

原因也很简单,一个正经的服务器是不需要图形化界面的,也就是不会用Qt来开发。

HTTPClient关键类主要是三个. QNetworkAccessManager , QNetworkRequest , QNetworkReply 

QNetworkAccessManager 提供了 HTTP 的核⼼操作:

 

QNetworkRequest 表⽰⼀个 HTTP 请求(不含 body):

如果需要发送⼀个带有 body 的请求(⽐如 post), 会在 QNetworkAccessManager 的 post ⽅法
中通过单独的参数来传⼊ body

 

 

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

 

QNetworkReply 表⽰⼀个 HTTP 响应. 这个类同时也是 QIODevice 的⼦类:

 

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

 

发送get请求 

客户端界面:

 这里我们以请求百度首页为例,得到的响应大概率是一个HTML格式的文件,这里我们的QplainTextEdit可以看到响应原始的模样。而QTextEdit天然会对HTML进行解析。

 初始化:

slot槽函数

void Widget::on_pushButton_clicked()
{QUrl url = ui->lineEdit->text();if(url.isEmpty()) return;ui->lineEdit->clear();// 构建http请求对象QNetworkRequest request(url);// 获取http请求响应QNetworkReply* response =  manager->get(request);// 构建槽函数来处理响应connect(response,&QNetworkReply::finished,response,[=](){if(response->error() == QNetworkReply::NoError){// 响应正确QString html = response->readAll();ui->plainTextEdit->setPlainText(html);}else{// 响应出错ui->plainTextEdit->setPlainText(response->errorString());}response->deleteLater(); // 记得销毁});
}

 运行结果:

发送 POST 请求代码也是类似. 使⽤ manager->post() 即可 

 

Qt音频 

这里简单介绍一下Qt的音频

在 Qt 中,⾳频主要是通过 QSound 类来实现。但是需要注意的是 QSound 类只⽀持播放 wav 格式的⾳频⽂件。也就是说如果想要添加⾳频效果,那么⾸先需要将 ⾮wav格式 的⾳频⽂件转换为 wav 格式。

 

另外:使⽤ QSound 类时,需要添加模块:multimedia

它的核心API就一个:
 

 

先准备一个.wav格式的音频,然后可以用qrc管理起来。

示例:

#include <QSound> //添加⾳频头⽂件
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);QSound *sound = new QSound(":/1.wav",this); //实例化对象connect(ui->btn,&QPushButton::clicked,[=](){sound->play(); //播放});
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/62248.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

永久免费的PDF万能水印删除工具

永久免费的PDF万能水印删除工具 1.简介 PDF万能水印删除工具&#xff0c;可以去除99.9%的PDF水印。例如&#xff1a;XObject水印&#xff08;含图片水印&#xff09;、文本水印、绘图水印/曲线水印、注释水印、工件水印、剪切路径水印等等。本软件是永久免费&#xff0c;无有…

华三(HCL)和华为(eNSP)模拟器共存安装手册

接上章叙述&#xff0c;解决同一台PC上同时部署华三(HCL)和华为(eNSP&#xff09;模拟器。原因就是华三HCL 的老版本如v2及以下使用VirtualBox v5版本&#xff0c;可以直接和eNSP兼容Oracle VirtualBox&#xff0c;而其他版本均使用Oracle VirtualBox v6以上的版本&#xff0c;…

深度理解进程的概念(Linux)

目录 一、冯诺依曼体系 二、操作系统(OS) 设计操作系统的目的 核心功能 系统调用 三、进程的概念与基本操作 简介 查看进程 通过系统调用获取进程标识符 通过系统调用创建进程——fork() 四、进程的状态 操作系统中的运行、阻塞和挂起 理解linux内核链表 Linux的进…

SQLite 管理工具 SQLiteStudio 3.4.5 发布

SQLiteStudio 3.4.5 版本现已发布&#xff0c;它带来了大量的 bug 修复&#xff0c;并增加了一些小功能。SQLiteStudio 是一个跨平台的 SQLite 数据库的管理工具。 具体更新内容包括&#xff1a; 现在可以使用 Collations Editor 窗口在数据库中注册 Extension-based collatio…

非常简单实用的前后端分离项目-仓库管理系统(Springboot+Vue)part 2

七、创建前端项目 你下载了nodejs吗&#xff1f;从cn官网下载&#xff1a;http://nodejs.cn/download/&#xff0c;或者从一个国外org网站下载&#xff0c;选择自己想要的版本https://nodejs.org/download/release/&#xff0c;双击下载好的安装文件&#xff0c;选择安装路径安…

继续完善wsl相关内容:基础指令

文章目录 前言一、我们需要安装wsl,这也是安装docker desktop的前提,因此我们在这篇文章里做了介绍:二、虽然我们在以安装docker desktop为目的时,不需要安装wsl的分发(distribution),但是装一个分发也是有诸多好处的:三、在使用wsl时,不建议把东西直接放到系统里,因…

20241124 Typecho 视频插入插件

博文免不了涉及到视频插入这些,网上的插件都或多或少的比较重,和Typecho的风格不搭配 后面就有了DPlay插件精简而来的VideoInsertion插件 VideoInsertion: Typecho 视频插入插件 目录结构 rockhinlink-ht2:/var/www/html/typecho/usr/plugins/VideoInsertion$ tree -h [4.…

css:项目

这是一个完整的网站制作的流程 美工会先制作一个原型图&#xff1a; 原型图写的不详细&#xff0c;就是体现一个网页大致的布局 然后美工再做一个psd样例图片 然后再交给程序员 项目 模块化开发&#xff1a;把代码的不同的样式封装起来&#xff0c;需要用到相同样式的标签就…

Qt桌面应用开发 第九天(综合项目一 飞翔的鸟)

目录 1.鸟类创建 2.鸟动画实现 3.鼠标拖拽 4.自动移动 5.右键菜单 6.窗口透明化 项目需求&#xff1a; 实现思路&#xff1a; 创建项目导入资源鸟类创建鸟动画实现鼠标拖拽实现自动移动右键菜单窗口透明化 1.鸟类创建 ①鸟类中包含鸟图片、鸟图片的最小值下标和最大值…

网络安全期末复习

第1章 网络安全概括 &#xff08;1&#xff09;用户模式切换到系统配置模式&#xff08;enable&#xff09;。 &#xff08;2&#xff09;显示当前位置的设置信息&#xff0c;很方便了解系统设置&#xff08;show running-config&#xff09;。 &#xff08;3&#xff09;显…

使用Python实现自动化邮件通知:当长时程序运行结束时

使用Python实现自动化邮件通知&#xff1a;当长时程序运行结束时 前提声明 本代码仅供学习和研究使用&#xff0c;不得用于商业用途。请确保在合法合规的前提下使用本代码。 目录 引言项目背景项目设置代码分析 导入所需模块定义邮件发送函数发送邮件 实现步骤结语全部代码…

Python学习35天

# 定义父类 class Computer: CPUNone MemoryNone diskNone def __init__(self,CPU,Memory,disk): self.disk disk self.Memory Memory self.CPU CPU def get_details(self): return f"CPU:{self.CPU}\tdisk:{self.disk}\t…

Opencv+ROS实现摄像头读取处理画面信息

一、工具 ubuntu18.04 ROSopencv2 编译器&#xff1a;Visual Studio Code 二、原理 图像信息 ROS数据形式&#xff1a;sensor_msgs::Image OpenCV数据形式&#xff1a;cv:Mat 通过cv_bridge()函数进行ROS向opencv转换 cv_bridge是在ROS图像消息和OpenCV图像之间进行转…

LAMP环境的部署

一、软件安装介绍 在Linux系统中安装软件有rpm安装、yum安装、源码安装等方法&#xff0c;在这里主要给大家介绍 yum 安装&#xff0c;这是一种最简单方便的一种安装方法。 YUM&#xff08;Yellow dog Upadate Modifie&#xff09;是改进版的 RPM 管理器&#xff0c;很好地解…

『VUE』elementUI dialog的子组件created生命周期不刷新(详细图文注释)

目录 1. 测试代码分析令人迷惑的效果 分析原因解决方法 如何在dialog中反复触发created呢?总结 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 主要是在做表单的时候想要有一个编辑表单在dialog弹窗中出现,同时dialog调用的封装的…

项目实战:基于深度学习的人脸表情识别系统设计与实现

大家好&#xff0c;人脸表情识别是计算机视觉领域中的一个重要研究方向&#xff0c;它涉及到对人类情感状态的理解和分析。随着深度学习技术的发展&#xff0c;基于深度学习的人脸表情识别系统因其高精度和强大的特征学习能力而受到广泛关注。本文旨在探讨基于深度学习的人脸表…

QChart数据可视化

目录 一、QChart基本介绍 1.1 QChart基本概念与用途 1.2 主要类的介绍 1.2.1 QChartView类 1.2.2 QChart类 1.2.3QAbstractSeries类 1.2.4 QAbstractAxis类 1.2.5 QLegendMarker 二、与图表交互 1. 动态绘制数据 2. 深入数据 3. 缩放和滚动 4. 鼠标悬停 三、主题 …

Chrome和edge浏览器如何为任何网站强制暗模式

前言 因为我的编辑器是黑色&#xff0c;可能是看的时间长了比较喜欢这种颜色了&#xff0c;感觉白色有些刺眼。尤其是看文章时&#xff0c;两边的空白纯白色&#xff0c;所以强迫症搜素设置了谷歌浏览器和edge如何设置成黑色。 Chrome和edge浏览器如何为任何网站强制暗模式 前…

使用 Elastic 收集 Windows 遥测数据:ETW Filebeat 输入简介

作者&#xff1a;来自 Elastic Chema Martinez 在安全领域&#xff0c;能够使用 Windows 主机的系统遥测数据为监控、故障排除和保护 IT 环境开辟了新的可能性。意识到这一点&#xff0c;Elastic 推出了专注于 Windows 事件跟踪 (ETW) 的新功能 - 这是一种强大的 Windows 原生机…

k8s网络服务

k8s 中向外界提供服务的几种方法port-forward、NodePort&#xff0c;以及 更加常用的提供服务的资源ingress。 1 kubectl port-forward service/redis 6379:6379 现在k8s中有一个pod运行在6379&#xff0c;本机访问映射到6379上&#xff0c;它可以针对部署&#xff0c;服务&…