IP多播
(一). 定义:
IP多播是指一个IP数据报向一个主机组的传送,该主机组是由一个单独的IP目的地址标记的多个或零个主机。一个多播数据报被尽可能地传递给它的目的主机组的所有成员,就像常规的单播IP数据报一样。也就是说,不能保证数据报能完好无损的到达目的组所有成员,也不能保证它以相对于其它数据报同样的顺序到达。(详情请参照RFC988,RFC1112)
(二).协议
1. 多播地址
(224.0.0.0 -- 239.255.255.255)
保留IP广播地址:
224.0.0.0 基地址
224.0.0.1 本地子网上所有节点
224.0.0.2 本地子网上的所有路由器
224.0.0.4
224.0.0.5
224.0.0.6
224.0.0.9
224.0.0.13
2. IGMP协议(RFC2236 RFC3376)
工作分为两个阶段:
第一阶段:当某个主机加入新的多播组是,该主机向多播地址发送一个IGMP报文,声明自己要加入该组。本地多播路由器收到报文后,利用多播路由器由选择协议把这种成员关系发送给因特网上其他多播路由器。
第二阶段:组成员关系是动态的。本地多播路由器要周期性的试探本地局域网上的主机,以便知道这些主机是否还继续是该组成员。主要有一个主机对该组相应,多播路由器测认为这个组是活跃的,否则则认为所有主机都已经离开此多播组,并把这个关系转发给其他多播路由器
(三).使用IP多播
typedef struct ip_mreq {
struct in_addr imr_multiaddr; //多播组IP地址
struct in_addr imr_interface; //将要加入或者离开的本地地址
} IP_MREQ, *PIP_MREQ;
1. 加入组
IP_MREQ mcast;
mcast.imr_interface.S_un.S_addr = INADDR_ANY;
mcast.imr_multiaddr.S_un.S_addr = inet_addr("234.5.6.7");
if (SOCKET_ERROR == setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mcast, sizeof(IP_MREQ)))
{
return -1;
}
2. 发送数据
printf(">");
scanf("%s", szText);
printf("%s\n", szText);
sendto(s, szText, strlen(szText) + 1, 0, (LPSOCKADDR)&saiBcast, sizeof(saiBcast));
3. 接收数据
int nRet = recvfrom(s, szRecvBuf, 255, 0, (SOCKADDR *)&saiRemote, &nLen);
if (nRet != SOCKET_ERROR)
{
printf(szRecvBuf);
printf("\n");
}
4. 离开组
setsockopt(s, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char *)&mcast, sizeof(mcast));
5. 带源地址的IP多播
def 带源地址的IP多播允许加入组时候指定要接受哪些成员的数据。
typedef struct ip_mreq_source {
struct in_addr imr_multiaddr; //多播IP地址
struct in_addr imr_sourceaddr; //指定源IP地址
struct in_addr imr_interface; //主机IP地址
} IP_MREQ_SOURCE, *PIP_MREQ_SOURCE;
1) 包含式:只接受指定Ip的信息
setsockopt(s, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, (char *)&mreqSource, sizeof(IP_MREQ_SOURCE));
2) 排除式:只接受除指定IP以外的信息
setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreqSource, sizeof(IP_MREQ_SOURCE));
setsockopt(s, IPPROTO_IP, IP_BLOCK_SOURCE, (char *)&mreqSource, sizeof(IP_MREQ_SOURCE))
;
完整代码参照上传资料