Qt Udp的组播(多播)、广播和单播

UDP通讯的基本概念和特点‌
UDP(User Datagram Protocol,用户数据报协议)是‌TCP/IP协议族中的一种无连接协议,主要用于那些对实时性要求较高而可靠性要求较低的应用场景。UDP的主要特点包括:

‌无连接‌:UDP在发送数据之前不需要建立连接,减少了建立连接的开销。
‌不保证可靠传输‌:UDP不提供数据传输的可靠性保证,数据可能会丢失或重复。
‌面向报文‌:UDP以独立的数据报形式发送数据,每个数据报都是独立的,并且保留了数据的边界。
‌首部开销小‌:UDP的首部开销非常小,只有8个字节,适合传输小数据包。
‌支持多种通信模式‌:UDP支持一对一、一对多、多对一和多对多的通信模式。
UDP通讯的实现步骤
‌创建套接字‌:使用socket()函数创建一个UDP套接字。
‌绑定地址‌:使用bind()函数将套接字与本地地址绑定。
‌发送数据‌:使用sendto()函数发送数据包,需要指定目的地址和端口。
‌接收数据‌:使用recvfrom()函数接收数据包,可以获取发送方的地址和端口信息。
‌关闭套接字‌:使用close()函数关闭套接字,释放资源。
UDP通讯的应用场景
由于UDP具有无连接、快速传输的特点,它非常适合用于那些对实时性要求较高而可靠性要求较低的应用场景,例如:

‌‌视频会议‌:视频流传输需要低延迟,UDP可以满足这一需求。
‌在线游戏‌:游戏中的实时交互需要快速的数据传输,UDP可以减少延迟。
‌实时监控‌:监控系统需要实时传输视频和报警信息,UDP可以提供快速的数据传输。
‌多媒体直播‌:直播需要低延迟和高带宽利用率,UDP可以满足这些要求。

单播
一个UDP客户端发送数据报到指定地址和端口的另一UDP客户端,是一对一的数据传输。
请添加图片描述
组播(多播)
是一点对多点的通信,IPv6没有采用IPv4中的组播术语,而是将广播看成是多播的一个特殊例子。
多播与单播步骤是一样的,只有IP地址有所区别。
多播的地址是特定的,D类地址用于多播。D类IP地址就是多播IP地址,即224.0.0.0至239.255.255.255之间的IP地址,并被划分为局部连接多播地址、预留多播地址和管理权限多播地址3类:
1,局部多播地址:在224.0.0.0~224.0.0.255之间,这是为路由协议和其他用途保留的地址,路由器并不转发属于此范围的IP包
2,预留多播地址:在224.0.1.0~238.255.255.255之间,可用于全球范围(如Internet)或网络协议。
3,管理权限多播地址:在239.0.0.0~239.255.255.255之间,可供组织内部使用,类似于私有IP地址,不能用于Internet,可限制多播范围。
请添加图片描述

广播
广播与组播是一样的,只是ip地址有所不同,而且不用加入指定的组。单播的数据只是收发数据的特定主机进行处理,组播在特定组之间进行处理,而广播的数据整个局域网都进行处理。
广播可以理解为一个人通过广播喇叭对在场的全体说话,这样做的好处是通话效率高,信息一下子就可以传递到全体。
广播在网络中的应用较多,如客户机通过DHCP自动获得IP地址的过程就是通过广播来实现的。但是同单播和多播相比,广播几乎占用了子网内网络的所有带宽。拿开会打一个比方吧,在会场上只能有一个人发言,想象一下如果所有的人同时都用麦克风发言,那会场上就会乱成一锅粥。
在IP网络中,广播地址用IP地址“255.255.255.255”来表示,这个IP地址代表同一子网内所有的IP地址。
请添加图片描述
代码:
.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QUdpSocket>
#include <QTimer>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();

    void unicastOpen();
public slots:
    void onSocketReadyRead();
private slots:
    void on_openbtn_clicked();

    void on_senbtn_clicked();

    void on_autoBox_clicked(bool checked);

    void on_leavebtn_clicked();

    void on_typebox_activated(int index);

