IP多播

来源:互联网 发布:CodeIgniter 知乎 编辑:程序博客网 时间:2024/06/02 04:26

                                                  IP多播

使用广播可以将封包发送到网络中的各个节点,使用多播则仅将封包发送到网络节点的一个集合。

1.1多播地址

为了发送IP多播数据,发送者需要一个合适的多播地址,这个地址代表一个组,IP多播地址采用D类IP地址确定多播的组,地址的范围是224.0.0.0239.255.255.255。不过有些多播地址保留为特殊的目的使用。

224.0.0.0-------------------------------基地址(保留)

224.0.0.1-------------------------------本子网上的所有节点

224.0.0.2-------------------------------本子网上的所有路由器

224.0.0.4-------------------------------网段中所有的DVMRP路由器

224.0.0.5-------------------------------所有的OSPF路由器

224.0.0.6-------------------------------所有的OSPF指派路由器

224.0.0.9-------------------------------所有RIPv2路由器

224.0.0.13------------------------------所有PIM路由器

 

1.2组管理协议(IGMP

IGMP是IPv4引入的管理多播客户和它们之间关系的协议。IGMP被开发出来用于通知路由器网络上的一个机器对指定组的数据感兴趣。

为了多播正确的工作,两个多播节点之间的所有路由器必须支持IGMP协议。任何没有开启IGMP协议的路由器仅简单地丢弃接收到的多播数据。

另外,当终端加入到多播组时,它指定TTL参数,来指明终端的多播应用程序想要经过多少个路由器来发送和接收数据,如下代码所示。

int nTtl =0; setsockopt(sock,IPPROTO_IP,IP_MULTICAST_TTL,(char*)&nTtl,sizeof(nTtl));

l初始TTL为0的多播封包被限制在同一个主机

l初始TTL为1的多播封包被限制在同一个子网

l初始TTL为32的多播封包被限制在同一个站点

l初始TTL为64的多播封包被限制在同一个地区

l初始TTL为128的多播封包被限制在同一个大陆

l初始TTL为255的多播封包没有范围限制

注意:许多多播路由器拒绝转发目的地址在224.0.0.0~224.0.0.255之间的任何多播数据报,不管它的TTL是多少。

 

每个多播传输仅从一个网络接口发出,即便是主机有多个多播接口。可以使用套接字选项IP_MULTICAST_IF改变默认发送数据接口,如下代码所示。

structin_addr addr;

setsockopt(sock,IPPROTO_IP,IP_MULTICAST_IF,&addr,sizeof(addr));

其中addr是本地机器想要外出的接口。设置为地址INADDR_ANY可以恢复使用默认接口。

 

1.3带源地址的IP多播

 

带源地址的IP多播允许加入组时指定要接收哪些成员的数据。有两种方式:

1)“包含”方式,这种方式下,为套接字指定N个有效源地址,套接字仅接收来自这些源地址的数据;使用IP_ADD_SOURCE_MEMBERSHIPIP_DROP_SOURCE_MEMBERSHIP

2)“排除”方式,这种方式下,为套接字指定N个源地址,套接字将接收来自这些源地址之外的数据;使用IP_BLOCK_SOURCE(排除某个源地址)和IP_UNBLOCK_SOURCE(从排除集合中移除此源地址)以上两种方式输入参数都是ip_mreq_source结构

下面是一个测试程序。

接收端:

#include <winsock2.h>

#include <ws2tcpip.h>

#pragma comment(lib,"ws2_32")

void initSock(){

WORDwVersionRequested;

WSADATAwsaData;

int err;

wVersionRequested= MAKEWORD( 2, 2 );

err =WSAStartup( wVersionRequested, &wsaData);

if ( err!= 0 ) {

return;

}

if (LOBYTE( wsaData.wVersion ) != 2 ||

HIBYTE(wsaData.wVersion ) != 2 ) {

WSACleanup();

return;

}

}

int main(){

initSock();

 

SOCKETsock = socket(AF_INET,SOCK_DGRAM,0);

if(sock==INVALID_SOCKET){

return 0;

}

BOOLbReuse = TRUE;

setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(char*)&bReuse,sizeof(BOOL));

sockaddr_inaddr;

addr.sin_family= AF_INET;

addr.sin_addr.S_un.S_addr= INADDR_ANY;

addr.sin_port= htons(4567);

 

::bind(sock,(sockaddr*)&addr,sizeof(addr));

 

ip_mreqmcast;

mcast.imr_interface.S_un.S_addr= INADDR_ANY;

mcast.imr_multiaddr.S_un.S_addr= inet_addr("234.5.15.8");

setsockopt(sock,IPPROTO_IP,IP_ADD_MEMBERSHIP,(char*)&mcast,sizeof(mcast));

 

 

 

 

char buf[100];

int len= sizeof(sockaddr);

 

while(true){

int ret =::recvfrom(sock,buf,sizeof(buf),0,(sockaddr*)&addr,&len);

if(ret ==SOCKET_ERROR)

break;

printf("%s\n",buf);

}

 

closesocket(sock);

WSACleanup();

return 0;

}

 

发送端:

#include <winsock2.h>

#include <ws2tcpip.h>

#pragma comment(lib,"ws2_32")

void initSock(){

WORDwVersionRequested;

WSADATAwsaData;

int err;

wVersionRequested= MAKEWORD( 2, 2 );

err =WSAStartup( wVersionRequested, &wsaData);

if ( err!= 0 ) {

return;

}

if (LOBYTE( wsaData.wVersion ) != 2 ||

HIBYTE(wsaData.wVersion ) != 2 ) {

WSACleanup();

return;

}

}

int main(){

initSock();

SOCKETsock = socket(AF_INET,SOCK_DGRAM,0);

int nTtl =0;

setsockopt(sock,IPPROTO_IP,IP_MULTICAST_TTL,(char*)&nTtl,sizeof(nTtl));

sockaddr_inaddr;

addr.sin_addr.S_un.S_addr= inet_addr("234.5.15.8");

addr.sin_family= AF_INET;

addr.sin_port= htons(4567);

 

char buf[100]= {0};

int i =0;

while(++i<=20){

char name[100]= {0};

gethostname(name,sizeof(name));

hostent*phost = gethostbyname(name);

sprintf(buf,"hello!I'm %s (%s)",name,inet_ntoa(*(in_addr*)(phost->h_addr_list[0])));

::sendto(sock,buf,sizeof(buf),0,(sockaddr*)&addr,sizeof(sockaddr));

}

closesocket(sock);

WSACleanup();

return 0;

}

 

运行结果:

IP多播

原创粉丝点击