Qt 网络编程 udp通信

学习目标:使用udp通信

前置环境

运行环境:qt creator 4.12

学习内容

UDP 协议基础知识
1、UDP(用户数据报协议)是轻量的、不可靠的、面向数据报、无连接的协议,用于可靠性要求不高的场合。两个应用程序之间进行UDP 通信不需先建立持久的 socket 连接,UDP 每次发送数据报都需要指定目标地址和端口。

2.ÙDP 报文没有可靠性保证、顺序保证和流量控制字段等,可靠性一较差。但是正因为 UDP 协议的控制选项较少在数据传输过程中延迟小、数据传输效率高,适合对可靠性要求不高的应用程序,或者可以保障可靠性的应用程序,如 DNS、TFTP、SNMP 等。

3、UDP 报头由 4个域组成,其中每个域各占用 2 个字节,具体包括
源端口号、目标端口号、数据包长度、校验值。端口号有效范围0--65535,假设端口号大于 49151的端口都代表动态端口

4、QUdpSocket类从QAbstractSocket类继承 基本跟QTcpSocket共用大部分的接口函数,主要区别在于 QUdpSocket 以数据报传输数据,不是以连续的数据流,发送方发送数据报使用函数QUdpSocket::writeDataGram(),数据报长度一般不超过 512 个字节,每个数据报包含发送方和接收方的 IP 地址和端口等数据信息。

QUdpSocket是Qt中用于UDP网络通信的类,它提供了以下一些常用的成员函数:

  1. bind(const QHostAddress &address, quint16 port): 绑定到指定的地址和端口。

  2. bind(quint16 port, BindMode mode = DefaultForPlatform): 绑定到指定的端口,并设置绑定模式。

  3. writeDatagram(const QByteArray &datagram, const QHostAddress &host, quint16 port): 将指定的数据报发送到指定的主机和端口。

  4. writeDatagram(const char *data, qint64 size, const QHostAddress &host, quint16 port): 将指定大小的数据发送到指定的主机和端口。

  5. readDatagram(char *data, qint64 maxSize, QHostAddress *address = nullptr, quint16 *port = nullptr): 从接收缓冲区中读取一个数据报,并将其存储在指定的缓冲区中。

  6. pendingDatagramSize(): 返回下一个待读取的数据报的大小。

  7. hasPendingDatagrams(): 检查是否有待读取的数据报。

  8. joinMulticastGroup(const QHostAddress &groupAddress): 加入一个多播组。

  9. leaveMulticastGroup(const QHostAddress &groupAddress): 退出一个多播组。

  10. setMulticastInterface(const QNetworkInterface &interface): 设置用于多播的网络接口。

  11. multicastInterface(): 返回用于多播的网络接口。

  12. setSocketOption(SocketOption option, const QVariant &value): 设置套接字选项。

  13. socketOption(SocketOption option): 返回指定的套接字选项的值。

  14. state(): 返回套接字的当前状态。

  15. error(): 返回最近一次发生的错误。

  16. abort() 用于中断或终止当前的 UDP 网络操作。可以确保 QUdpSocket 实例回到一个干净、可重用的状态,而不会产生任何残留的网络操作。需要注意的是,abort() 函数只会中断当前正在进行的操作,而不会关闭套接字本身。如果需要彻底关闭套接字,可以调用 close() 函数。

    1. 立即中断正在进行的任何 UDP 发送或接收操作。

    2. 清空内部缓冲区,丢弃所有待发送或待接收的数据。

    3. 将套接字的状态设置为 QAbstractSocket::UnconnectedState

这些成员函数涵盖了UDP网络编程的各个方面,包括数据发送、数据接收、多播管理、套接字选项设置等。使用这些函数可以方便地实现UDP通信的各种功能。

实现项目

