UDP 广播组播点播的区别及联系

1、网络IP地址的分类

组播地址是分类编址的IPv4地址中的D类地址,又叫多播地址,他的前四位必须是1110,所以网络地址的二进制取值范围是11100000~11101111对应的十进制为 224~~239。所以以224~239开头的网络地址都是组播地址。

组播地址的功能分类:

224.0.0.0~224.0.0.255为预留的组播地址(永久组地址)。

224.0.1.0~224.0.1.255是公用组播地址,可以用于Internet。

224.0.2.0~238.255.255.255为用户可用的组播地址(临时组地址),全网范围内有效。

239.0.0.0~239.255.255.255为本地管理组播地址,仅在特定的本地范围内有效。

组播优势: 降低网络流量,减轻硬件负荷,减少冗余流量,节约带宽。
**组播应用:**多媒体、任何"单到多"数据发布应用。

2、单播、组播和广播的区别

组播(Multicast, 又称多播)是UDP专有的, 关于UDP的单播(Unicast), 组播, 广播(Broadcast)的区别, 网络上有张比较形象的图如下:

组播工作原理:

1)组播使用特殊的IPv4组播地址(224.0.0.0至239.255.255.255),组播地址是一种特殊的IP地址,用于标识一个组播组。

2)Internet组管理协议(IGMP)是一种用于主机加入和离开组播组的协议。主机通过发送IGMP报文来通知路由器它们希望加入或离开一个组播组。路由器根据接收到的IGMP报文来维护组播组的成员列表。

3)路由器:组播数据的传输需要路由器的支持。路由器通过使用组播路由协议(如PIM、IGMP等)来维护组播组的成员信息,并根据这些信息将组播数据转发到适当的接口上。

4)数据传输:当一个主机发送组播数据时,它将数据包发送到一个特定的组播地址。路由器根据组播地址组员列表来确定将数据包转发到哪些接口上。只有加入了组播组的主机才会接收到组播数据。

总结:组播的原理是通过使用特定的组播地址和IGMP协议来实现多个主机之间 的组播通信。路由器 根据组员列表来转发组播数据,只有加入了组播组的主机才能接收到数据。组播可以提供高效的数据传输,适用于需要向多个目标主机发送相同数据的场景,如视频流、实时通信等。

3、 加入和离开组播组

3.1指令方式

加入组播组指令:sudo ip addr add 239.0.0.1 dev eth1 autojoin

离开组播组指令:sudo ip addr del 239.0.0.1/24 dev eth1 autojoin

3.2代码方式

**加入组播组:**加入组播组使用setsockopt设置IP_ADD_MEMBERSHIP选项。

struct ip_mreq multi_addr;

bzero(&multi_addr, sizeof(multi_addr));

multi_addr.imr_multiaddr.s_addr = inet_addr("239.0.0.1");

multi_addr.imr_interface.s_addr = INADDR_ANY;
setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&multi_addr, sizeof(multi_addr));

离开组播组:离开组播组使用setsockopt设置IP_DROP_MEMBERSHIP选项。

struct ip_mreq multi_addr;

bzero(&multi_addr, sizeof(multi_addr));

multi_addr.imr_multiaddr.s_addr = inet_addr("239.0.0.1");

multi_addr.imr_interface.s_addr = INADDR_ANY;
setsockopt(sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (void *)&multi_addr, sizeof(multi_addr));

4、C语言编写接收和发送udp组播数据

4.1组播数据发送

cpp 复制代码
//组播发送初始化
int initUdpMultiCastSender(uint32_t localip,uint16_t localport)
{
	int sockfd = socket(AF_INET,SOCK_DGRAM,0);//创建套接字
	if (-1 == sockfd)
	{
		printf("[initUdpMultiCastSender]socket fail\n");
		return -1;
	}
    //设置本地的组播地址和端口(注意:该port不是组播port,而是本地port)
	struct sockaddr_in myaddr;
	memset(&myaddr,0,sizeof(myaddr));
	myaddr.sin_family = AF_INET;
	myaddr.sin_port = htons(localport);
	myaddr.sin_addr.s_addr = localip;
	int bindret = bind(sockfd,(struct sockaddr *)(&myaddr),sizeof(struct sockaddr));
	if (-1 == bindret)
	{
		perror("[initUdpMultiCastSender]bind fail\n");
		close(sockfd);
		return -1;
	}
	return sockfd;
}
//组播数据发送--注意发送的ip和port为组播ip,port
int sendUdpMultiCast(int sockfd,char *pMultiCastIp,uint16_t multicastPort,void *data,uint32_t len)
{
	struct sockaddr_in destAddr;
	destAddr.sin_family = AF_INET;
	destAddr.sin_addr.s_addr = inet_addr(pMultiCastIp);
	destAddr.sin_port = htons(multicastPort);
	int sendLen = sendto(sockfd,data,len,0,(struct sockaddr *)(&destAddr),sizeof(struct sockaddr));
	return sendLen;
}

