当前位置:   article > 正文

Linux C编程 socket——Udp组播(多播)_linux 组播

linux 组播

Udp多播简介

概述

  1. 单播用于两个主机间单对单的通信
  2. 广播用于一个主机对整个局域网上所有主机上的数据通信
  3. 单播和广播是两个极端,要么对一个主机进行通信,要么对整个局域网的主机进行通信
  4. 实际情况下,经常需要对一组特定的主机进行通信,而不是所有局域网上的主机,这时候就有了组播
  5. IP组播(也称多址广播或多播),是一种允许一台或多台主机发送数据包到多台主机的TCP/IP网路技术。
  6. 多播是 IPv6 数据包的 3 种基本目的地址类型之一,多播是一点对多点的通信, IPv6 没有采用 IPv4 中的组播术语,而是将广播看成是多播的一个特殊例子。

组播应用

  1. 点对多点应用

点对多点应用是指一个发送者,多个接收者的应用形式,这是最常见的多播应用形式。典型的应用包括:媒体广播、媒体推送、信息缓存、事件通知和状态监视等。

  1. 多点对点应用

多点对点应用是指多个发送者,一个接收者的应用形式。通常是双向请求响应应用,任何一端(多点或点)都有可能发起请求。典型应用包括:资源查找、数据收集、网络竞拍、信息询问等。

  1. 多点对多点应用

多点对多点应用是指多个发送者和多个接收者的应用形式。通常,每个接收者可以接收多个发送者发送的数据,同时,每个发送者可以把数据发送给多个接收者。典型应用包括:多点会议、资源同步、并行处理、协同处理、远程学习、讨论组、分布式交互模拟(DIS)、多人游戏等。

组播地址

IP 组播通信必须依赖于 IP 多播地址,在 IPv4 中它是一个 D 类 IP 地址,范围从 224.0.0.0 到 239.255.255.255,并被划分为局部链接多播地址、预留多播地址和管理权限多播地址三类:

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,可限制多播范围。

组播地址与MAC地址的映射

  • 使用同一个 IP 多播地址接收多播数据包的所有主机构成了一个主机组,也称为多播组。一个多播组的成员是随时变动的,一台主机可以随时加入或离开多播组,多播组成员的数目和所在的地理位置也不受限制,一台主机也可以属于几个多播组。

  • 这个我们可以这样理解,多播地址就类似于 QQ 群号,多播组相当于 QQ 群,一个个的主机就相当于群里面的成员。

  • 设备驱动程序就必须接收所有多播数据帧,然后对它们进行过滤,这个过滤过程是网络驱动或IP层自动完成。(设备驱动程序会对多播数据进行过滤,将其发到相应的位置)

Udp组播编程

函数简介

  1. setsockopt函数
  #include <sys/types.h>          /* See NOTES */
  #include <sys/socket.h>
  int setsockopt(int sockfd, int level, int optname,
                      const void *optval, socklen_t optlen);

  • 1
  • 2
  • 3
  • 4
  • 5
  1. level
  • IPPROTO_IP
  1. optname
  • IP_MULTICAST_LOOP 支持多播数据回送
  • IP_ADD_MEMBERSHIP 加入多播组
  • IP_DROP_MEMBERSHIP 离开多播组
  1. optval
  • IP_MULTICAST_LOOP 选项对应传入 unsigned int 来确认是否支持多播数据回送
  • IP_ADD_MEMBERSHIP 传入 ip_mreq
  • IP_DROP_MEMBERSHIP 传入 ip_mreq

结构体原型

struct in_addr
{
in_addr_t s_addr;
}
struct ip_mreq          
{ 

struct in_addr imn_multiaddr; // 多播组 IP,类似于 QQ 群号

struct in_addr imr_interface;   // 将要添加到多播组的 IP,类似于QQ 成员号

};

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

tips:
多播组只能用UDP 或者原始套接字实现,不能用TCP

UDP组播示例

说明接收组播地址为224.0.0.88 或者 224.0.0.66 的信息,

//Udp_group_recv.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>


int main(int argc,char *argv[])
{	
	int socked=socket(AF_INET,SOCK_DGRAM,0);  
	char group[16]="224.0.0.88";
	char group_1[16]="224.0.0.66";
	if(socked<0)
	{
		perror("socket failed!");
		return 2;
	}
	
	struct sockaddr_in local_addr;
	memset(&local_addr,0,sizeof(local_addr));
	
	local_addr.sin_family=AF_INET;
	local_addr.sin_addr.s_addr=htonl(INADDR_ANY);
	local_addr.sin_port=htons(8888);
	
	int ret=bind(socked,(struct sockaddr*)&local_addr,sizeof(local_addr));
	if(ret<0)
	{
		perror("bind failed !");
		return 3;
	}
	
	struct ip_mreq mreq; // 多播地址结构体
	mreq.imr_multiaddr.s_addr=inet_addr(group);
	mreq.imr_interface.s_addr = htonl(INADDR_ANY);
	
	ret=setsockopt(socked,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));
	if(ret<0)
	{
		perror("setsockopt failed !");
		return 3;
	}
	else
	{
		printf("setsockopt success\n");		
	}
	mreq.imr_multiaddr.s_addr=inet_addr(group_1);
	ret=setsockopt(socked,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));
	if(ret<0)
	{
		perror("setsockopt_1 failed !");
		return 3;
	}
	else
	{
		printf("setsockopt_1 success\n");		
	}
	char buf[1024];
	int length=0;
	struct sockaddr_in sender;
	int sender_len=sizeof(sender);
 	while(1)
	{
		memset(buf, 0, sizeof(buf));  
		length=recvfrom(socked,buf,sizeof(buf),0,(struct sockaddr*)&sender,&sender_len);
		buf[length]='\0';
		printf("%s %d : %s\n",inet_ntoa(sender.sin_addr),ntohs(sender.sin_port),buf);
	}
	setsockopt(socked, IPPROTO_IP, IP_DROP_MEMBERSHIP,&mreq, sizeof(mreq));
	close(socked);
	return 0;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78

在这里插入图片描述
在这里插入图片描述

//向组播地址为224.0.0.88的组发送信息

Udp_group_send.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>


int main(int argc,char *argv[])
{	
    char group_addr[16]="224.0.0.88";
	int socked=socket(AF_INET,SOCK_DGRAM,0);  
	if(socked<0)
	{
		perror("socket failed!");
		return 2;
	}
	
	struct sockaddr_in remote_addr;
	memset(&remote_addr,0,sizeof(remote_addr));
	
	remote_addr.sin_family=AF_INET;
	remote_addr.sin_addr.s_addr=inet_addr(group_addr);
	remote_addr.sin_port=htons(8888);
	
	char buf[1024]="This is a group udp";
	int length=0;
 	while(1)
	{
		memset(buf, 0, sizeof(buf));  
		
		length=sendto(socked,buf,strlen(buf),0,(struct sockaddr *)&remote_addr,sizeof(remote_addr));
		printf("Send Message%s\n",buf);
	}
	close(socked);
	return 0;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/187182
推荐阅读
相关标签
  

闽ICP备14008679号