Qt udp通讯编程

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //获取当前主机ip  放到ip选项栏
    QHostInfo info =QHostInfo::fromName(QHostInfo::localHostName());
    QList<QHostAddress> addrs=info.addresses();
    if(!addrs.empty()){
        foreach(const QHostAddress& addr,addrs){
            if(addr.protocol()==QAbstractSocket::IPv4Protocol){
                ui->plainTextEdit->appendPlainText("本机当前ipv4:"+addr.toString());
                ui->tarip->addItem(addr.toString());
            }
        }
    }


    udpsocket=new QUdpSocket(this);

    ui->pushButton->setEnabled(true);
    ui->pushButton_3->setEnabled(false);

    //用作消息到达 处理消息
    // QObject::connect(udpsocket,SIGNAL(readyRead()),this,SLOT(UdpSockerRecvData())); 老版本Qt4.0语法糖 5.0弃用但是仍然可使用

    //QObject::connect(udpsocket,SIGNAL(QUdpSocket::readyRead()),this,SLOT(MainWindow::UdpSockerRecvData())); 新版本5.0 误区点
    //新版本5.0
    QObject:: connect(udpsocket, &QUdpSocket::readyRead, this, &MainWindow::UdpSockerRecvData);
}
void MainWindow::UdpSockerRecvData(){
    while(udpsocket->hasPendingDatagrams())
       {
           QByteArray datagrams;

           datagrams.resize(udpsocket->pendingDatagramSize());

           QHostAddress paddress;
           quint16 pport;

           // 通过readDatagram()此函数读取数据报,
           udpsocket->readDatagram(datagrams.data(),datagrams.size(),&paddress,&pport);

           QString strs=datagrams.data();
           QString peer="[From:"+paddress.toString()+":"+QString::number(pport)+"]:";

           ui->plainTextEdit->appendPlainText(peer+strs);

           qDebug()<<"UdpSockerRecvData:"<<peer;
       }
}

MainWindow::~MainWindow()
{
    delete ui;
    udpsocket->close();
    delete udpsocket;
}


void MainWindow::on_pushButton_clicked()//绑定端口
{
    QString ip=ui->tarip->currentText();
    qint16 port =ui->curport->value();

    if(udpsocket->bind(QHostAddress(ip),port)){
        ui->plainTextEdit->appendPlainText("**********绑定成功**********");
        ui->plainTextEdit->appendPlainText("$$$$$$$$$$绑定端口$$$$$$$$$$:"+QString::number(udpsocket->localPort()));
        ui->pushButton->setEnabled(false);
        ui->pushButton_3->setEnabled(true);
        qDebug()<<"绑定端口:"<<port;

    }else ui->plainTextEdit->appendPlainText("**********绑定失败**********");
}

void MainWindow::on_pushButton_3_clicked()//解除绑定端口
{
    qDebug()<<"解除绑定端口:"<<udpsocket->localPort();
    udpsocket->abort();
    ui->pushButton->setEnabled(true);
    ui->pushButton_3->setEnabled(false);
    ui->plainTextEdit->appendPlainText("**********已经停止服务**********");
}

void MainWindow::on_pushButton_2_clicked()//发送数据
{
     // 获取目标IP地址 端口 发送消息内容
    QString targetip=ui->tarip->currentText();
    uint16_t targetport =ui->tarport->value();
    QString msg =ui->editmsg->text();
    qDebug()<<"发送数据:"<<targetip<<targetport;
    QByteArray send =msg.toUtf8();
    // 发送数据报信息
    udpsocket->writeDatagram(send,QHostAddress(targetip),targetport);
    ui->plainTextEdit->appendPlainText("[out]:"+msg);
    ui->editmsg->clear();
}

void MainWindow::on_pushButton_4_clicked()//广播发送
{
    qint16 tarport =ui->tarport->value();
    QString msg =ui->editmsg->text();
    QByteArray send =msg.toUtf8();

    udpsocket->writeDatagram(send,QHostAddress::Broadcast,tarport);
    ui->plainTextEdit->appendPlainText("[broadcast out]:"+msg);
    ui->editmsg->clear();

    ui->editmsg->setFocus(); // 将光标焦点定位到编辑框控件
}

 总结

  1. 获取本地IP地址:

    • 通过 QHostInfo::fromName(QHostInfo::localHostName()) 获取本地主机信息
    • 遍历 QHostInfo::addresses() 中的地址,找到 IPv4 协议的地址
    • 将这些地址添加到 tarip 下拉框中供用户选择
  2. 创建 UDP 套接字:

    • 使用 QUdpSocket 类创建 UDP 套接字实例
    • 将 readyRead 信号连接到 UdpSockerRecvData 槽函数,用于处理接收到的数据
  3. 绑定 UDP 端口:

    • 在 on_pushButton_clicked 函数中,获取用户选择的 IP 地址和端口
    • 使用 udpsocket->bind(QHostAddress(ip), port) 绑定 UDP 套接字
    • 根据绑定结果更新 UI 状态和按钮可用性
  4. 接收 UDP 数据报:

    • 在 UdpSockerRecvData 槽函数中,通过 udpsocket->hasPendingDatagrams() 检查是否有待处理的数据报
    • 使用 udpsocket->readDatagram() 读取数据报,获取发送方地址和端口
    • 将接收到的消息显示在 plainTextEdit 窗口中
  5. 发送 UDP 数据报:

    • 在 on_pushButton_2_clicked 函数中,获取用户输入的目标 IP 地址、端口和消息
    • 使用 udpsocket->writeDatagram() 将消息发送到指定的目标
    • 在 plainTextEdit 窗口中显示发送的消息
  6. 广播 UDP 数据报:

    • 在 on_pushButton_4_clicked 函数中,获取用户输入的目标端口和消息
    • 使用 udpsocket->writeDatagram(data, QHostAddress::Broadcast, port) 将消息广播到所有客户端
    • 在 plainTextEdit 窗口中显示广播的消息
  7. 资源清理:

    • 在 MainWindow 析构函数中,关闭 UDP 套接字并删除实例
    • 确保资源得到正确释放,避免内存泄漏