4.2接收组播数据

cpp 复制代码
	int sockfd = socket(AF_INET,SOCK_DGRAM,0);
	if (-1 == sockfd)
	{
		perror("socket fail\n");
		return -3;
	}
	printf("socket succ\n");
 
	struct ip_mreq mreq;
	memset(&mreq,0,sizeof(struct ip_mreq));
	mreq.imr_interface.s_addr = htonl(INADDR_ANY);
	mreq.imr_multiaddr.s_addr = inet_addr(pUdpMultiCastIp);
    //加入组
	int setoptret = setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(struct ip_mreq));
	if (-1 == setoptret)
	{
		perror("setsockopt fail\n");
		return -4;
	}
	printf("setsockopt ip_add_membership succ\n");
 
	struct sockaddr_in peeraddr;
	memset(&peeraddr,0,sizeof(struct sockaddr_in));
	peeraddr.sin_family = AF_INET;
	peeraddr.sin_addr.s_addr = inet_addr(pUdpMultiCastIp);
	peeraddr.sin_port = htons(udpMultiCastPort);
    //绑定要接收的组播地址
	int bindRet = bind(sockfd,(struct sockaddr *)(&peeraddr),sizeof(struct sockaddr));
	if (-1 == bindRet)
	{
		perror("bind fail\n");
		return -5;
	}
	printf("bind succ\n");
 
	while(1)
	{
		char buffer[1024] = {0};
		socklen_t addrLen = sizeof(struct sockaddr);
		printf("ready 2 recv\n");
		int recvRet = recvfrom(sockfd,buffer,sizeof(buffer)-1,0,(struct sockaddr*)(&peeraddr),&addrLen);
		if (-1 == recvRet)
		{
			perror("recvfrom fail\n");
			break;
		}
		printf("recvfrom succ,buffer is %s\n",buffer);
	}

说明:接收端的代码,整体的思路就是创建socket->加入组播(本地地址和组播地址赋值给mreq)->绑定ip,port(注意,该ip和port是组播ip和组播port)->接收数据(注意,接收的ip和port为组播ip,port)。

相关推荐
河北瑾航科技2 小时前
广西水资源遥测终端 广西水利遥测终端 广西用水监测遥测终端 河北瑾航科技遥测终端机HBJH-B01说明书
网络·科技·水文遥测终端机·遥测终端机·广西水资源遥测终端机·广西水利遥测终端·广西用水终端
羑悻的小杀马特2 小时前
轻量跨云·掌控无界:Portainer CE + cpolar 让远程容器运维像点外卖一样简单——免复杂配置,安全直达对应集群
运维·网络·安全·docker·cpolar
愚戏师3 小时前
Python3 Socket 网络编程复习笔记
网络·笔记
降临-max4 小时前
JavaSE---网络编程
java·开发语言·网络·笔记·学习
156082072194 小时前
基于7VX690T FPGA实现万兆TCP/IP资源和性能测试
网络协议·tcp/ip·fpga开发
赖small强4 小时前
【Linux 网络基础】libwebsockets HTTPS 服务端实现机制详解
linux·网络·https·tls·libwebsockets
大白的编程日记.4 小时前
【计算网络学习笔记】MySql的多版本控制MVCC和Read View
网络·笔记·学习·mysql
踏浪无痕6 小时前
线上偶发 502 排查:用 Netty 成功复现 KeepAlive 时间窗口案例实战(附完整源码)
运维·网络协议
shmexon6 小时前
上海兆越亮相无锡新能源盛会,以硬核通信科技赋能“能碳未来”
网络·人工智能
爱学习的小可爱卢6 小时前
Java UDP编程实战:UDP数据报套接字编程DatagramPacket、DatagramSocket 、InetSocketAddress
java·udp·udp数据报