多播

广播和多播(组播)仅用于UDP

多播,也称为“组播”,将局域网中同一业务类型主机进行了逻辑上的分组,进行数据收发的时候其数据仅仅在同一分组中进行,其他的主机没有加入此分组不能收发对应的数据。

多播IP地址

多播的地址是特定的,D类地址用于多播。D类IP地址就是多播IP地址,即224.0.0.0至239.255.255.255之间的IP地址,并被划分为局部连接多播地址、预留多播地址和管理权限多播地址3类:

  • 局部多播地址:在224.0.0.0~224.0.0.255之间,这是为路由协议和其他用途保留的地址,路由器并不转发属于此范围的IP包
  • 预留多播地址:在224.0.1.0~238.255.255.255之间,可用于全球范围(如Internet)或网络协议
  • 管理权限多播地址:在239.0.0.0~239.255.255.255之间,可供组织内部使用,类似于私有IP地址,不能用于Internet,可限制多播范围

其他特殊地址

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网络时间协议

 

多播地址到以太网地址的转换

以太网多播地址范围地址:01:00:5e:00:00:00 -- 01:00:5e:7f:ff:ff

地址都以01:00:5e开头。第25位为0,低23位为IPv4组播地址的低23位。IPv4组播地址与MAC地址的映射关系如图所示:

由于多播组号中的最高5bit在映射过程中被忽略,因此每个以太网多播地址对应的多播组是不唯一的。32个不同的多播组号被映射为一个以太网地址。例如,多播地址224.128.64.32(十六进制e0.80.40.20)和224.0.64.32(十六进制e0.00.40.20)都映射为同一以太网地址01:00:5e:00:40:20。

 

多播编程步骤

1>建立一个socket;
2>设置多播的参数,例如超时时间TTL,本地回环许可LOOP等
3>加入多播组
4>发送和接收数据
5>从多播组离开

多播程序设计使用setsockopt()函数和getsockopt()函数来实现,组播的选项是IP层的。

 

1 int setsockopt(
2 SOCKET s,
3 int level,
4 int optname,
5 const char* optval,
6 int optlen
7 );

 

s(套接字): 指向一个打开的套接口描述字
level:(级别): 指定选项代码的类型。
SOL_SOCKET: 基本套接口
  IPPROTO_IP: IPv4套接口
  IPPROTO_IPV6: IPv6套接口
  IPPROTO_TCP: TCP套接口
optname(选项名): 选项名称

getsockopt()/setsockopt()的选项

    义

IP_MULTICAST_TTL

设置多播组数据的TTL值

IP_ADD_MEMBERSHIP

在指定接口上加入组播组

IP_DROP_MEMBERSHIP

退出组播组

IP_MULTICAST_IF

获取默认接口或设置接口

IP_MULTICAST_LOOP

禁止组播数据回送

 


optval(选项值): 是一个指向变量的指针 类型:整形,套接口结构, 其他结构类型:linger{}, timeval{ }
optlen(选项长度) :optval 的大小

 

广播组结构体:

1 struct ip_mreq          
2 { 
3     struct in_addr imn_multiaddr;      /*加入或者退出的广播组IP地址*/ 
4    struct in_addr imr_interface;      /*加入或者退出的网络接口IP地址*/
5 };

 

加入或者退出一个多播组,通过选项IP_ADD_MEMBERSHIP和IP_DROP_MEMBERSHIP,对一个结构struct ip_mreq类型的变量进行控制

选项IP_ADD_MEMBERSHIP用于加入某个多播组,之后就可以向这个多播组发送数据或者从多播组接收数据。此选项的值为mreq结构,成员imn_multiaddr是需要加入的多播组IP地址,成员imr_interface是本机需要加入广播组的网络接口IP地址。例如:

1 struct ip_mreq mreq;
2 setsockopt(s,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));

 

 

实例

服务端:

 1 #include<iostream>
 2 #include<stdio.h>
 3 #include<sys/socket.h>
 4 #include<netdb.h>
 5 #include<sys/types.h>
 6 #include<arpa/inet.h>
 7 #include<netinet/in.h>
 8 #include<unistd.h>
 9 #include<stdlib.h>