private:
    Ui::Widget *ui;
    QUdpSocket *m_socket = nullptr;
    QTimer m_timer;
    bool m_joinFg = false;
    void multicastSendData();
    void multicastReadData();
    void multicastOpen();
    void multicastLeave();
    void broadcastSendData();
    void broadcastReadData();
    void broadcastOpen();
    void broadcastClose();
    void unicastClose();
    void unicastReadData();
    void unicastSendData();
    void open();
    void close();
    void readData();
    void sendData();
};

#endif // WIDGET_H

.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QNetworkInterface>

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    ///单播
    //一个UDP客户端发送数据报到指定地址和端口的另一UDP客户端,是一对一的数据传输。
    ///组播(多播)
    /*是一点对多点的通信,IPv6没有采用IPv4中的组播术语,而是将广播看成是多播的一个特殊例子。
    多播与单播步骤是一样的,只有IP地址有所区别。
    多播的地址是特定的,D类地址用于多播。D类IP地址就是多播IP地址,即224.0.0.0至239.255.255.255之间的IP地址,并被划分为局部连接多播地址、预留多播地址和管理权限多播地址3类:
    1,局部多播地址:在224.0.0.0~224.0.0.255之间,这是为路由协议和其他用途保留的地址,路由器并不转发属于此范围的IP包
    2,预留多播地址:在224.0.1.0~238.255.255.255之间,可用于全球范围(如Internet)或网络协议。
    3,管理权限多播地址:在239.0.0.0~239.255.255.255之间,可供组织内部使用,类似于私有IP地址,不能用于Internet,可限制多播范围。*/
    ///广播
    /*广播与组播是一样的,只是ip地址有所不同,而且不用加入指定的组。单播的数据只是收发数据的特定主机进行处理,组播在特定组之间进行处理,而广播的数据整个局域网都进行处理。
    广播可以理解为一个人通过广播喇叭对在场的全体说话,这样做的好处是通话效率高,信息一下子就可以传递到全体。
    广播在网络中的应用较多,如客户机通过DHCP自动获得IP地址的过程就是通过广播来实现的。但是同单播和多播相比,广播几乎占用了子网内网络的所有带宽。拿开会打一个比方吧,在会场上只能有一个人发言,想象一下如果所有的人同时都用麦克风发言,那会场上就会乱成一锅粥。
    在IP网络中,广播地址用IP地址“255.255.255.255”来表示,这个IP地址代表同一子网内所有的IP地址。*/


    m_socket = new QUdpSocket(this);
    connect(m_socket,&QUdpSocket::readyRead,this,&Widget::onSocketReadyRead);
    connect(&m_timer,&QTimer::timeout,this,[=](){
        if (m_joinFg)
            on_senbtn_clicked();
    });

    ui->ipedit1->setEnabled(false);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_openbtn_clicked()
{
    if (ui->typebox->currentIndex() == 0)
        multicastOpen();
    else if (ui->typebox->currentIndex() == 1)
        broadcastOpen();
    else if (ui->typebox->currentIndex() == 2)
        unicastOpen();
}
void Widget::on_leavebtn_clicked()
{
    if (ui->typebox->currentIndex() == 0)
        multicastLeave();
    else if (ui->typebox->currentIndex() == 1)
        broadcastClose();
    else if (ui->typebox->currentIndex() == 2)
        unicastClose();
}
void Widget::onSocketReadyRead()
{
    if (ui->typebox->currentIndex() == 0)
        multicastReadData();
    else if (ui->typebox->currentIndex() == 1)
        broadcastReadData();
    else if (ui->typebox->currentIndex() == 2)
        unicastReadData();
}
void Widget::on_senbtn_clicked()
{
    if (ui->typebox->currentIndex() == 0)
        multicastSendData();
    else if (ui->typebox->currentIndex() == 1)
        broadcastSendData();
    else if (ui->typebox->currentIndex() == 2)
        unicastSendData();
}


