【Linux C | 网络编程】多播的概念、多播地址、UDP实现多播的C语言例子

😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
🤣本文内容🤣:🍭介绍多播的概念、多播地址、UDP实现广播的C语言例子 🍭
😎金句分享😎:🍭你不能选择最好的,但最好的会来选择你——泰戈尔🍭
⏰发布时间⏰:2024-03-07 20:31:23

本文未经允许,不得转发!!!

目录

  • 🎄一、多播概述
  • 🎄二、多播地址
    • ✨2.1、IPv4 多播地址
    • ✨2.2、IPv6 多播地址
    • ✨2.3、多播地址映射为MAC地址
  • 🎄三、多播的过程
  • 🎄四、源特定多播
    • ✨4.1 广域网的多播
    • ✨4.2 源特定多播(Source-Specific Multicast)
  • 🎄五、UDP实现多播的例子
    • ✨5.1 多播接收端代码
    • ✨5.2 多播发送端代码
  • 🎄六、总结


在这里插入图片描述

🎄一、多播概述

在网络编程中,有三种常见的通信方式:单播、广播、多播(组播),这三种方式对比如下表:

类型IPv4IPv6TCPUDP所标识接口数递送到的接口数
单播支持支持支持支持一个一个
广播支持支持全体全体
多播可选支持支持一组整个组

多播的概念
IP 多播(也称多址广播组播)技术,是允许一台主机多台主机 发送消息的一种通信方式。单播只向单个IP接口发送数据,广播是向子网内所有IP接口发送数据,多播则介于两者之间,向一组IP接口发送数据。
多播支持IPv4,也支持IPv6。在IPv6中没有广播,认为广播只是特殊(把整个子网视为多播组)的多播。
多播支持UDP,不支持TCP。
多播既可用于局域网,也可用于广域网,而广播一般在局域网使用。

多播的优点
比起广播,多播数据报只会发送到加入多播组的主机,不会像广播那样发给所有主机。


在这里插入图片描述

🎄二、多播地址

多播地址用来标识多播组,IPv4使用D类地址的某一个来表示一个多播组地址,IPv6多播地址的高序字节值为ff

✨2.1、IPv4 多播地址

IPv4的D类地址(从224.0.0.0到239.255.255.255)是IPv4多播地址,见下图:
在这里插入图片描述
D类地址的低序28位构成多播组ID(group ID),整个32位地址则称为组地址(group address)。

IPv4的多播地址可分为三类:

  • 链路局部多播地址:224.0.0.0224.0.0.255,这是为路由协议和其它用途保留的地址,路由器并不转发属于此范围的IP包;
  • 预留多播地址:224.0.1.0238.255.255.255,可用于全球范围(如Internet)或网络协议。
  • 管理权限多播地址:239.0.0.0239.255.255.255,可供组织内部使用,类似于私有 IP 地址,不能用于 Internet,可限制多播范围。
下面是若干个IPv4特殊多播地址,这些地址是由IANA确定的,作为永久主机组:
224.0.0.1    所有组播主机
224.0.0.2    所有组播路由器
224.0.0.4    DRMRP 路由器
224.0.0.5    所有 OSPF 的路由器
224.0.0.6    OSPF 指派路由器
224.0.0.9    RPIv2 路由器
224.0.0.10   EIGRP 路由器
224.0.0.13   PIM 路由器
224.0.0.22   IGMPv3
224.0.0.25   RGMP
224.0.1.1    NTP 网络时间协议

✨2.2、IPv6 多播地址

