单播(Unicast)传输:在发送者和每一接收者之间需要单独的数据信道。 如果一台主机同时给很少量的接收者传输数据,一般没有什么问题。但如果有大量主机希望获得数据包的同一份拷贝时却很难实现。 这将导致发送者负担沉重、延迟长、网络拥塞;为保证一定的服务质量需增加硬件和带宽。
组播(Multicast)传输:它提高了数据传送效率。减少了主干网出现拥塞的可能性。组播组中的主机可以是在同一个物理网络, 也可以来自不同的物理网络(如果有组播路由器的支持)。
广播(Broadcast)传输:是指在IP子网内广播数据包,所有在子网内部的主机都将收到这些数据包。 广播意味着网络向子网主机都投递一份数据包,不论这些主机是否乐于接收该数据包。然而广播的使用范围非常小, 只在本地子网内有效,因为路由器会封锁广播通信。广播传输增加非接收者的开销。
二、组播技术
2.1、组播技术的原理
组播是一种允许一个或多个发送者(组播源)发送单一的数据包到多个接收者(一次的,同时的)的网络技术。 组播源把数据包发送到特定组播组,而只有属于该组播组的地址才能接收到数据包。组播可以大大的节省网络带宽, 因为无论有多少个目标地址,在整个网络的任何一条链路上只传送单一的数据包。 它提高了数据传送效率。减少了主干网出现拥塞的可能性。组播组中的主机可以是在同一个物理网络, 也可以来自不同的物理网络(如果有组播路由器的支持)。
2.2、实现组播技术的前提条件
实现IP组播传输,则组播源和接收者以及两者之间的下层网络都必须支持组播。这包括以下几方面:
* 主机的TCP/IP实现支持发送和接收IP组播;
* 主机的网络接口支持组播;
* 有一套用于加入、离开、查询的组管理协议,即IGMP(v1,v2);
* 有一套IP地址分配策略,并能将第三层IP组播地址映射到第二层MAC地址;
* 支持IP组播的应用软件;
* 所有介于组播源和接收者之间的路由器、集线器、交换机、TCP/IP栈、防火墙均需支持组播;
2.3、组播地址
在组播通信中,我们需要两种地址:一个IP组播地址和一个Ethernet组播地址。其中,IP组播地址标识一个组播组。 由于所有IP数据包都封装在Ethernet帧中,所以还需要一个组播Ethernet地址。为使组播正常工作, 主机应能同时接收单播和组播数据,这意味着主机需要多个IP和Ethernet地址。 IP地址方案专门为组播划出一个地址范围,在IPv4中为D类地址,范围是224.0.0.0到239.255.255.255, 并将D类地址划分为局部链接组播地址、预留组播地址、管理权限组播地址。
局部链接地址:224.0.0.0~224.0.0.255,用于局域网,路由器不转发属于此范围的IP包;
预留组播地址:224.0.1.0~238.255.255.255,用于全球范围或网络协议;
管理权限地址:239.0.0.0~239.255.255.255,组织内部使用,用于限制组播范围;
D类地址的最后28比特没有结构化,即没有网络ID和主机ID之分。响应某一个IP多播地址的主机构成一个主机组,主机组可跨越多个网络。主机组的成员 数是动态的,主机可以通过IGMP协议加入或离开某个主机组。IP多播地址影射到以太网地址的方法见下图。因为IP多播地址的高5位未影射,因此,影射的 以太网地址不是唯一的,共有32个IP多播地址影射到一个以太网地址。
2.4、组播协议:
组播协议主要包括组管理协议(IGMP)和组播路由协议(密集模式协议(如DVMRP,PIM-DM)、稀疏模式协议(如PIM-SM,CBT) 和链路状态协议(MOSPF))
* 组管理协议IGMP
主机使用IGMP通知子网组播路由器,希望加入组播组;路由器使用IGMP查询本地子网中是否有属于某个组播组的主机。
* 加入组播组
当某个主机加入某一个组播组时,它通过“成员资格报告”消息通知它所在的IP子网的组播路由器,同时将自己的IP模块做相应的准备, 以便开始接收来自该组播组传来的数据。如果这台主机是它所在的IP子网中第一台加入该组播组的主机, 通过路由信息的交换,组播路由器加入组播分布树。
* 退出组播组
在IGMP v1中,当主机离开某一个组播组时,它将自行退出。组播路由器定时(如120秒) 使用“成员资格查询” 消息向IP子网中的所有主机的组地址(224.0.0.1)查询,如果某一组播组在IP子网中已经没有任何成员, 那么组播路由器在确认这一事件后, 将不再在子网中转发该组播组的数据。与此同时,通过路由信息交换, 从特定的组播组分布树中删除相应的组播路由器。 这种不通知任何人而悄悄离开的方法, 使得组播路由器知道IP子网中已经没有任何成员的事件延时了一段时间,所以在IGMP v2.0中,当每一个主机离开某一个组播组时, 需要通知子网组播路由器,组播路由器立即向IP子网中的所有组播组询问,从而减少了系统处理停止组播的延时。
* 组播路由协议
要想在一个实际网络中实现组播数据包的转发,必须在各个互连设备上运行可互操作的组播路由协议。 组播路由协议可分为三类:密集模式协议(如DVMRP,PIM-DM)、稀疏模式协议(如PIM-SM,CBT) 和链路状态协议(MOSPF),下面分别介绍各个协议的工作原理。
* 距离向量组播路由协议(Distance Vector Multicast Routing Protocol:DVMRP)
DVMRP由单播路由协议RIP扩展而来,两者都使用距离向量算法得到网络的拓扑信息,不同之处在于RIP根据路由表前向转发数据, 而DVMRP则是基于RPF。为了使新加入的组播成员能及时收到组播数据,DVMPR采用定时发送数据包给所有的LAN的方法, 然而这种方法导致大量路由控制数据包的扩散,这部分开销限制了网络规模的扩大。另一方面,DVMRP使用跳数作为计量尺度, 其上限为32跳,这对网络规模也是一个限制。目前提出了分层DVMRP,即对组播网络划分区域, 在区域内的组播可以按照任何协议进行,而对于跨区域的组播则由边界路由器在DVMRP协议下进行,这样可大大减少路由开销。
* 开放式组播最短路径优先协议(Multicast Open Shortest Path First:MOSPF)
- Listener Program
-
- /*
- * listener.c -- joins a multicast group and echoes all data it receives from
- * the group to its stdout...
- */
-
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <stdlib.h>
- #include <time.h>
- #include <string.h>
- #include <stdio.h>
-
-
- #define HELLO_PORT 12345
- #define HELLO_GROUP "225.0.0.37"
- #define MSGBUFSIZE 256
-
- int main(int argc, char *argv[])
- {
- struct sockaddr_in addr;
- int fd, nbytes,addrlen;
- struct ip_mreq mreq;
- char msgbuf[MSGBUFSIZE];
-
- u_int yes=1; /*** MODIFICATION TO ORIGINAL */
-
- /* create what looks like an ordinary UDP socket */
- if ((fd=socket(AF_INET,SOCK_DGRAM,0)) < 0)
- {
- perror("socket");
- exit(1);
- }
-
-
- /**** MODIFICATION TO ORIGINAL */
- /* allow multiple sockets to use the same PORT number */
- if (setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(yes)) < 0)
- {
- perror("Reusing ADDR failed");
- exit(1);
- }
- /*** END OF MODIFICATION TO ORIGINAL */
-
- /* set up destination address */
- memset(&addr,0,sizeof(addr));
- addr.sin_family=AF_INET;
- addr.sin_addr.s_addr=htonl(INADDR_ANY); /* N.B.: differs from sender */
- addr.sin_port=htons(HELLO_PORT);
-
- /* bind to receive address */
- if (bind(fd,(struct sockaddr *) &addr,sizeof(addr)) < 0)
- {
- perror("bind");
- exit(1);
- }
-
- /* use setsockopt() to request that the kernel join a multicast group */
- mreq.imr_multiaddr.s_addr=inet_addr(HELLO_GROUP);
- mreq.imr_interface.s_addr=htonl(INADDR_ANY);
- if (setsockopt(fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq)) < 0)
- {
- perror("setsockopt");
- exit(1);
- }
-
- /* now just enter a read-print loop */
- while (1)
- {
- addrlen=sizeof(addr);
- if ((nbytes=recvfrom(fd,msgbuf,MSGBUFSIZE,0,(struct sockaddr *) &addr,&addrlen)) < 0)
- {
- perror("recvfrom");
- exit(1);
- }
- puts(msgbuf);
- }
- }
-
-
- Sender Program
-
- /*
- * sender.c -- multicasts "hello, world!" to a multicast group once a second
- */
-
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <stdlib.h>
- #include <time.h>
- #include <string.h>
- #include <stdio.h>
-
-
- #define HELLO_PORT 12345
- #define HELLO_GROUP "225.0.0.37"
-
- int main(int argc, char *argv[])
- {
- struct sockaddr_in addr;
- int fd, cnt;
- struct ip_mreq mreq;
- char message[16]="Hello, World!";
-
- /* create what looks like an ordinary UDP socket */
- if ((fd=socket(AF_INET,SOCK_DGRAM,0)) < 0)
- {
- perror("socket");
- exit(1);
- }
-
- /* set up destination address */
- memset(&addr,0,sizeof(addr));
- addr.sin_family=AF_INET;
- addr.sin_addr.s_addr=inet_addr(HELLO_GROUP);
- addr.sin_port=htons(HELLO_PORT);
-
- /* now just sendto() our */
- while (1)
- {
- if (sendto(fd,message,sizeof(message),0,(struct sockaddr *) &addr,sizeof(addr)) < 0)
- {
- perror("sendto");
- exit(1);
- }
- sleep(1);
- }
- }