void Widget::multicastOpen()
{
    m_socket->setSocketOption(QAbstractSocket::MulticastTtlOption,100);

    QString ip = ui->ipedit1->text()+ui->ipedit2->text();
    int port = ui->portedit->text().toInt();
    if (m_socket->bind(QHostAddress::AnyIPv4,port,QUdpSocket::BindFlag::ShareAddress | QUdpSocket::BindFlag::ReuseAddressHint))
    {
        m_socket->joinMulticastGroup(QHostAddress(ip));
        QString msg = "加入组播"+ip+":"+ui->portedit->text();
        ui->msgedit->append(msg);
        m_joinFg = true;
        qDebug()<<msg;
    }
    else
    {
        ui->msgedit->append("加入组播失败");
        m_joinFg = false;
    }
}
void Widget::multicastLeave()
{
    QString ip = ui->ipedit1->text()+ui->ipedit2->text();
    m_socket->leaveMulticastGroup(QHostAddress(ip));
    m_socket->abort();
    ui->msgedit->append("退出组播");
    ui->autoBox->setChecked(false);
    m_joinFg = false;
    m_timer.stop();
}
void Widget::multicastReadData()
{
    while(m_socket->hasPendingDatagrams())
    {
        QByteArray datagram;
        datagram.resize(m_socket->pendingDatagramSize());
        QHostAddress peerAddr;
        quint16 peerPort;
        m_socket->readDatagram(datagram.data(),datagram.size(),&peerAddr,&peerPort);

        QString str=datagram.data();

        QString peer="[从 "+peerAddr.toString()+":"+QString::number(peerPort)+" 发送] ";

        ui->msgedit->append(peer+str);
        qDebug()<<peer+str;
    }
}
void Widget::multicastSendData()
{
    QString ip = ui->ipedit1->text()+ui->ipedit2->text();
    m_socket->writeDatagram(ui->sendedit->text().toUtf8(),QHostAddress(ip),ui->portedit->text().toInt());
}


void Widget::broadcastOpen()
{
    int port = ui->portedit->text().toInt();
    if (m_socket->bind(QHostAddress::AnyIPv4,port,QUdpSocket::BindFlag::ShareAddress | QUdpSocket::BindFlag::ReuseAddressHint))
    {
        QString msg = "打开广播"+ui->portedit->text();
        ui->msgedit->append(msg);
        m_joinFg = true;
        qDebug()<<msg;
    }
    else
    {
        ui->msgedit->append("打开广播失败");
        m_joinFg = false;
    }
}
void Widget::broadcastClose()
{
    m_socket->abort();
    ui->msgedit->append("退出广播");
    ui->autoBox->setChecked(false);
    m_joinFg = false;
    m_timer.stop();
}
void Widget::broadcastReadData()
{
    //读取数据
    while(m_socket->hasPendingDatagrams())//hasPendingDatagrams()如果至少有一个数据报等待读取,则返回true;
    {
        QByteArray datagram;
        datagram.resize(m_socket->pendingDatagramSize());
        QHostAddress peerAddr;
        quint16 peerPort;
        m_socket->readDatagram(datagram.data(),datagram.size(),&peerAddr,&peerPort);

        QString str=datagram.data();
        QString peer="[从 "+peerAddr.toString()+":"+QString::number(peerPort)+" 发送] ";

        ui->msgedit->append(peer+str);
        qDebug()<<peer+str;
    }
}
void Widget::broadcastSendData()
{
    m_socket->writeDatagram(ui->sendedit->text().toUtf8(),QHostAddress::Broadcast,ui->portedit->text().toInt());
}

void Widget::unicastOpen()
{
    if (m_socket->bind(QHostAddress::LocalHost,ui->portedit->text().toInt()))
    {
        QString msg = "打开单播";
        ui->msgedit->append(msg);
        m_joinFg = true;
        qDebug()<<msg;
    }
    else
    {
        ui->msgedit->append("打开单播失败");
        m_joinFg = false;
    }
}
void Widget::unicastClose()
{
    m_socket->abort();
    ui->msgedit->append("退出单播");
    ui->autoBox->setChecked(false);
    m_joinFg = false;
    m_timer.stop();
}
void Widget::unicastReadData()
{
    //读取数据
    while(m_socket->hasPendingDatagrams())//hasPendingDatagrams()如果至少有一个数据报等待读取,则返回true;
    {
        QByteArray datagram;
        datagram.resize(m_socket->pendingDatagramSize());
        QHostAddress peerAddr;
        quint16 peerPort;
        m_socket->readDatagram(datagram.data(),datagram.size(),&peerAddr,&peerPort);

        QString str=datagram.data();
        QString peer="[从 "+peerAddr.toString()+":"+QString::number(peerPort)+" 发送] ";

        ui->msgedit->append(peer+str);
        qDebug()<<peer+str;
    }
}
void Widget::unicastSendData()
{
    m_socket->writeDatagram(ui->sendedit->text().toUtf8(),QHostAddress::LocalHost,ui->portedit->text().toInt());
}

