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 - 不包含65534
int 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网络通信组件的更多相关文章
- 基于arm的嵌入式QT开发(课程设计)
一. 项目要求 配置QT5.7基于x86及arm 等两种CPU架构的调试及开发环境: 移植arm编译后的QT5.7及屏幕校准工具tslib1.4至CORTEX ARM9实验平台: 开发基于QT5.7的 ...
- win使用MSYS2安装Qt开发环境
原文链接 MSYS2 下载地址: pacman的具体用法 有pacman的具体使用方法.我们首先对系统升级 我们首先对系统升级 pacman -Syu 就会检测整个系统可以升级的组件,并自动下载安装, ...
- 基于QT开发的第三方库
基于Qt开发的第三方库 分类: Qt2014-02-12 11:34 1738人阅读 评论(0) 收藏 举报 QT第三方库 目录(?)[+] 文章来源:http://blog.csdn.net ...
- 轻量级C#网络通信组件StriveEngine —— C/S通信开源demo(附源码)
前段时间,有几个研究ESFramework网络通讯框架的朋友对我说,ESFramework有点庞大,对于他们目前的项目来说有点“杀鸡用牛刀”的意思,因为他们的项目不需要文件传送.不需要P2P.不存在好 ...
- QT 开发小记
1.开发socket网络通信时,需要在.pro 文件中添加 network项 QT += network 2. 报错: mutilple definition of 时,查看 .pro ...
- 【应用笔记】【AN005】Qt开发环境下基于RS485的4-20mA电流采集
简介 4-20mA电流环具有广泛的应用前景,在许多行业中都发挥着重要作用.本文主要介绍在Qt开发环境下基于RS485实现4-20mA电流采集,实现WINDOWS平台对数据的采集.分析及显示. 系统组成 ...
- 利用Qt开发跨平台APP
本文将手把手教你如何在Windows环境下,使用Qt编译出安卓应用程序. Qt是一个优秀的跨平台开发工具.我们利用Qt可以很方便地将一次编写的应用,多次编译到不同平台上,如Windows.Linux. ...
- Qt开发环境下载和安装
Qt是跨平台的图形开发库,目前由Digia全资子公司 Qt Company 独立运营,官方网址: http://www.qt.io/ 也可以访问Qt项目域名:http://qt-project.org ...
- Qt开发北斗定位系统融合百度地图API及Qt程序打包发布
Qt开发北斗定位系统融合百度地图API及Qt程序打包发布 1.上位机介绍 最近有个接了一个小型项目,内容很简单,就是解析北斗GPS的串口数据然后输出经纬度,但接过来觉得太简单,就发挥了主观能动性,增加 ...
- CAD控件:QT开发使用控件入门
1. 环境搭建: 3 1.1. 安装Qt 3 1.2. 安装Microsoft Windows SDK的调试包 6 2. QT中使用MxDraw控件 7 1.3. 引入控件 7 3. 打开DWG文件 ...
随机推荐
- Windows 10 快捷键大全|日常办公效率加倍
## 复制.粘贴及其他常规 Ctrl + X 剪切选定项. Ctrl + C(或 Ctrl + Insert) 复制选定项. Ctrl + V(或 Shift + Insert) 粘贴选定项. ...
- Power BI 3 DAY
目录 M函数基本表达式 注释 基本表达式 M函数基本变量类型 自定义函数 调用函数列表 if表达式 数据化结构 列表结构(List) 记录结构(Record)[ ] 表格结构(Table) M函数基本 ...
- NC50493 石子合并
题目链接 题目 题目描述 将n堆石子绕圆形操场排放,现要将石子有序地合并成一堆.规定每次只能选相邻的两堆合并成新的一堆,并将新的一堆的石子数记做该次合并的得分. 请编写一个程序,读入堆数n及每堆的石子 ...
- Spring Boot 加载外部配置文件
Spring Boot 允许你从外部加载配置,这样的话,就可以在不同的环境中使用相同的代码.支持的外部配置源包括:Java属性文件.YAML文件.环境变量.命令行参数. 用@Value注解可以将属性值 ...
- Swoole从入门到入土(14)——HTTP服务器[协程风格]
在这之间,我们讨论了异步风格HTTP服务器,它继承自异步风格的TCP服务器,有着异步风格的所有优点,同时如果碰到了大量的IO等待也会存在阻塞的缺点. 而协程风格的HTTP则很好处理了IO等待的问题.这 ...
- android 逆向笔记
壳检测工具 GDA 2. 逆向分析APP 一般流程 1. 使用自动化检测工具检测APP是否加壳,或者借助一些反编译工具依靠经验判断是否加壳 2. 如果apk加壳,则需要先对apk进行脱壳 3. 使用` ...
- 【Java复健指南07】OOP中级02-重写与多态思想
前情提要:https://www.cnblogs.com/DAYceng/category/2227185.html 重写 注意事项和使用细节 方法重写也叫方法覆法,需要满足下面的条件 1.子类的方法 ...
- 【Azure 存储服务】Azure Storage Account Queue中因数据格式无法处理而在一个小时内不在可见的问题
问题描述 在从Storage Account 队列中获取数据(Queue),在门户中,明显看见有数据,但是通过消费端代码去获取的时候,就是无法获取到有效数据的情况.获取消息的代码如下: 问题解答 经过 ...
- 代码随想录算法训练营第十三天| 239. 滑动窗口最大值 347.前 K 个高频元素 总结
239. 滑动窗口最大值 (一刷至少需要理解思路) 卡哥建议:之前讲的都是栈的应用,这次该是队列的应用了.本题算比较有难度的,需要自己去构造单调队列,建议先看视频来理解. 题目链接/文章讲解/视频讲解 ...
- android 混淆规则作用,Android代码混淆详解
一.混淆的意义 混淆代码并不是让代码无法被反编译,而是将代码中的类.方法.变量等信息进行重命名,把它们改成一些毫无意义的名字,同时也可以移除未被使用的类.方法.变量等. 所以直观的看,通过混淆可以提高 ...