最后附上源代码链接
对您有帮助的话,帮忙点个star

34-udpSocket · jbjnb/Qt demo - 码云 - 开源中国 (gitee.com)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于STM32F407ZG的FreeRTOS移植

1.从FreeRTOS官网中下载源码 2、简单分析FreeRTOS源码目录结构 2.1、简单分析FreeRTOS源码根目录 &#xff08;1&#xff09;Demo&#xff1a;是官方为一些单片机移植FreeRTOS的例程 &#xff08;2&#xff09;License&#xff1a;许可信息 &#xff08;3&#xff09;Sourc…

大学教师门诊预约小程序-计算机毕业设计源码73068

摘要 在当今数字化、信息化的浪潮中&#xff0c;大学校园的服务管理正朝着智能化、便捷化的方向迈进。为了优化大学教师的医疗体验&#xff0c;提升门诊预约的效率和便捷性&#xff0c;我们基于Spring Boot框架设计并实现了一款大学教师门诊预约小程序。该小程序不仅提供了传统…

你的 Mac 废纸篓都生苍蝇啦

今天给大家推荐个免费且有趣的小工具 BananaBin&#xff0c;它可以在你的废纸篓上“长”一些可爱的苍蝇&#x1fab0;。 软件介绍 BananaBin 是 macOS 上的一款有趣实用工具&#xff0c;当你的垃圾桶满了时&#xff0c;它会提醒你清理。这个软件通过在垃圾桶上添加互动的苍蝇…

亲子时光里的打脸高手,贾乃亮与甜馨的父爱如山

贾乃亮这波操作&#xff0c;简直是“实力打脸”界的MVP啊&#xff01; 7月5号&#xff0c;他一甩手&#xff0c;甩出张合照&#xff0c; 瞬间让多少猜测纷飞的小伙伴直呼&#xff1a;“脸疼不&#xff1f;”带着咱家小甜心甜馨&#xff0c; 回了哈尔滨老家&#xff0c;这趟亲…

AI革命:RAG技术引领未来智能

AI革命:RAG技术引领未来智能 在人工智能的浪潮中,一种名为RAG(Retrieval-Augmented Generation)的技术正在悄然改变我们的世界。这种技术通过整合外部知识库,极大地增强了大型语言模型(LLM)的性能,为智能助手、聊天机器人等应用带来了革命性的提升。 1 突破性的RAG技…

停车场小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;车主管理&#xff0c;商家管理&#xff0c;停车场信息管理&#xff0c;预约停车管理&#xff0c;商场收费管理&#xff0c;留言板管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;停车场信息…

Java——IO流(二)-(4/7):不同编码读取乱码的问题,转换流-InputStreamReader、OutputStreamWriter

目录 不同编码读取出现乱码的问题 转换流 InputStreamReader(字符输入转换流) 实例演示(1) OutputStreamWriter(字符输出转换流) 实例演示(2) 不同编码读取出现乱码的问题 如果代码编码和被读取的文本文件的编码是一致的&#xff0c;使用字符流读取文本文件时不会出现乱…

ctfshow web入门 nodejs

web334 有个文件下载之后改后缀为zip加压就可以得到两个文件 一个文件类似于index.php 还有一个就是登录密码登录成功就有flag username:ctfshow password:123456因为 return name!CTFSHOW && item.username name.toUpperCase() && item.password passwor…

8分钟带你快速了解Connector/Catalog API的核心设计

引言 在现代大数据应用中&#xff0c;数据集成和同步成为企业数据管理的关键环节。随着数据源和数据库的多样化&#xff0c;如何高效地进行数据集成成为企业面临的重要挑战。 Apache SeaTunnel 作为一款开源的数据集成工具&#xff0c;致力于解决这一问题。本文将详细介绍 Sea…

Drools开源业务规则引擎(一)- 安装与介绍

