linux网络编程之一-----多播(组播)编程
什么是多播
组播(Multicast)是网络一种点对多(one to many)的通信方式,通过报文复制完成网络中一台server对应多台接收者的高效数据传 送。对其形象的比喻就是类似于广播电台和电视台节目的发送。电台或电视台向特定频道发送他们的节目,而接收者可以根据自己的喜好选择频道来收听或收看节 目。
传统网络的通信方式单 播(Unicast) 在许多场合下并不合适,如果强行采于单播方式只是会增加网络上传送的报文,还会影响server端的运行效率,如网络游戏,网络视频会议等。这些场合下由于接收者需要的是同样的数据,如果有N个 接收者,那么server就需要把这份数据做成N个报文分别发送给接收者,这样当接收者增多的情况下,server端发送的报文也同样需要增多,server端承受这样的通信量肯定有一个 极值,当接收者到一定程度的时候,不单单是网络流量增大的问题了,server面临的只有宕机。
组播在这种场合下就有了用武之地了。Server端需要做的就是向特写的Group发送一个报文,当网络的多个接收者对这个报文感兴趣的时候,他们可以自由复制得到这个报文。这样的 情况下,无论接收者增加多少人,Server需要做的只是发送一个报文,而网络上传送的是只是一份报文。
单播用于两个主机之间的端对端通信,广播用于一个主机对整个局域网上所有主机上的数据通信。单播和广播是两个极端,要么对一个主机进行通信,要么对整个局域网上的主机进行通信。实际情况下,经常需要对一组特定的主机进行通信,而不是整个局域网上的所有主机,这就是多播的用途。
多播,也称为“组播”,将局域网中同一业务类型主机进行了逻辑上的分组,进行数据收发的时候其数据仅仅在同一分组中进行,其他的主机没有加入此分组不能收发对应的数据。
单播图例:
多播图例:
组播地址
32位的IP地址被分成了A、B、C、D、E五种类型,前三种是我们日常生活常见的,由一个权威部分统一分配。而D类地址我们需要的多播地址, 前三种地址我们可以形象的认为是一个点,而一个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,可限制多播范围。
IP组播地址到链路层地址的转换
因为以太网支持多种协议,所以要采取措施分配多播地址,避免冲突。IEEE管理以太网多播地址分配。IEEE把一块以太网多播地址分给IANA以支持IP多播。块的地址都以01:00:5e开头。第25位为0,低23位为IPv4组播地址的低23位。IPv4组播地址与MAC地址的映射关系如图所示:组播需要的网络环境
如果主机想获得多播报 文,相邻的路由器也必须支持IGMP,如果想获得Internet上的多播报文,主机到Server的这个路径中所遇到的路由器必须全部支持IGMP,路由器还必须支持源发现协议,如MSDP,PIM_DM,PIM_SM等。组播的等级
多播主机分为三个级别:
- 0级:主机不能发送或接收IP多播。这种主机应该自动丢弃它收到的具有D类目的地址的分组。
- 1级:主机能发送但不能接收IP多播。在向某个IP多播组发送数据报之前,并不要求主机加入该组。多播数据报的发送方式与单播一样,除了多播数据报的目的地址是 IP多播组之外。网络驱动器必须能够识别出这个地址,把在本地网络上多播数据报。
- 2级:主机能发送和接收IP多播。
一个演唱会现场网络直 播,由于采用了多播,服务器要向一个多播组发送报文,因为他不需要获取接收者的报文,所以可以建立一个socket只向特定的多播组发送数据就可以 了,这个socket应该就是1级。
一个网络会议的例子, 由于会议是有多个人参加的,每个人都需要接收其它人的报文,所以建立了一个socket,首先把这个socket加入到一个多播组,使其能接收多播组的数据,然后它也可以用这个socket向自己加入的多播组发送自己的状 态。这个socket就应该是2级。
linux多播编程步骤:
- 建立一个socket;
- 设置多播的参数,例如超时时间TTL,本地回环许可LOOP等。
- 加入多播组;
- 发送和接收数据;
- 从多播组离开
多播程序设计使用setsockopt()函数和getsockopt()函数来实现,组播的选项是IP层的。
int setsockopt(SOCKET s, int level, int optname, const char FAR * optval, int optlen); int getsockopt(SOCKET s, int level, int optname, char FAR * optval, int FAR * optlen);
level必须为IPPROTO_IP,optname就是在 组播起到最主要作用的一个字段,与组播相关的可取值:
可取值 | setsockopt() | getsockopt() | 含 义 |
IP_MULTICAST_TTL | 支持 | 支持 | 设置多播组数据的TTL值 |
IP_ADD_MEMBERSHIP | 支持 | 不支持 | 在指定接口上加入组播组 |
IP_DROP_MEMBERSHIP | 支持 | 不支持 | 退出组播组 |
IP_MULTICAST_IF | 支持 | 支持 | 获取默认接口或设置接口 |
IP_MULTICAST_LOOP | 支持 | 支持 | 禁止组播数据回送 |
1.选项IP_MULTICASE_TTL
选项IP_MULTICAST_TTL允许设置超时TTL,范围为0~255之间的任何值。默认情况下,多播报文的TTL被设置成了1,也就是说到这个报文在网络传送的时候,它只能在自己所在的网络传送,当要向外发送的时候,路由器把TTL减1以后变成了0,这个报文就已经被Discard了。例如:
unsigned char ttl=255; setsockopt(s,IPPROTO_IP,IP_MULTICAST_TTL,&ttl,sizeof(ttl));
2.选项IP_MULTICAST_IF
选项IP_MULTICAST_IF用于设置发送组播使用的本地接口,另一个网络接口会忽略此数据。默认情况下被设置成了本地接口的第一个地址。例如:
struct in_addr addr; setsockopt(s,IPPROTO_IP,IP_MULTICAST_IF,&addr,sizeof(addr));
参数addr是希望多播输出接口的IP地址,使用INADDR_ANY地址回送到默认接口。
当接收者加入到一个多播组以后,再向这个多播组发送数据,默认情况下在IP层,数据会回送到本地的回环接口,选项IP_MULTICAST_LOOP用于控制数据是否回送到本地的回环接口。例如:
unsigned char loop; setsockopt(s,IPPROTO_IP,IP_MULTICAST_LOOP,&loop,sizeof(loop));参数loop设置为0禁止回送,设置为1允许回送。
3.选项IP_ADD_MEMBERSHIP和IP_DROP_MEMBERSHIP
加入或者退出一个多播组,通过选项IP_ADD_MEMBERSHIP和IP_DROP_MEMBERSHIP,对一个结构struct ip_mreq类型的变量进行控制,struct ip_mreq原型如下:
struct ip_mreq { struct in_addr imn_multiaddr; /*加入或者退出的广播组IP地址*/ struct in_addr imr_interface; /*加入或者退出的网络接口IP地址*/ };选项IP_ADD_MEMBERSHIP用于加入某个多播组,之后就可以向这个多播组发送数据或者从多播组接收数据。此选项的值为mreq结构,成员imn_multiaddr是需要加入的多播组IP地址,成员imr_interface是本机需要加入广播组的网络接口IP地址。例如:
struct ip_mreq ipmr; ipmr.imr_interface.s_addr = htonl(INADDR_ANY); ipmr.imr_multiaddr.s_addr = inet_addr("234.5.6.7"); setsockopt(s, IPPROTO_IP, IP_ADDR_MEMBERSHIP, (char*)&ipmr, sizeof(ipmr));