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

这篇具有很好参考价值的文章主要介绍了【Linux C | 网络编程】多播的概念、多播地址、UDP实现多播的C语言例子。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

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


【Linux C | 网络编程】多播的概念、多播地址、UDP实现多播的C语言例子,Linux系统编程🏆,网络,linux,c语言,多播,多播地址,源特定多播

🎄一、多播概述

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

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

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

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


【Linux C | 网络编程】多播的概念、多播地址、UDP实现多播的C语言例子,Linux系统编程🏆,网络,linux,c语言,多播,多播地址,源特定多播

🎄二、多播地址

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

✨2.1、IPv4 多播地址

IPv4的D类地址(从224.0.0.0到239.255.255.255)是IPv4多播地址,见下图:
【Linux C | 网络编程】多播的概念、多播地址、UDP实现多播的C语言例子,Linux系统编程🏆,网络,linux,c语言,多播,多播地址,源特定多播
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位

【Linux C | 网络编程】多播的概念、多播地址、UDP实现多播的C语言例子,Linux系统编程🏆,网络,linux,c语言,多播,多播地址,源特定多播

下面是若干特殊的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地址来传输数据。

【Linux C | 网络编程】多播的概念、多播地址、UDP实现多播的C语言例子,Linux系统编程🏆,网络,linux,c语言,多播,多播地址,源特定多播

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多播地址的一部分直接复制到以太网地址中,并添加特定的前缀来确保唯一性。


【Linux C | 网络编程】多播的概念、多播地址、UDP实现多播的C语言例子,Linux系统编程🏆,网络,linux,c语言,多播,多播地址,源特定多播

🎄三、多播的过程

下图是可以展示多播的过程:
【Linux C | 网络编程】多播的概念、多播地址、UDP实现多播的C语言例子,Linux系统编程🏆,网络,linux,c语言,多播,多播地址,源特定多播
多播的过程:

  • 首先,接收主机(图中右侧)需要在接收进程创建一个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的套接字不存在)。

【Linux C | 网络编程】多播的概念、多播地址、UDP实现多播的C语言例子,Linux系统编程🏆,网络,linux,c语言,多播,多播地址,源特定多播

🎄四、源特定多播

✨4.1 广域网的多播

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

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


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

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

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

【Linux C | 网络编程】多播的概念、多播地址、UDP实现多播的C语言例子,Linux系统编程🏆,网络,linux,c语言,多播,多播地址,源特定多播