void Widget::on_autoBox_clicked(bool checked)
{
    if (checked)
        m_timer.start(200);
    else
        m_timer.stop();
}

void Widget::on_typebox_activated(int index)
{
    if (index == 1 || index == 2)
        ui->ipedit2->setEnabled(false);
}

源码

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

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

相关文章

搭建react项目

#pic_center 400x 参考文章&#xff1a; react开发环境搭建 系列文章&#xff1a; 文章目录 create-react-app安装reactnpm版本管理npm 镜像安装 create-react-app安装react 查看是否安装过create-react-app npm list create-react-app -- create-react-app5.0.1 # 输出版本…

Leetcode 两数之和 Ⅱ - 输入有序数组

这段代码实现了在一个非递减排序的数组中找到两个数&#xff0c;使它们的和等于目标值的算法。算法使用了双指针技术&#xff0c;具体思想如下&#xff1a; 算法思想&#xff1a; 初始化指针&#xff1a;定义两个指针 left 和 right&#xff0c;分别指向数组的起始位置和末尾位…

论文略读:GRAG:GraphRetrieval-Augmented Generation

202404 arxiv 1 motivation 在许多应用场景中&#xff0c;如科学文献网络、推荐系统和知识图谱&#xff0c;文档之间存在复杂的关联&#xff0c;这些关联在传统的RAG模型中常常被忽略 例如&#xff0c;在处理科学文献时&#xff0c;RAG仅基于文本相似性的检索方法无法充分利用…

103 - Lecture 1

Introduction to Database 一、Introduction to Database Systems 1. 数据的定义 What is Data? EX: data could be a docx file storing your project status report; data could be a spreadsheet containing information • 数据只有在设计的场景中才有意义。&#xff…

【论文复现】MSA+抑郁症模型总结(二)

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀MSA抑郁症模型 情感分析的应用1. 概述2. 论文地址3. 研究背景4. 主要贡献5. 模型结构和代码6. 数据集介绍7. 性能展示8. 复现过程9. 运行过程…

JavaScript 实现文本转语音功能

全篇大概2000 字&#xff08;含代码&#xff09;&#xff0c;建议阅读时间10分钟。 引言 我将向大家展示如何使用 JavaScript 和 Web Speech API 快速实现一个“文本转语音”的 Web 应用。通过这个教程&#xff0c;你将了解如何让浏览器将输入的文本朗读出来。 预览效果 一、…

GitLab基于Drone搭建持续集成(CI/CD)

本文介绍了如何为 Gitee 安装 Drone 服务器。服务器打包为在 DockerHub 上分发的最小 Docker 映像。 1. 准备工作 创建OAuth应用 创建 GitLab OAuth 应用。Consumer Key 和 Consumer Secret 用于授权访问极狐GitLab 资源。 ps:授权回调 URL 必须与以下格式和路径匹配&…

RHCE 第四次作业

一.搭建dns服务器能够对自定义的正向或者反向域完成数据解析查询。 1.配置环境 [rootlocalhost ~]# yum install bind [rootlocalhost ~]#systemctl stop firewalld [rootlocalhost ~]#setenforce 0 2.配置DNS主服务器 [rootlocalhost ~]# vim /etc/named.conf options { …

【ArcGIS】绘制各省碳排放分布的中国地图

首先&#xff0c;准备好各省、自治区、直辖市及特别行政区&#xff08;包括九段线&#xff09;的shp文件&#xff1a; 通过百度网盘分享的文件&#xff1a;GS&#xff08;2022&#xff09;1873 链接&#xff1a;https://pan.baidu.com/s/1wq8-XM99LXG_P8q-jNgPJA 提取码&#…

关于CountDownLatch失效问题

一、项目背景 这几天要开发一个类似支付宝那种年度账单统计的功能&#xff0c;就是到元旦后支付完会把用户这一年的消费情况从各个维度&#xff08;我们把这一个维度称作一个指标&#xff09;统计分析形成一张报告展示给用户。 这个功能实现用到了CountDownLatch。假如统计分析…

