组播主机需要的环境
如果要在一台主机上运行多播程序,这台主机支持IGMP协议。此协议用于加入一个多播组,离开一个多播组等而向路由器发送命令。现在的IGMP协议最高版本为v3(rfc3376),现在有很少数的UNIX实现了,WindowXp己实现。大部分主机,路由器实现的版本为v2(rfc2236),而v1版本(rfc1112)的运行是从v2中可以实现。V2与v1的区别就是把V1版本中的4位版本字段跟4位操作类型字段合并成了8位操作类型,在V1中不用使用的8位字段在V2中被称之为最大响应时间。用C写V2的IGMP结构即为:
struct igmp
{
u_char igmp_type;
u_char igmp_code;
u_char igmp_cksum;
struct in_addr igmp_addr;
};
组播需要的网络环境
如果主机想获得多播报文,相邻的路由器也必须支持IGMP,如果想获得Internet上的多播报文,主机到Server的这个路径中所遇到的路由器必须全部支持IGMP,路由器还必须支持源发现协议,如MSDP,PIM_DM,PIM_SM等。
组播的等级
Level 0 不支持IP多播
Level 1 只支持向多播组发送数据而不能接收多播组的数据
Level 2 IP多播全支持
对这三个等级的理解应该从SOCKET上。建立了一个SOCKET以后可以对它进行设置,看它需求什么。一般现在存在的网络程序就就是Level0了,因为它们不支持多播,如用于连接WEB服务器获取网页内容的那个SOCKET就应该属于Level0。
一个演唱会现场网络直播,由于采用了多播,服务器要向一个多播组发送报文,因为他不需要获取接收者的报文,所以可以建立一个SOCKET只向特定的多播组发送数据就可以了,这个SOCKET应该就是Level 1
一个网络会议的例子,由于会议是有多个人参加的,每个人都需要接收其它人的报文,所以建立了一个SOCKET,首先把这个SOCKET加入到一个多播组,使其能接收多播组的数据,然后它也可以用这个SOCKET向自己加入的多播组发送自己的状态。这个SOCKET就应该是Level 2了
组播编程相关的socket结构和函数
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。不要问为什么。这两个函数在组播干什么呢?获取系统对组播的设置(如TTL),加入一个多播组,离开一个多播组就用setsockopt 。optname就是在组播起到最主要作用的一个字段,与组播相关的可取值
可取值 setsockopt getsockopt
IP_MULTICAST_LOOP 支持 支持
IP_MULTICAST_TTL 支持 支持
IP_MULTICAST_IF 支持 支持
IP_ADD_MEMBERSHIP 支持 不支持
IP_DROP_MEMBERSHIP 支持 不支持
1. IP_MULTICAST_LOOP
当接收者加入到一个多播组以后,再向这个多播组发送数据,这个字段的设置是否允许再返回到本身。
2. IP_MULTICAST_TTL
默认情况下,多播报文的TTL被设置成了1,也就是说到这个报文在网络传送的时候,它只能在自己所在的网络传送,当要向外发送的时候,路由器把TTL减1以后变成了0,这个报文就已经被Discard了。例:
char ttl;
ttl = 2;
setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, (char*)ttl, sizeof(ttl));
3. IP_MULTICAST_IF
发送多播报文时用的本地接口,默认情况下被设置成了本地接口的第一个地址。
未完
4. IP_ADD_MEMBERSHIP
这个option和下面的option是实现多播必不可少的,它用于加入一个多播组,例:
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));
5. IP_DROP_MEMBERSHIP
用于离开一个多播组,使用方法同IP_ADDR_MEMBERSHIP。
struct ip_mreq ipmr;
int len;
setsockopt(s, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char*)&ipmr, &len);