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

devtools/2025/2/13 3:21:33/

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_OBJECTpublic: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);elsem_timer.stop();
}void Widget::on_typebox_activated(int index)
{if (index == 1 || index == 2)ui->ipedit2->setEnabled(false);
}

源码


http://www.ppmy.cn/devtools/132541.html

相关文章

2024.11.09【BUG报错】| Fastuniq “Error in Reading pair-end FASTQ sequence!”解决方案

解决 Fastuniq 中“Error in Reading pair-end FASTQ sequence!”报错的指南 在使用 Fastuniq 进行高通量测序数据分析时&#xff0c;用户可能会遇到“Error in Reading pair-end FASTQ sequence!”的错误提示。这通常表明在读取配对的 FASTQ 序列时出现了问题。以下是一些可能…

GEE 图表——sentinel-2和Landsat-8 影像各波段的图表展示和对比

简介 GEE 图表——sentinel-2和Landsat-8 影像各波段的图表展示和对比 函数 ui.Chart.image.regions(image, regions, reducer, scale, seriesProperty, xLabels) Generates a Chart from an image. Extracts and plots the value of each band in one or more regions. 从…

华为大咖说 | 浅谈智能运维技术

本文分享自华为云社区&#xff1a;华为大咖说 | 浅谈智能运维技术-云社区-华为云 本文作者&#xff1a;李文轩 &#xff08; 华为智能运维专家 &#xff09; 全文约2695字&#xff0c;阅读约需8分钟 在大数据、人工智能等新兴技术的加持下&#xff0c;智能运维&#xff08;AI…

推荐一款PowerPoint转Flash工具:iSpring Suite

iSpring Suite是一款PowerPoint转Flash工具&#xff0c;使用iSpring Suite 8可以轻松的将PPT演示文档转换为对Web友好的Flash影片格式。软件界面简洁&#xff0c;使用方便。为什么要转换成flash格式呢?Flash格式的最大特点是体积小巧、易于分发&#xff0c;兼容所有的操作系统…

浏览器漫谈HTML--2.1印象深刻的标签-语义化标签

语义化标签 HTML语义化标签是HTML5引入的一个重要特性 常见的语义化标签&#xff1a; <header>, <nav>, <main>, <article>, <section>, <aside>, <footer> 布局如下 底层实现逻辑&&好处 语义化标签其实底层实现逻辑和…

linux 通过apt安装软件包时出现依赖包版本不对的问题解决

通过网上查找解决办法时&#xff0c;发现的解决办法无法完美解决问题: 比如通过安装对应版本解决 如: sudo apt-get install xxx2.7.0ubuntu 这样会先卸载原先包&#xff0c;在安装对应版本的包 或者直接删除依赖的包 sudo apt-get purge xxxx 如果碰到底层包的话&#xf…

2024一带一路暨金砖国家技能发展与技术创新大赛 (高职组)【网络安全防护治理实战技能赛项】

湖南省第一届职业技能大赛网络安全竞赛赛卷样题 1.基础设置和安全强化&#xff08;xxx 分&#xff09;2.安全监测和预警&#xff08;xxx 分&#xff09;2.1.任务一&#xff1a;建立目录安全监控规则2.2.任务二&#xff1a;威胁情报分析2.3.任务三&#xff1a;网络流量分析2.4.任…

YAML 语法随笔

文章目录 1_基本语法格式要求2_数据类型2.1 字符串2.2 数值2.3 布尔值2.4 空值2.5 列表 (Array)2.6 对象/字典 (Map)2.7 日期时间类型 3_强制类型转换4_YAML 复杂数据结构示例4.1 嵌套结构4.2 列表包含字典4.3 字典包含列表4.4 复用锚点和引用 5_YAML 字面量和折叠字符串6_特殊…