文章目录 [toc] Drools开源业务规则引擎&#xff08;一&#xff09;- 安装与介绍0.何为规则引擎1.Drools介绍1.1.依赖模块1.2.规则引擎 2.Drools安装2.1.依赖导入2.2.规则的输入和输出类型输入类型输出类型 2.3.创建规则文件2.4.构建可执行规则库2.5.执行结果&#xff1a; 3.Dr…

Oracle Database 23ai新特性:增加聚合函数对INTERVAL数据类型支持

在Oracle早期的版本&#xff0c;聚合函数和分析函数MIN/MAX 就支持了INTERVAL 数据类型。但是&#xff0c;当我们使用SUM或AVG函数对INTERVAL 数据类型进行运算时&#xff0c;就会报错。 随着Oracle Database 23ai 的发布&#xff0c;增加了 AVG 以及 SUM 函数对INTERVAL 数据…

Keepalived+LVS实现负责均衡,高可用的集群

Keepalived的设计目标是构建高可用的LVS负载均衡群集&#xff0c;可以调用ipvsadm工具来创建虚拟服务器&#xff0c;管理服务器池&#xff0c;而不仅仅用作双机热备。使用Keepalived构建LVS群集更加简便易用&#xff0c;主要优势体现在&#xff1a;对LVS负责调度器实现热备切换…

七、MyBatis-Plus高级用法:最优化持久层开发-个人版

七、MyBatis-Plus高级用法&#xff1a;最优化持久层开发 目录 文章目录 七、MyBatis-Plus高级用法&#xff1a;最优化持久层开发目录 一、MyBatis-Plus快速入门1.1 简介1.2 快速入门回顾复习 二、MyBatis-Plus核心功能2.1 基于Mapper接口CRUDInsert方法Delete方法Update方法Se…

实战某大型连锁企业域渗透

点击星标&#xff0c;即时接收最新推文 本文选自《内网安全攻防&#xff1a;红队之路》 扫描二维码五折购书 实战域渗透测试流程 对黑客来说&#xff0c;拿下域控制器是终极目标。然而攻击者空间是如何通过采取信息收集、权限提升、横向移动等一系列手段&#xff0c;从而一步步…

Maven基本使用

1. Maven前瞻 Maven官网&#xff1a;https://maven.apache.org/ Maven镜像&#xff1a;https://mvnrepository.com 1.1、Maven是什么 Maven是一个功能强大的项目管理和构建工具&#xff0c;可以帮助开发人员简化Java项目的构建过程。 在Maven中&#xff0c;使用一个名为 pom.…

Nginx-http_auth_basic_module使用

文章目录 前言一、ngx_http_auth_basic_module二、指令1.auth_basic1.auth_basic_user_file 示例生成密码文件配置basic认证浏览器验证 总结 前言 nginx可以通过HTTP Basic Authutication协议进行用户名和密码的认证。 一、ngx_http_auth_basic_module 生效阶段&#xff1a; …

Apache DolphinScheduler 与 AWS 的 EMR/Redshift 集成实践分享

引言 这篇文章将给大家讲解关于DolphinScheduler与AWS的EMR和Redshift的集成实践&#xff0c;通过本文希望大家能更深入地了解AWS智能湖仓架构&#xff0c;以及DolphinScheduler在实际应用中的重要性。 AWS智能湖仓架构 首先&#xff0c;我们来看一下AWS经典的智能湖仓架构图…

软件运维服务方案(Word原件2024)

软件运维服务方案&#xff08;Word原件&#xff09; 1. 服务简述 我们提供全面的软件运维服务&#xff0c;确保软件系统的稳定运行。 1.1 服务内容 包括监控、维护、故障排查与优化。 1.2 服务方式 结合远程与现场服务&#xff0c;灵活响应客户需求。 1.3 服务要求 高效响应&am…

计算机应用数学--第三次作业

第三次作业计算题编程题1 基于降维的机器学习2 深度学习训练方法总结 第三次作业 计算题 (15 分&#xff09;对于给定矩阵 A A A&#xff08;规模为 42&#xff09;&#xff0c;求 A A A 的 SVD&#xff08;奇异值分解&#xff09;&#xff0c;即求 U U U&#xff0c; Σ …

Spring 6.1.10版本源码编译

每篇一句 我们对时间的感知其实非常主观&#xff0c;我们越习惯于我们的生活方式&#xff0c;生活里面的新鲜感就越少&#xff0c;我们对时间 的感知就越快&#xff0c;生命就越短。 1.源码下载 进入Spring官网 https://spring.io/ 按照上图步骤进入如下Spring Framework链…