如果主机想获得多播报文,相邻的路由器也必须支持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);
http://www.cnblogs.com/hateislove214/archive/2010/11/05/1869868.html
http://www.cnblogs.com/hateislove214/archive/2010/11/05/1869883.html
m_sendAddr.sin_family = AF_INET;
m_sendAddr.sin_port = htons( m_send_port );
inet_pton(AF_INET, m_send_ip, &m_sendAddr.sin_addr.s_addr);
m_udpsocket = socket( AF_INET , SOCK_DGRAM , IPPROTO_UDP);
bind(m_udpsocket, (SA*)&m_sendAddr, sizeof(m_sendAddr) );
setsockopt(m_udpsocket, IPPROTO_IP, IP_MULTICAST_IF, (char*)&m_sendAddr.sin_addr, sizeof(m_sendAddr.sin_addr));
//把地址改为组地址, 以便后面向组内发送
m_sendAddr.sin_addr.s_addr = inet_addr( (char*)m_send_ip );
struct ip_mreq mreq;
memset(&mreq, 0, sizeof(struct ip_mreq));
/* 设置组地址 */
mreq.imr_multiaddr.s_addr = inet_addr(m_send_ip);
/* 设置发送组播消息的源主机的地址信息 */
mreq.imr_interface.s_addr = htons(INADDR_ANY);
setsockopt(m_udpsocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mreq, sizeof(struct ip_mreq));
int mc_loop = 0;
setsockopt(m_udpsocket, IPPROTO_IP, IP_MULTICAST_LOOP, (char*)&mc_loop, sizeof(int) );