C++ Qt开发:QUdpSocket网络通信组件
Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍如何运用QUdpSocket组件实现基于UDP的网络通信功能。
与QTcpSocket组件功能类似,QUdpSocket组件是 Qt 中用于实现用户数据报协议(UDP,User Datagram Protocol)通信的类。UDP 是一种无连接的、不可靠的数据传输协议,它不保证数据包的顺序和可靠性,但具有低延迟和简单的特点。
以下是 QUdpSocket 类的完整函数及其简要解释:
| 函数 | 描述 |
|---|---|
QUdpSocket(QObject *parent = nullptr) | 构造函数,创建一个新的 QUdpSocket 对象。 |
~QUdpSocket() | 析构函数,释放 QUdpSocket 对象及其资源。 |
void bind(const QHostAddress &address, quint16 port, BindMode mode = DefaultForPlatform) | 将套接字绑定到指定的本地地址和端口。 |
void close() | 关闭套接字。 |
bool joinMulticastGroup(const QHostAddress &groupAddress, const QNetworkInterface &iface = QNetworkInterface()) | 加入多播组。 |
bool leaveMulticastGroup(const QHostAddress &groupAddress, const QNetworkInterface &iface = QNetworkInterface()) | 离开多播组。 |
qint64 pendingDatagramSize() const | 返回下一个待读取的数据报的大小。 |
qint64 readDatagram(char *data, qint64 maxSize, QHostAddress *address = nullptr, quint16 *port = nullptr) | 读取数据报。 |
QByteArray readDatagram(qint64 maxSize, QHostAddress *address = nullptr, quint16 *port = nullptr) | 读取数据报,返回 QByteArray 对象。 |
qint64 writeDatagram(const char *data, qint64 size, const QHostAddress &address, quint16 port) | 发送数据报。 |
qint64 writeDatagram(const QByteArray &datagram, const QHostAddress &address, quint16 port) | 发送数据报,接受 QByteArray 对象。 |
QAbstractSocket::SocketState state() const | 返回套接字的当前状态。 |
QAbstractSocket::SocketType socketType() const | 返回套接字的类型。 |
bool isValid() const | 如果套接字有效,则返回 true;否则返回 false。 |
int error() const | 返回套接字的当前错误代码。 |
QHostAddress localAddress() const | 返回本地地址。 |
quint16 localPort() const | 返回本地端口。 |
int readBufferSize() const | 返回读取缓冲区的大小。 |
void setReadBufferSize(int size) | 设置读取缓冲区的大小。 |
QNetworkInterface multicastInterface() const | 返回多播组的网络接口。 |
void setMulticastInterface(const QNetworkInterface &iface) | 设置多播组的网络接口。 |
bool hasPendingDatagrams() const | 如果有待读取的数据报,则返回 true;否则返回 false。 |
bool isReadable() const | 如果套接字可读,则返回 true;否则返回 false。 |
bool isWritable() const | 如果套接字可写,则返回 true;否则返回 false。 |
bool setSocketDescriptor(int socketDescriptor, QUdpSocket::SocketState socketState = ConnectedState, QIODevice::OpenMode openMode = ReadWrite) | 设置套接字描述符。 |
int socketDescriptor() const | 返回套接字描述符。 |
bool waitForReadyRead(int msecs = 30000) | 等待套接字可读取数据。 |
bool waitForBytesWritten(int msecs = 30000) | 等待套接字已写入指定字节数的数据。 |
void ignoreSslErrors(const QList<QSslError> &errors) | 忽略 SSL 错误。 |
void abort() | 强制关闭套接字。 |
QNetworkProxy proxy() const | 返回套接字的代理设置。 |
void setProxy(const QNetworkProxy &networkProxy) | 设置套接字的代理设置。 |
QString errorString() const | 返回套接字的错误消息字符串。 |
这些函数提供了在 UDP 通信中使用 QUdpSocket 的各种功能,包括绑定、发送和接收数据报、设置和获取套接字的状态等。
1.1 初始化部分
在初始化部分我们首先通过new QUdpSocket来实现创建UDP对象,QUdpSocket 构造函数的函数原型如下:
QUdpSocket::QUdpSocket(QObject * parent = nullptr)
如上构造函数创建一个新的 QUdpSocket 对象。如果提供了 parent 参数,则会将新创建的 QUdpSocket 对象添加到 parent 对象的子对象列表中,并且在 parent 对象被销毁时自动销毁 QUdpSocket 对象。如果没有提供 parent 参数,则 QUdpSocket 对象将不会有父对象,并且需要手动管理其生命周期。
初始化结束后,则下一步需要调用bind(),bind() 函数是 QUdpSocket 类的一个成员函数,用于将套接字绑定到特定的本地地址和端口。它的函数原型如下:
void QUdpSocket::bind(const QHostAddress &address, quint16 port, BindMode mode = DefaultForPlatform)
address:要绑定的本地地址,通常是QHostAddress::Any,表示绑定到所有可用的网络接口。port:要绑定的本地端口号。mode:绑定模式,指定套接字的行为。默认值是DefaultForPlatform,表示使用平台默认的绑定模式。
该函数允许 QUdpSocket 在本地网络接口上监听传入的数据报。一旦调用了 bind() 函数,QUdpSocket 就可以接收来自指定地址和端口的数据报。
在调用 bind() 函数之后,如果成功绑定了指定的地址和端口,套接字将处于 BoundState 状态。如果出现错误,可以通过检查 error() 函数获取错误代码,并通过 errorString() 函数获取错误消息。
接着我们通过connect()函数依次绑定套接字到stateChanged状态改变信号,以及readyRead()读取信号上,这段初始化代码如下所示;
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);udpSocket=new QUdpSocket(this);// 生成随机整数 包含2000 - 不包含65534int randomInt = QRandomGenerator::global()->bounded(2000, 65534);if(udpSocket->bind(randomInt)){this->setWindowTitle(this->windowTitle() + " | 地址: " + getLocalAddress() + " 绑定端口:" + QString::number(udpSocket->localPort()));}connect(udpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,SLOT(onSocketStateChange(QAbstractSocket::SocketState)));onSocketStateChange(udpSocket->state());connect(udpSocket,SIGNAL(readyRead()),this,SLOT(onSocketReadyRead()));
}
接着切换到读取信号所对应的槽函数上,onSocketReadyRead是我们自定义的一个槽,该槽函数功能如下所示;
// 读取收到的数据报
void MainWindow::onSocketReadyRead()
{while(udpSocket->hasPendingDatagrams()){QByteArray datagram;datagram.resize(udpSocket->pendingDatagramSize());QHostAddress peerAddr;quint16 peerPort;udpSocket->readDatagram(datagram.data(),datagram.size(),&peerAddr,&peerPort);QString str=datagram.data();QString peer="[消息来自 " + peerAddr.toString()+":"+QString::number(peerPort)+"] | ";ui->plainTextEdit->appendPlainText(peer+str);}
}
首先在代码中调用pendingDatagramSize函数,pendingDatagramSize() 是 QUdpSocket 类的一个成员函数,用于获取下一个待读取的数据报的大小。它的函数原型如下:
qint64 QUdpSocket::pendingDatagramSize() const
该函数返回一个 qint64 类型的值,表示下一个待读取的数据报的大小(以字节为单位)。如果没有待读取的数据报,或者发生了错误,该函数将返回 -1。
通常,可以在调用 readDatagram() 函数之前调用 pendingDatagramSize() 函数来获取下一个待读取的数据报的大小。这样可以为数据缓冲区分配正确大小的空间,以确保完整地读取数据报。
当有了待读取字节后,接着就可以直接通过调用readDatagram函数来从套接字中读取数据报,readDatagram() 是 QUdpSocket 类的一个成员函数,它有几个重载形式,其中最常用的是:
qint64 QUdpSocket::readDatagram(char * data, qint64 maxSize, QHostAddress * address = nullptr, quint16 * port = nullptr)
该函数用于读取数据报并将其存储到指定的缓冲区 data 中,最多读取 maxSize 个字节的数据。可选参数 address 和 port 用于返回数据报的源地址和端口号。如果不需要这些信息,可以将它们设置为 nullptr。
函数返回实际读取的字节数,如果发生错误,返回 -1。要查看错误信息,可以使用 error() 和 errorString() 函数。
另外,还有一个更简单的重载形式:
QByteArray QUdpSocket::readDatagram(qint64 maxSize, QHostAddress * address = nullptr, quint16 * port = nullptr)
这个重载函数直接返回一个 QByteArray 对象,其中包含了读取的数据报。
1.2 单播与广播消息
单播(Unicast)和广播(Broadcast)是网络通信中常见的两种数据传输方式,它们在数据包的传输范围和目标数量上有所不同。
单播(Unicast)
单播是一种一对一的通信方式,其中数据包从一个发送者传输到一个接收者。在单播通信中,数据包只发送到目标主机的网络接口,并且只有目标主机能够接收和处理这个数据包。
- 一对一通信:每个数据包只有一个发送者和一个接收者。
- 目标明确:数据包只发送到特定的目标主机,其他主机不会接收到这个数据包。
- 点到点通信:适用于直接通信的场景,如客户端与服务器之间的通信。
当按钮发送消息被点击后,则是一种单播模式,通常该模式需要得到目标地址与端口号,并通过调用writeDatagram来实现数据的发送,该函数通过传入三个参数,分别是发送字符串,目标地址与目标端口来实现一对一推送。
void MainWindow::on_pushButton_clicked()
{QHostAddress targetAddr(ui->lineEdit_addr->text());QString portString = ui->lineEdit_port->text();quint16 targetPort = portString.toUShort();QString msg=ui->lineEdit_msg->text();QByteArray str=msg.toUtf8();// 发送数据报udpSocket->writeDatagram(str,targetAddr,targetPort);ui->plainTextEdit->appendPlainText("[单播消息] | " + msg);
}
广播(Broadcast)
广播是一种一对多的通信方式,其中数据包从一个发送者传输到同一网络中的所有主机。在广播通信中,数据包被发送到网络中的所有主机,并且所有的主机都能够接收和处理这个数据包。
- 一对多通信:每个数据包有一个发送者,但可以有多个接收者。
- 目标不明确:数据包被发送到网络中的所有主机,不需要知道接收者的具体地址。
- 广播域:在局域网中进行广播,只有在同一广播域内的主机才能接收到广播消息。
- 网络负载:在大型网络中使用广播可能会产生大量的网络流量,影响网络性能。
当按钮广播消息被点击后,则同样是调用writeDatagram函数与,唯一的区别在于第二个参数并未指定地址,而是使用了QHostAddress::Broadcast来代替,意味着只要端口是一致的则对所有的客户推送消息,其他保持不变。
void MainWindow::on_pushButton_2_clicked()
{// 广播地址QString portString = ui->lineEdit_port->text();quint16 targetPort = portString.toUShort();QString msg=ui->lineEdit_msg->text();QByteArray str=msg.toUtf8();udpSocket->writeDatagram(str,QHostAddress::Broadcast,targetPort);ui->plainTextEdit->appendPlainText("[广播消息] | " + msg);
}
读者可自行运行两次客户端,此时的端口将会随机分配,当指定对端端口后就可以向其发送数据,如下图所示;具体实现细节,请参考文章附件。