🎄五、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套接字socket
	int 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、绑定多播组端口 bind
	if (bind(sockfd,(struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
		perror("bind error" );
	
	// 4、加入多播组 239.0.1.1
	struct 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套接字socket
	int 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台机器运行多播接收端,下面是发送端的运行结果,发出多播数据报后,收到了各个接收端的回复:
【Linux C | 网络编程】多播的概念、多播地址、UDP实现多播的C语言例子,Linux系统编程🏆,网络,linux,c语言,多播,多播地址,源特定多播


【Linux C | 网络编程】多播的概念、多播地址、UDP实现多播的C语言例子,Linux系统编程🏆,网络,linux,c语言,多播,多播地址,源特定多播

🎄六、总结

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

【Linux C | 网络编程】多播的概念、多播地址、UDP实现多播的C语言例子,Linux系统编程🏆,网络,linux,c语言,多播,多播地址,源特定多播
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁文章来源地址https://www.toymoban.com/news/detail-838346.html

到了这里,关于【Linux C | 网络编程】多播的概念、多播地址、UDP实现多播的C语言例子的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【探索Linux】P.25(网络编程套接字基本概念 —— 预备知识)

    在上一篇文章中,我们深入探讨了Linux网络的基础知识和它的发展历史,为读者揭开了Linux网络技术演变的序幕。我们了解到,Linux网络技术的发展不仅促进了操作系统本身的成熟,还对整个互联网的进步产生了深远的影响。随着网络技术的不断进步,Linux系统在网络通信方面

    2024年04月27日
    浏览(49)
  • 【探索Linux】—— 强大的命令行工具 P.26(网络编程套接字基本概念—— socket编程接口 | socket编程接口相关函数详细介绍 )

    本文将深入探讨使用套接字进行网络通信的基本步骤,包括创建套接字、绑定地址、监听连接(对于服务器端)、连接远程主机(对于客户端)、以及发送和接收数据等操作。套接字编程涉及一系列系统调用和函数,如 socket() 、 bind() 、 listen() 、 connect() 、 send() 、 recv() 等。

    2024年03月10日
    浏览(84)
  • Java网络编程(一)基本网络概念

            网络(network) 是几乎可以实时相互发送和接收数据的计算机和其他设备的集合。网络通常用线缆连接,数据位转换为电磁波,通过线缆移动。不过,无线网络会通过无线电波传输数据,许多长距离的传输现在会用通过玻璃纤维发送可见光的光纤电缆来完成。传输数

    2024年02月16日
    浏览(45)
  • 【网络编程】网络编程概念,socket套接字,基于UDP和TCP的网络编程

    前言: 大家好,我是 良辰丫 ,今天我们一起来学习网络编程,网络编程的基本概念,认识套接字,UDP与TCP编程.💞💞💞 🧑个人主页:良辰针不戳 📖所属专栏:javaEE初阶 🍎励志语句:生活也许会让我们遍体鳞伤,但最终这些伤口会成为我们一辈子的财富。 💦期待大家三连,关注

    2023年04月20日
    浏览(61)
  • [C++ 网络协议编程] 域名及网络地址

    DNS(Domain Name System):是对IP地址和域名(如:www.baidu.com等)进行相互转换的系统,其核心是DNS服务器。 我们输入的www.baidu.com是域名,是一种虚拟地址,而非实际地址,DNS服务器会将这个虚拟地址转换为实际地址,即IP地址。若我们直接输入IP地址,则不会发生上面的转换。

    2024年02月12日
    浏览(41)
  • Linux网络编程:IP地址的字符串与网络字节序转换:inet_addr()、inet_aton()、inet_ntoa()、inet_pton()、inet_ntop()

    IP地址的字符串与网络字节序转换 向sockaddr_in注入地址时,需要将ip地址的字符串形式转化为网络字节序的形式;而相反地,网络字节序也能转化回字符串形式。用到的函数分别inet_addr()、inet_aton()、inet_ntoa()、inet_pton()、inet_ntop(),转化的方向如下图。 1 inet_addr() 功能:是将一

    2024年02月03日
    浏览(47)
  • 网络编程 http 相关基础概念

    HTTP表单是一种用于在Web应用程序中收集用户输入数据的机制。它由HTML表单元素和HTTP请求组成。 HTML表单元素(如、、等)用于创建用户界面,让用户输入数据。用户可以在表单中填写文本、选择选项、上传文件等。 当用户提交表单时,浏览器会将表单数据封装在HTTP请求中,

    2024年02月11日
    浏览(44)
  • 《TCP/IP网络编程》阅读笔记--域名及网络地址

    目录 1--域名系统 2--域名与 IP 地址的转换 2-1--利用域名来获取 IP 地址 2-2--利用 IP 地址获取域名 3--代码实例 3-1--gethostbyname() 3-2--gethostbyaddr()         域名系统(Domain Name System, DNS )是对 IP 地址和域名进行相互转换 的系统,其核心是 DNS 服务器;         一般来说, IP

    2024年02月09日
    浏览(65)
  • TCP IP网络编程(三) 地址族与数据序列

    网络地址 IP地址分为两类: IPv4 4字节地址族 IPv6 16字节地址族 IPv4和IPv6的差别主要是表示在IP地址所用的字节数,目前通用的地址族为IPv4,而IPv6是为了应对IP地址耗尽的问题而提出的标准,目前主要还是使用IPv4 IPv4标准的4字节IP地址分为网络地址和主机地址,且分为A、B、C、

    2024年02月10日
    浏览(86)
  • 一文带你彻底了解java 网络编程的基本概念

    主题:探索Java网络编程:构建连接世界的桥梁 作者:Stevedash 发布日期:2023年8月11日 15点18分 (PS:这一篇文章作为总章,今天着重讲“Socket套接字编程”这里的知识,其他模块的知识,后续补上,拆分成单独章节来慢慢完善该文,并且后面会附带上其他文章的链接,会持续

    2024年02月13日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包