10 #include<string.h>
11 #define MCAST_PORT 8888
12 #define MCAST_ADDR "224.0.0.88"  // 多播地址
13 #define MCAST_DATA "BROADCAST TEST DATA"  // 多播内容
14 #define MCAST_INTERVAL 5  //多播时间间隔
15 using namespace std;
16 
17 int main()
18 {
19     int sock;
20     struct sockaddr_in mcast_addr;
21     sock=socket(AF_INET,SOCK_DGRAM,0);
22     if(sock==-1)
23     {
24         cout<<"socket error"<<endl;
25         return -1;
26     }
27     memset(&mcast_addr,0,sizeof(mcast_addr));
28     mcast_addr.sin_family=AF_INET;
29     mcast_addr.sin_addr.s_addr=inet_addr(MCAST_ADDR);
30     mcast_addr.sin_port=htons(MCAST_PORT);
31     while(1)
32     {       //向局部多播地址发送多播内容
33         int n=sendto(sock,MCAST_DATA,sizeof(MCAST_DATA),0,(struct sockaddr*)&mcast_addr,sizeof(mcast_addr));
34         if(n<0)
35         {
36             cout<<"send error"<<endl;
37             return -2;
38         }
39         else
40         {
41             cout<<"send message is going ...."<<endl;
42         }
43         sleep(MCAST_INTERVAL);
44 
45     }
46     return 0;
47 }

 

客户端:

 1 #include<iostream>
 2 #include<stdio.h>
 3 #include<stdlib.h>
 4 #include<string.h>
 5 #include<sys/types.h>
 6 #include<unistd.h>
 7 #include<sys/socket.h>
 8 #include<netdb.h>
 9 #include<arpa/inet.h>
10 #include<netinet/in.h>
11 #define MCAST_PORT 8888
12 #define MCAST_ADDR "224.0.0.88" /*一个局部连接多播地址,路由器不进行转发*/
13 #define MCAST_INTERVAL 5  //发送时间间隔
14 #define BUFF_SIZE 256   //接收缓冲区大小
15 using namespace std;
16 int main()
17 {
18     int sock;
19     struct sockaddr_in local_addr;
20     int err=-1;
21     sock=socket(AF_INET,SOCK_DGRAM,0);
22     if(sock==-1)
23     {
24         cout<<"sock error"<<endl;
25         return -1;
26     }
27     /*初始化地址*/
28     local_addr.sin_family=AF_INET;
29     local_addr.sin_addr.s_addr=htonl(INADDR_ANY);
30     local_addr.sin_port=htons(MCAST_PORT);
31     /*绑定socket*/
32     err=bind(sock,(struct sockaddr*)&local_addr,sizeof(local_addr));
33     if(err<0)
34     {
35         cout<<"bind error"<<endl;
36         return -2;
37     }
38     /*设置回环许可*/
39     int loop=1;
40     err=setsockopt(sock,IPPROTO_IP,IP_MULTICAST_LOOP,&loop,sizeof(loop));
41     if(err<0)
42     {
43         cout<<"set sock error"<<endl;
44         return -3;
45     }
46     struct ip_mreq mreq;/*加入广播组*/
47     mreq.imr_multiaddr.s_addr=inet_addr(MCAST_ADDR);//广播地址
48     mreq.imr_interface.s_addr=htonl(INADDR_ANY); //网络接口为默认
49     /*将本机加入广播组*/
50     err=setsockopt(sock,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));
51     if(err<0)
52     {
53         cout<<"set sock error"<<endl;
54         return -4;
55     }
56     int times=0;
57     socklen_t addr_len=0;
58     char buff[BUFF_SIZE];
59     int n=0;
60     /*循环接受广播组的消息,5次后退出*/
61     for(times=0;;times++)
62     {
63         addr_len=sizeof(local_addr);
64         memset(buff,0,BUFF_SIZE);
65         n=recvfrom(sock,buff,BUFF_SIZE,0,(struct sockaddr*)&local_addr,&addr_len);
66         if(n==-1)
67         {
68             cout<<"recv error"<<endl;
69             return -5;
70         }
71         /*打印信息*/
72         printf("RECV %dst message from server : %s\n",times,buff);
73         sleep(MCAST_INTERVAL);
74     }
75     /*退出广播组*/
76     err=setsockopt(sock,IPPROTO_IP,IP_DROP_MEMBERSHIP,&mreq,sizeof(mreq));
77     close(sock);
78     return 0;
79 }

 

posted on 2015-12-07 21:40  已停更  阅读(967)  评论(0编辑  收藏  举报