相关文章:
C++ Qt开发:QUdpSocket网络通信组件
Qt 是一个跨平台C图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍如何运用QUdpSocket组件实现基于UDP的网络通信…...
微信小程序小白易入门基础教程1
微信小程序 基本结构 页面配置 页面配置 app.json 中的部分配置,也支持对单个页面进行配置,可以在页面对应的 .json 文件来对本页面的表现进行配置。 页面中配置项在当前页面会覆盖 app.json 中相同的配置项(样式相关的配置项属于 app.js…...
D. Tandem Repeats? - 思维 + 双指针
题面 分析 s s s的范围很小,可以 O ( n 2 ) O(n^2) O(n2),在规定复杂度以内来完成枚举所有子串判断是否有满足条件的最大的子串,可以在第一层循环枚举子串长度 d d d,第二层循环枚举左右端点,通过双指针维护区间。对长…...
第十三届蓝桥杯省赛CC++ 研究生组
蓝桥杯2022年第十三届省赛真题-裁纸刀 蓝桥杯2022年第十三届省赛真题-灭鼠先锋 蓝桥杯2022年第十三届省赛真题-质因数个数 求个数,则只需要计数即可。求啥算啥,尽量不要搞多余操作 蓝桥杯2022年第十三届省赛真题-选数异或 蓝桥杯2022年第十三届省赛真题…...
Oracle中的commit与rollback
SQL语言分为五大类: DDL(数据定义语言:DataDefinitionLanguage) - Create、Alter、Drop 这些语句自动提交,无需用Commit提交。 DQL(数据查询语言:DataQueryLanguage) - Select 查询语句不存在是否提交问题。 DML(数据操纵语言:DataManipulationLangua…...
鸿蒙Harmony应用开发—ArkTS声明式开发(画布组件:OffscreenCanvasRenderingContext2D)
使用OffscreenCanvasRenderingContext2D在Canvas上进行离屏绘制,绘制对象可以是矩形、文本、图片等。离屏绘制是指将需要绘制的内容先绘制在缓存区,然后将其转换成图片,一次性绘制到canvas上,加快了绘制速度。 说明: 从…...
Redis如何实现主从复制?主从复制的作用是什么?Redis集群是如何工作的?它有哪些优点和缺点?
Redis如何实现主从复制?主从复制的作用是什么? Redis的主从复制是一种数据复制机制,其中一个Redis实例作为主节点(master),而其他Redis实例作为从节点(slave)。主从复制的实现过程如…...
【Numpy】(2)numpy对象和random模块
numpy.array对象 numpy.array 对象是 NumPy 库的核心,它提供了一种高效的方式来存储和操作同质数据类型的多维数组。每个 numpy.array 对象都有一系列的属性,这些属性提供了关于数组的重要信息。理解这些属性对于有效地使用 NumPy 和进行数据分析是非常…...
[QJS xmake] 非常简单地在Windows下编译QuickJS!
文章目录 前言准备C编译器xmake编译包 工程准备修改版本号第一遍编译第二遍编译效果 前言 quickjs是个很厉害的东西啊,我一直想编译一下的,奈何一直没成功。现在找了点时间成功编译了,写篇文章记录一下。当前版本:2024-1-13 应该…...
Ubuntu双系统/home分区扩容
一、Windows系统中利用磁盘管理分出空闲区域,如果多就多分一些 二、插入安装Ubuntu的U盘启动盘,lenovo电脑F12(其他电脑可选择其他类似方式)选择U盘启动项,然后选择ubuntu,出现安装界面,再选择t…...
0基础学习VR全景平台篇第145篇:图层控件功能
大家好,欢迎观看蛙色VR官方——后台使用系列课程!这期,我们将为大家介绍如何使用图层控件功能。 一.如何使用图层控件功能? 进入作品编辑页面,点击左边的控件后就可以在右边进行相应设置。 二.图层控件有哪些功能&am…...
一文看懂套利的那些事儿
我们经常在投资中都有提到套利策略,经常听到某某套利,或者借用什么套利工具,股票可以套利,基金期货期权也可以套利,套利到底是什么?套利到底是如何运用的? 今天我们一文解读套利市场!…...
【工具】Mermaid + 大模型画流程图
🌈个人主页: 鑫宝Code 🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础 💫个人格言: "如无必要,勿增实体" 文章目录 引入使用画TCP三次握手了解历史人物 总结 引入 最近看面试文章关于TCP三次握手和…...
内网渗透学习-环境搭建
1、环境搭建测试 虚拟机网络环境配置,模拟外网和内网 主机操作系统网络内网ip外网ip物理主机window10vmnet8192.168.70.1攻击机kali Linuxvmnet8192.168.70.134域控主机win server 2008 r2vmnet0192.168.52.138域成员主机win server 2k3vmnet0192.168.52.141服务器…...
el-progress渐变色
线性渐变喝环形渐变 线性渐变:直接修改样式根据所需颜色修改即可 ::v-deep .el-progress {.el-progress-bar {.el-progress-bar__outer {background: linear-gradient(to right#8075fd, #b87bfe)}.el-progress-bar__inner {background: linear-gradient(to right…...
DHCP在企业网的部署及安全防范
学习目标: 1. DHCP能够解决什么问题? 2. DHCP服务器如何部署? 3. 私接设备会带来什么问题以及如何防范? 给DHCP服务器配置地址: 地址池: DHCP有2种分配模式:全局分配和接口分配 DHCP enable...
列表的常用操作
列表的常用操作(方法) 列表除了可以: 定义使用下标索引获取值 此外列表也提供一些列功能:插入元素删除元素清空元素修改元素统计元素个数 等等功能,这些功能我们都称之为:列表的方法 列表的查询功能&…...
外包2月,技术退步惊现!大专生逆袭大厂,全靠这份神秘资料!
大家好,我是一名大专生,19年通过校招进入湖南某软件公司,从事功能测试工作已近4年。今年8月,我意识到长期舒适的环境让我变得不思进取,技术停滞不前,甚至因此失去了谈了2年的女朋友。我下定决心,…...
考研失败, 学点Java打小工_Day3_卫语句_循环
1 编码规范——卫语句 表达异常分支时,少用if-else方式。 比如成绩判断中对于非法输入的处理: /*>90 <100 优秀>80 <90 良好>70 <80 一般>60 <70 及格<60 不及格*/Testpu…...
网络架构层_服务器上下行宽带
网络架构层_服务器上下行宽带 解释一 云服务器ECS网络带宽的概念、计费、安全及使用限制_云服务器 ECS(ECS)-阿里云帮助中心 网络带宽是指在单位时间(一般指的是1秒钟)内能传输的数据量,带宽数值越大表示传输能力越强,即在单位…...
后进先出(LIFO)详解
LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子(…...
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...
基于服务器使用 apt 安装、配置 Nginx
🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...
使用SSE解决获取状态不一致问题
使用SSE解决获取状态不一致问题 1. 问题描述2. SSE介绍2.1 SSE 的工作原理2.2 SSE 的事件格式规范2.3 SSE与其他技术对比2.4 SSE 的优缺点 3. 实战代码 1. 问题描述 目前做的一个功能是上传多个文件,这个上传文件是整体功能的一部分,文件在上传的过程中…...
Linux安全加固:从攻防视角构建系统免疫
Linux安全加固:从攻防视角构建系统免疫 构建坚不可摧的数字堡垒 引言:攻防对抗的新纪元 在日益复杂的网络威胁环境中,Linux系统安全已从被动防御转向主动免疫。2023年全球网络安全报告显示,高级持续性威胁(APT)攻击同比增长65%,平均入侵停留时间缩短至48小时。本章将从…...
【Java多线程从青铜到王者】单例设计模式(八)
wait和sleep的区别 我们的wait也是提供了一个还有超时时间的版本,sleep也是可以指定时间的,也就是说时间一到就会解除阻塞,继续执行 wait和sleep都能被提前唤醒(虽然时间还没有到也可以提前唤醒),wait能被notify提前唤醒…...
Ray框架:分布式AI训练与调参实践
Ray框架:分布式AI训练与调参实践 系统化学习人工智能网站(收藏):https://www.captainbed.cn/flu 文章目录 Ray框架:分布式AI训练与调参实践摘要引言框架架构解析1. 核心组件设计2. 关键技术实现2.1 动态资源调度2.2 …...