【专题】2024年全球生物医药交易报告汇总PDF洞察(附原数据表)

原文链接&#xff1a;https://tecdat.cn/?p38191 在当今复杂多变的全球经济环境下&#xff0c;医药行业正面临着诸多挑战与机遇。2024 年&#xff0c;医药行业的发展态势备受关注。 一方面&#xff0c;全球生物医药交易活跃&#xff0c;2021 - 2023 年的交易中&#xff0c;已…

鸿蒙5.0时代:原生鸿蒙应用市场引领开发者服务新篇章

前言 10月22日原生鸿蒙之夜发布会宣布HarmonyOS NEXT正式发布&#xff0c;首个版本号&#xff1a;鸿蒙5.0。这次“纯血鸿蒙”脱离了底层安卓架构成为纯国产的独立系统&#xff0c;仅凭这一点就有很多想象空间。 目前鸿蒙生态设备已超10亿&#xff0c;原生鸿蒙操作系统在中国市…

3.PyCharm工具

第三方IDE&#xff0c;集成开发工具&#xff0c;官网下载。 社区版本&#xff0c;免费使用。 创建项目 配置解释器&#xff0c;创建python文件&#xff0c;编写代码&#xff0c;运行&#xff1a;

arkUI:Flex弹性布局的各个属性

arkUI&#xff1a;Flex弹性布局的简单使用 1 主要内容说明2 相关内容2.1 Flex弹性布局的方向2.1.1 源码1的简答说明2.1.2 源码1 &#xff08;Flex弹性布局的方向&#xff09;2.1.3 源码1运行效果2.1.3.1 当direction: FlexDirection.RowReverse2.1.3.2 当direction: FlexDirect…

串口接收,不定长数据接收

###1.CUBE-MX配置串口 2.我采用串口中断接收&#xff0c;打开中断接口 3.时钟同样8倍频&#xff0c;1分频&#xff0c;使用内部时钟 打开串口中断 main() { __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); // 启用空闲中断__HAL_UART_ENABLE_IT(&huart1, UART_IT_R…

TikTok本土店vs跨境店:解读TikTok小店差异

TikTok小店的两种主要的店铺类型&#xff1a;本土店和跨境店&#xff0c;虽然这两种店铺在功能上有相似之处&#xff0c;但它们在运营模式、市场定位、目标受众和面临的挑战等方面存在显著的区别。 一、定义与基本特征 1. TikTok本土店 本土店指的是在特定国家或地区内经营的…

深度学习——优化算法、激活函数、归一化、正则化

文章目录 &#x1f33a;深度学习面试八股汇总&#x1f33a;优化算法方法梯度下降 (Gradient Descent, GD)动量法 (Momentum)AdaGrad (Adaptive Gradient Algorithm)RMSProp (Root Mean Square Propagation)Adam (Adaptive Moment Estimation)AdamW 优化算法总结 经验和实践建议…

用 Python搭建一个微型的HTTP服务器用于传输 2024/11/9

使用内置的 http.server 模块,来搭建微型服务器。 快速启动服务器http.server --- HTTP 服务器Python 3.13.0 文档 声明:文章代码部分 由 ai 生成 创建一个简单的文件共享服务器 进入 需要共享的目录 再打开cmd 输入以下代码 python -m http.server 8000 打开服务器 设置主…

虚拟机linux7.9下安装mysql

1.MySQL官网下载安装包&#xff1a; MySQL :: Download MySQL Community Server https://cdn.mysql.com/archives/mysql-5.7/mysql-5.7.39-linux-glibc2.12-x86_64.tar.gz 2.解压文件&#xff1a; #tar xvzf mysql-5.7.39-linux-glibc2.12-x86_64.tar.gz 3.移动文件&#…

Turtlebot3 buger 硬件与操作平台详细介绍

引言 TurtleBot3 有三个版本&#xff0c;分别是紧凑型的 Burger、功能更强的 Waffle和性能提升的 Waffle Pi&#xff0c;分别适用于不同的应用需求。使用 Raspberry Pi 作为主控单板计算机&#xff08;SBC&#xff09;&#xff0c;而 Waffle Pi 可以使用更强大的 NVIDIA Jetson…