IPv6多播地址的结构如下图,分成4个部分:

  • 高位8比特:全部为1,这是固定的,表示这是一个多播地址;
  • 标志4比特:分以下几种取值
    0000:众所周知的多播组;
    0001:临时的多播组;
    0010:表示多播地址是基于某个单播前缀赋予的;
    0011:表示基于单播的多播地址总是临时的。
  • 范围4比特:可能有以下取值
    0:保留。
    1:接口本地范围(Interface-Local scope )。
    2:链路本地范围(Link-Local scope )。
    3:基于单播前缀的地址(Unicast-Prefix-based address )。
    4:管理本地范围(Admin-Local scope )。
    5:站点本地范围(Site-Local scope)。
    6:未分配。
    7:汇聚点标记(Rendezvous Point flag )。
    8:组织本地范围(Organization-Local scope )。
    9-D:未分配。
    E:全局范围(Global scope。
    F:保留。
  • 组ID112比特:低序32位复制到以太网地址的低序32位

在这里插入图片描述

下面是若干特殊的IPv6多播地址。

  • ff01::1ff02::1是所有节点(all-nodes)组。子网上所有具有多播能力的节点(主机、路由器和打印机等)必须在所有具有多播能力的接口上加入该组,类似于IPv4的224.0.0.1多播地址。但多播是IPv6的一个组成部分,这与IPv4是不同的。
    尽管对应的IPv4组称为所有主机组,而IPv6组称为所有节点组,它们的含义是一致的。IPv6重新命名意在更为清晰地指出本组包括了子网上的主机、路由器、打印机,以及任何IP设备。
  • ff01::2ff02::2ff05::2是所有路由器(all-routers)组。子网上所有多播路由器必须在所有具有多播能力的接口上加入该组,类似于IPv4的224.0.0.2多播地址。

✨2.3、多播地址映射为MAC地址

将多播地址映射到以太网多播地址的过程是重要的,因为以太网是数据链路层的协议,而IPv4、IPv6的多播地址是网络层的协议。这种映射使得多播数据能够在以太网上正确传输到目标设备,确保只有加入了相应多播组的设备才会接收到相应的多播数据包。

以太网地址,通常称为MAC地址(Media Access Control address),是网络设备在数据链路层使用的唯一标识符。MAC地址由48位二进制数组成,通常以十六进制表示,每6位之间用冒号或连字符分隔,如 00:1A:2B:3C:4D:5E。通常,MAC地址是网络设备(如网卡)出厂设置好的,一般不会改变。

当一个IPv4多播数据包需要发送到多个接收者时,IPv4多播地址会被映射成对应的以太网多播地址。这种映射不会改变设备的硬件MAC地址,而是针对特定的多播传输而生成的临时多播MAC地址。多播MAC地址是一个虚拟的地址,源主机将数据发送到多播组对应的以太网多播地址,而不会影响到设备的真实MAC地址。设备仍然使用其固定的硬件MAC地址来标识自己,只是在多播通信过程中会使用临时的多播MAC地址来传输数据。

在这里插入图片描述

IPv4多播地址是通过特定规则映射到以太网多播地址的,映射规则如下:

  • 前24位以固定的前缀01:00:5E开头,第25位总是0。
  • 后23位直接由IPv4多播地址的低23位组成。IPv4多播地址高序4位固定为e,映射过程中,中间的5位被忽略,因此这个映射关系不是一对一的。

IPv6多播地址到以太网地址的映射是通过多播组里的成员关系进行的。下面是IPv6多播地址到以太网地址的映射过程:

  • 首先确定IPv6多播地址的范围,IPv6多播地址通常在ff00::/8的范围内。
  • 多播组的最低24位用于构建对应的以太网地址。这个过程使用了特殊的前缀:33:33。
  • 取IPv6多播地址的最低32位,将其转换为16进制,并插入到33:33之后,形成完整的以太网地址。
  • 以太网地址的第一个字节设置为01-00-5E。这个步骤可以保证以太网地址不会与单播地址冲突。

总的来说,IPv6多播地址到以太网地址的映射是通过将IPv6多播地址的一部分直接复制到以太网地址中,并添加特定的前缀来确保唯一性。


在这里插入图片描述

🎄三、多播的过程

下图是可以展示多播的过程:
在这里插入图片描述
多播的过程:

  • 首先,接收主机(图中右侧)需要在接收进程创建一个UDP套接字,绑定端口123,然后加入多播组224.0.1.1。该主机的IPv4层会保存这些信息,并告知合适的数据链路接收目的以太网地址为01:00:5e:00:01:01的以太网帧。
  • 然后,发送主机(图中左侧)的发送应用进程创建一个UDP套接字,往IP地址224.0.1.1的123端口发送一个数据报,并最后转换成以太网帧发到网络。发送多播数据报无需任何特殊处理,发送应用进程不必为此加入多播组。
  • 接着,不具备多播能力的主机(图中中间主机)会完全忽略该帧。因为:
    1、该帧的目的以太网地址不匹配该主机的接口地址;
    2、该帧的目的以太网地址不是以太网广播地址;
    3、该主机的接口未被告知接收任何组地址(高序字节的低序位被置为1的以太网地址,如图21-1所示)。
  • 最后,接收主机(图中右侧)的数据链路收取该帧后将承载的分组传递到IP层。IP层比较该地址和本机的接收应用进程已经加入的所有多播地址,根据比较结果确定是接受还是丢弃该分组。确定接受之后,再把承载的UDP数据报传递到UDP层。UDP层再把承载在数据报中的数据传递到绑定了端口123的套接字。

图中没有展示的还有以下三种情形:

  • (1)运行所加入多播地址为225.0.1.1的某个应用进程的一个主机。既然多播地址组ID的高5位在到以太网地址的映射中被忽略,该主机的接口也将接收目的以太网地址为01:00:5e:00:01:01的帧。这种情况下,由该帧承载的分组将由IP层中的完备过滤丢弃。
  • (2)运行所加入多播地址符合以下条件的某个应用进程的一个主机:由这个多播地址映射成的以太网地址恰好和01:00:5e:00:01:01一样被该主机执行非完备过滤的接口散列到同一个结果。该接口也将接收目的以太网地址为01:00:5e:00:01:01的帧,直到由数据链路层或IP层丢弃。
  • (3)目的地为相同多播组(224.0.1.1)不同端口(譬如4000)的一个数据报。图21-4中右侧主机仍然接收该数据报,并由P层接受并传递给UDP层,不过UDP层将丢弃它(假设绑定端口4000的套接字不存在)。

在这里插入图片描述

🎄四、源特定多播

✨4.1 广域网的多播

多播是不仅支持局域网,也支持广域网。

当某个主机上的一个进程加入一个多播组时,该主机向所有直接连接的多播路由器发送一个IGMP消息,告知它们本主机已加入了那个多播组。多播路由器随后使用多播路由协议(MRP)交换这些信息,这样每个多播路由器就知道在收到目的地为所加入多播地址的分组时该如何处理。


✨4.2 源特定多播(Source-Specific Multicast)

源特定多播的英文是Source-Specific Multicast,简称SSM,是基于源地址和目的地址的组合来定义多播组,接收者只能从单个源(或称为发送者)接收数据,而不是从任意源接收,这使得网络更加安全可靠。

  • 接收进程向多播路由器提供发送进程的源地址作为多播组加入操作的一部分。这种方式可以减少网络中的不必要流量,提高网络效率。
  • 把多播组的标识从单纯多播组地址细化为单播源地址和多播目的地址之组合(SSM称之为通道)。

在这里插入图片描述

🎄五、UDP实现多播的例子

下面给出一个使用UDP实现多播的例子,代码是之前文章的例子修改的,文章链接: 入门知识:UDP协议、一个最简单的UDP客户端、一个最简单的UDP服务端 。

✨5.1 多播接收端代码

接收端是使用UDP服务端代码修改,需要在交互数据之前,将套接字加入多播组239.0.1.1,让链路层接口接收该多播组的数据报,使用完需要离开多播组。

UDP多播接收端步骤:

  • 1、创建UDP套接字socket;
  • 2、准备本地ip接口和多播组端口;
  • 3、绑定多播组端口 bind;
  • 4、加入多播组 239.0.1.1;
  • 5、使用 sendto、recvfrom 交互数据;
  • 6、离开多播组
  • 7、关闭套接字
// multicastSer.c
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>int main()
{// 1、创建UDP套接字socketint sockfd = socket(AF_INET, SOCK_DGRAM, 0);if(sockfd<0)perror("socket error" );// 2、准备本地ip接口和多播组端口struct sockaddr_in servaddr;bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons (10086);servaddr.sin_addr.s_addr = INADDR_ANY; // 指定ip地址为 INADDR_ANY,这样要是服务器主机有多个网络接口,服务器进程就可以在任一网络接口上接受客户端的连接// 3、绑定多播组端口 bindif (bind(sockfd,(struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)perror("bind error" );// 4、加入多播组 239.0.1.1struct ip_mreq mreq;mreq.imr_multiaddr.s_addr = inet_addr("239.0.1.1");	// 多播组的IP地址mreq.imr_interface.s_addr = htonl(INADDR_ANY);		// 加入的客服端主机IP地址if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1)    {perror("setsockopt");return -1;}// 5、使用 sendto、recvfrom 交互数据printf("UdpSer sockfd=%d, start \n",sockfd);char recvline[256];while(1){struct sockaddr_in cliaddr;bzero(&cliaddr, sizeof(cliaddr));socklen_t addrLen=sizeof(cliaddr);int n = recvfrom(sockfd, recvline, sizeof(recvline), 0, (struct sockaddr*)&cliaddr, &addrLen);if(n>0){recvline[n] = 0 ;/*null terminate */printf("recv sockfd=%d %d byte, [%s] addrLen=%d, cliIp=%s, cliPort=%d\n",sockfd, n, recvline, addrLen, inet_ntoa(cliaddr.sin_addr),cliaddr.sin_port);sendto(sockfd, "Hello,I am udp server", strlen("Hello,I am udp server"), 0, (struct sockaddr*)&cliaddr, addrLen);}}// 6、离开多播组setsockopt(sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP,&mreq, sizeof(mreq)); // 7、关闭close(sockfd);return 0;
}

✨5.2 多播发送端代码

发送端是使用UDP客户端代码修改,整个流程都不需改动,只需要把要发送的目的地址改为多播组地址239.0.1.1。修改后代码如下:

// multicastCli.c
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>int main()
{// 1、创建UDP套接字socketint sockfd = socket(AF_INET, SOCK_DGRAM, 0);if(sockfd<0)perror("socket error" );// 2、准备多播组地址和端口struct sockaddr_in servaddr;bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons (10086);if (inet_pton(AF_INET, "239.0.1.1", &servaddr.sin_addr) <= 0)perror("inet_pton error");// 4、使用 sendto 发送多播组数据报if(sendto(sockfd, "Hello,I am udp client", strlen("Hello,I am udp client"), 0, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)perror("sendto error" );// 5、处理应答char recvline[256];int n = 0;struct sockaddr_in tmpAddr;bzero(&tmpAddr, sizeof(tmpAddr));socklen_t addrLen=sizeof(tmpAddr);while ( (n = recvfrom (sockfd, recvline, sizeof(recvline), 0, (struct sockaddr*)&tmpAddr, &addrLen)) > 0){recvline[n] = 0 ;/*null terminate */printf("recvfrom ip=[%s], [%s]\n",inet_ntoa(tmpAddr.sin_addr), recvline);bzero(&tmpAddr, sizeof(tmpAddr));}if (n < 0)perror("read error" );// 6、关闭close(sockfd);return 0;
}

在4台机器运行多播接收端,下面是发送端的运行结果,发出多播数据报后,收到了各个接收端的回复:
在这里插入图片描述


在这里插入图片描述

🎄六、总结

👉本文介绍多播的概念,多播地址,多播数据报发送过程,最后给出C语言实现多播的例子。

在这里插入图片描述
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何选择适合您需求的虚拟主机服务

随着互联网的发展&#xff0c;虚拟主机服务在网站托管领域扮演着至关重要的角色。我们在前几天遇到客户咨询如何在Hostease服务商选择适合的主机服务。本文将介绍如何选择适合您需求的虚拟主机服务&#xff0c;以确保您的网站或应用程序能够稳定运行并获得最佳性能。 确定您的需…

常见的验证码

一、短信验证码 前端&#xff1a; 用户填写手机号&#xff0c;点击按钮发送请求用户短信得到验证码后&#xff0c;用户填写表单提交 form 表单&#xff0c;进行验证 后台&#xff1a; 随机生成几位验证码并将生成时间、手机号、验证码存储起来&#xff0c;可以存到session、…

小游戏加固方案已全面适配微信、QQ、抖音、快手、美团、华为、支付宝渠道

2023年&#xff0c;国内移动游戏收入与游戏用户规模双双创下历史新高。其中小游戏异军突起&#xff0c;市场规模达到200亿元&#xff0c;同比增长300%&#xff0c;成了万众瞩目的行业新风口。 小游戏的高速发展带来了更多的活力&#xff0c;产出了多款月流水过亿的热门游戏。行…

webpack编译报错Cannot find module ‘@babel/core‘且无法识别es6的reset语法

~ npm install babel-core babel-loader --save-dev 用了这个指令后webpack报错 尝试重新下载了babel-core babel-loader 还是不行 Cannot find module babel/core babel-loader8 requires Babel 7.x (the package babel/core). If youd like to use Babel 6.x (babel-core), …

Matter 笔记1-环境准备,编译

不要远程登录Ubuntu输入以下命令&#xff0c;原因&#xff1a;ubuntu/linux上的http代理设置 1. 准备 1.1 工具 Ubuntu 22.04 LTSClash 里General的端口设置到ubuntu 的网络设置里 1.2 代码 这里使用芯科整理过的代码 git clone https://github.com/SiliconLabs/matter.…

3. springboot中集成部署vue3

1. vue3构建 构建命令 npm run build&#xff0c; 构建的结果在disc目录&#xff1a; 2. springboot集成 2.1 拷贝vue3构建结果到springboot resources/static目录 2.2 springboot pom依赖 添加thymeleaf依赖 <dependency><groupId>org.springframework.boot</…

Rust错误处理和Result枚举类异常错误传递

Rust 有一套独特的处理异常情况的机制&#xff0c;它并不像其它语言中的 try 机制那样简单。 首先&#xff0c;程序中一般会出现两种错误&#xff1a;可恢复错误和不可恢复错误。 可恢复错误的典型案例是文件访问错误&#xff0c;如果访问一个文件失败&#xff0c;有可能是因…

乔琼:高性能会议传声器的产品优化设计| 演讲嘉宾公布

一、智能家居与会议系统 智能家居与会议系统分论坛将于3月28日同期举办&#xff01; 智能会议系统它通过先进的技术手段&#xff0c;提高了会议效率&#xff0c;降低了沟通成本&#xff0c;提升了参会者的会议体验。对于现代企业、政府机构和学术界是不可或缺的。在这里&#x…

arm系统构建的基础知识

目录 一、环境变量 二、归档和压缩 (一) 常用命令 (二) 常用参数 三、磁盘分区和挂载 四、网络管理 一、环境变量 显示环境变量 —— echo设置临时环境变量 —— exportecho $PATH —— 显示当前PATH环境变量 在当前目录下&#xff0c;编写一个hello.c 编译并运行。 图…

千帆AppBuilder使用指南-组件中心

应用中心 百度智能云千帆AppBuilder&#xff08;以下简称为AppBuilder&#xff09;应用中心&#xff0c;提供了大量可以立即体验的应用示例&#xff0c;开发者可以在这里搜索感兴趣的应用进行使用。 官方应用&#xff1a;AppBuilder官方提供的应用&#xff0c;可以立即体验应用…

【nowcoder】NC248 左叶子之和

NC248 左叶子之和 计算给定二叉树的左叶子之和。 树上叶子节点指没有后继节点的节点&#xff0c;左叶子指连向父节点的左侧的叶子节点。 int sumOfLeftLeaves(struct TreeNode* root ) {if (root ! NULL) {int sum 0;if (root->left ! NULL && root->left->…

【CSP试题回顾】201409-3-字符串匹配

CSP-201409-3-字符串匹配 关键点&#xff1a;<string>库函数的使用 length() 或 size(): 返回字符串的长度。 empty(): 检查字符串是否为空。 append() 或 : 向字符串的末尾添加字符或另一个字符串。 insert()在字符串的指定位置插入另一个字符串或字符。 std::str…

redis未设置密码被植入挖矿脚本

最近一台测试linux响应速度贼慢&#xff0c;检查发现cpu消耗高达100%&#xff01;查看进程杀死后过段时间又重启了&#xff0c;一时间也摸不到头绪。无意间发现启动redis的时候cpu瞬间拉到了100%&#xff0c;主要就是zzh和newinit.sh两个脚本。百度了一下说是被植入了挖矿脚本&…

玩转安卓之配置gradle-8.2.1

概述&#xff1a;看了一下&#xff0c;由于gradle是国外的&#xff0c;所以下载速度很慢&#xff0c;这个老师又是很菜的类型&#xff0c;同学又不会&#xff0c;于是曹某就写这一篇文章&#xff0c;教大家学会简单的为安卓配置gradle-8.2.1。 第一步&#xff1a;下载gradle-8…

C++复习笔记——泛型编程模板

01 模板 模板就是建立通用的模具&#xff0c;大大提高复用性&#xff1b; 02 函数模板 C另一种编程思想称为 泛型编程 &#xff0c;主要利用的技术就是模板 C 提供两种模板机制:函数模板和类模板 函数模板语法 函数模板作用&#xff1a; 建立一个通用函数&#xff0c;其函…

【kubernetes】关于k8s集群的配置资源(configmap和secret)

目录 一、Secret 类型一&#xff1a;kubernetes.io/service-account-token 类型二&#xff1a;普通类型secret&#xff0c; ●Opaque&#xff0c;base64 编码格式的 Secret&#xff0c;用来存储用户自定义的密码、密钥等&#xff0c;默认的 Secret 类型; 类型三&#xff1a;…

tiktok矩阵引流系统开发常用源代码!

在数字营销领域&#xff0c;TikTok已成为一个不可忽视的平台&#xff0c;随着其用户基数的不断增长&#xff0c;如何利用TikTok进行有效的引流成为了许多企业和营销人员关注的焦点。 为了实现这一目标&#xff0c;许多开发者开始构建TikTok矩阵引流系统&#xff0c;这些系统通…

基于docker安装的Jenkins实现python执行自动化测试程序

背景 通过Jenkins实现自动化测试,在全局配置中配置好后,执行构建发生如下错误 解决办法: 在Jenkins中插件管理中下载python后,回到Jenkins容器中 查找刚下载的python所在位置 到Jenkins中全局配置中修改脚本 1.可以在环境变量中定义python所在位置 2.在一下图示中进行获取…

数据解读乡村发展!专家详解 2024 年(第 17 届)中国大学生计算机设计大赛大数据主题赛赛题

2024 年&#xff08;第 17 届&#xff09;中国大学生计算机设计大赛大数据主题赛“数据解读乡村发展”赛题已于和鲸平台正式开赛&#xff0c;一月来&#xff0c;已有来自全国超百所高校的优秀本科生积极响应大赛号召完成报名。 为进一步使广大师生对于赛题主旨形成更清晰的认知…

尝试各种可以联网的AI

phind https://www.phind.com/ 搜索次数限制&#xff1a;无 右侧显示搜索引用文章地址链接以及大致内容缩略显示 左侧显示总结 perplexity https://www.perplexity.ai/ 搜索次数限制&#xff1a;每四小时5次搜索 内容上下分层&#xff0c;样式如下&#xff1a; Sources 显示…