组播

组播技术是TCP/IP传送方式的一种。在我们讨论组播技术之前先来看看 TCP/IP的传送方式。TCP/IP传送方式有三种:单播,广播,组播。

   单播(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)

  1. Listener Program

  2. /*
  3. * listener.-- joins a multicast group and echoes all data it receives from
  4. * the group to its stdout...
  5. */

  6. #include <sys/types.h>
  7. #include <sys/socket.h>
  8. #include <netinet/in.h>
  9. #include <arpa/inet.h>
  10. #include <stdlib.h>
  11. #include <time.h>
  12. #include <string.h>
  13. #include <stdio.h>


  14. #define HELLO_PORT 12345
  15. #define HELLO_GROUP "225.0.0.37"
  16. #define MSGBUFSIZE 256

  17. int main(int argc, char *argv[])
  18. {
  19.     struct sockaddr_in addr;
  20.     int fd, nbytes,addrlen;
  21.     struct ip_mreq mreq;
  22.     char msgbuf[MSGBUFSIZE];

  23.     u_int yes=1; /*** MODIFICATION TO ORIGINAL */

  24.     /* create what looks like an ordinary UDP socket */
  25.     if ((fd=socket(AF_INET,SOCK_DGRAM,0)) < 0) 
  26.     {
  27.         perror("socket");
  28.         exit(1);
  29.     }


  30.     /**** MODIFICATION TO ORIGINAL */
  31.     /* allow multiple sockets to use the same PORT number */
  32.     if (setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(yes)) < 0) 
  33.     {
  34.         perror("Reusing ADDR failed");
  35.         exit(1);
  36.     }
  37.     /*** END OF MODIFICATION TO ORIGINAL */

  38.     /* set up destination address */
  39.     memset(&addr,0,sizeof(addr));
  40.     addr.sin_family=AF_INET;
  41.     addr.sin_addr.s_addr=htonl(INADDR_ANY); /* N.B.: differs from sender */
  42.     addr.sin_port=htons(HELLO_PORT);
  43.          
  44.     /* bind to receive address */
  45.     if (bind(fd,(struct sockaddr *) &addr,sizeof(addr)) < 0) 
  46.     {
  47.         perror("bind");
  48.         exit(1);
  49.     }
  50.          
  51.     /* use setsockopt() to request that the kernel join a multicast group */
  52.     mreq.imr_multiaddr.s_addr=inet_addr(HELLO_GROUP);
  53.     mreq.imr_interface.s_addr=htonl(INADDR_ANY);
  54.     if (setsockopt(fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq)) < 0) 
  55.     {
  56.         perror("setsockopt");
  57.         exit(1);
  58.     }

  59.     /* now just enter a read-print loop */
  60.     while (1) 
  61.     {
  62.         addrlen=sizeof(addr);
  63.         if ((nbytes=recvfrom(fd,msgbuf,MSGBUFSIZE,0,(struct sockaddr *) &addr,&addrlen)) < 0) 
  64.         {
  65.             perror("recvfrom");
  66.             exit(1);
  67.         }
  68.         puts(msgbuf);
  69.     }
  70. }


  71. Sender Program

  72. /*
  73. * sender.-- multicasts "hello, world!" to a multicast group once a second
  74. */

  75. #include <sys/types.h>
  76. #include <sys/socket.h>
  77. #include <netinet/in.h>
  78. #include <arpa/inet.h>
  79. #include <stdlib.h>
  80. #include <time.h>
  81. #include <string.h>
  82. #include <stdio.h>


  83. #define HELLO_PORT 12345
  84. #define HELLO_GROUP "225.0.0.37"

  85. int main(int argc, char *argv[])
  86. {
  87.     struct sockaddr_in addr;
  88.     int fd, cnt;
  89.     struct ip_mreq mreq;
  90.     char message[16]="Hello, World!";

  91.     /* create what looks like an ordinary UDP socket */
  92.     if ((fd=socket(AF_INET,SOCK_DGRAM,0)) < 0) 
  93.     {
  94.         perror("socket");
  95.         exit(1);
  96.     }

  97.     /* set up destination address */
  98.     memset(&addr,0,sizeof(addr));
  99.     addr.sin_family=AF_INET;
  100.     addr.sin_addr.s_addr=inet_addr(HELLO_GROUP);
  101.     addr.sin_port=htons(HELLO_PORT);
  102.          
  103.     /* now just sendto() our */
  104.     while (1) 
  105.     {
  106.         if (sendto(fd,message,sizeof(message),0,(struct sockaddr *) &addr,sizeof(addr)) < 0) 
  107.         {
  108.             perror("sendto");
  109.             exit(1);
  110.         }
  111.         sleep(1);
  112.     }
  113. }


转自:http://blog.chinaunix.net/uid-25885064-id-3128646.html
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值