点对多点应用是指一个发送者,多个接收者的应用形式,这是最常见的多播应用形式。典型的应用包括:媒体广播、媒体推送、信息缓存、事件通知和状态监视等。
多点对点应用是指多个发送者,一个接收者的应用形式。通常是双向请求响应应用,任何一端(多点或点)都有可能发起请求。典型应用包括:资源查找、数据收集、网络竞拍、信息询问等。
多点对多点应用是指多个发送者和多个接收者的应用形式。通常,每个接收者可以接收多个发送者发送的数据,同时,每个发送者可以把数据发送给多个接收者。典型应用包括:多点会议、资源同步、并行处理、协同处理、远程学习、讨论组、分布式交互模拟(DIS)、多人游戏等。
IP 组播通信必须依赖于 IP 多播地址,在 IPv4 中它是一个 D 类 IP 地址,范围从 224.0.0.0 到 239.255.255.255,并被划分为局部链接多播地址、预留多播地址和管理权限多播地址三类:
1)局部链接多播地址范围在 224.0.0.0~224.0.0.255,这是为路由协议和其它用途保留的地址,路由器并不转发属于此范围的IP包;
2)预留多播地址为 224.0.1.0~238.255.255.255,可用于全球范围(如Internet)或网络协议;
3)管理权限多播地址为 239.0.0.0~239.255.255.255,可供组织内部使用,类似于私有 IP 地址,不能用于 Internet,可限制多播范围。
使用同一个 IP 多播地址接收多播数据包的所有主机构成了一个主机组,也称为多播组。一个多播组的成员是随时变动的,一台主机可以随时加入或离开多播组,多播组成员的数目和所在的地理位置也不受限制,一台主机也可以属于几个多播组。
这个我们可以这样理解,多播地址就类似于 QQ 群号,多播组相当于 QQ 群,一个个的主机就相当于群里面的成员。
设备驱动程序就必须接收所有多播数据帧,然后对它们进行过滤,这个过滤过程是网络驱动或IP层自动完成。(设备驱动程序会对多播数据进行过滤,将其发到相应的位置)
#include /* See NOTES */
#include
int setsockopt(int sockfd, int level, int optname,
const void *optval, socklen_t optlen);
结构体原型
struct in_addr
{
in_addr_t s_addr;
}
struct ip_mreq
{
struct in_addr imn_multiaddr; // 多播组 IP,类似于 QQ 群号
struct in_addr imr_interface; // 将要添加到多播组的 IP,类似于QQ 成员号
};
tips:
多播组只能用UDP 或者原始套接字实现,不能用TCP
说明接收组播地址为224.0.0.88 或者 224.0.0.66 的信息,
//Udp_group_recv.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc,char *argv[])
{
int socked=socket(AF_INET,SOCK_DGRAM,0);
char group[16]="224.0.0.88";
char group_1[16]="224.0.0.66";
if(socked<0)
{
perror("socket failed!");
return 2;
}
struct sockaddr_in local_addr;
memset(&local_addr,0,sizeof(local_addr));
local_addr.sin_family=AF_INET;
local_addr.sin_addr.s_addr=htonl(INADDR_ANY);
local_addr.sin_port=htons(8888);
int ret=bind(socked,(struct sockaddr*)&local_addr,sizeof(local_addr));
if(ret<0)
{
perror("bind failed !");
return 3;
}
struct ip_mreq mreq; // 多播地址结构体
mreq.imr_multiaddr.s_addr=inet_addr(group);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
ret=setsockopt(socked,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));
if(ret<0)
{
perror("setsockopt failed !");
return 3;
}
else
{
printf("setsockopt success\n");
}
mreq.imr_multiaddr.s_addr=inet_addr(group_1);
ret=setsockopt(socked,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));
if(ret<0)
{
perror("setsockopt_1 failed !");
return 3;
}
else
{
printf("setsockopt_1 success\n");
}
char buf[1024];
int length=0;
struct sockaddr_in sender;
int sender_len=sizeof(sender);
while(1)
{
memset(buf, 0, sizeof(buf));
length=recvfrom(socked,buf,sizeof(buf),0,(struct sockaddr*)&sender,&sender_len);
buf[length]='\0';
printf("%s %d : %s\n",inet_ntoa(sender.sin_addr),ntohs(sender.sin_port),buf);
}
setsockopt(socked, IPPROTO_IP, IP_DROP_MEMBERSHIP,&mreq, sizeof(mreq));
close(socked);
return 0;
}
//向组播地址为224.0.0.88的组发送信息
Udp_group_send.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc,char *argv[])
{
char group_addr[16]="224.0.0.88";
int socked=socket(AF_INET,SOCK_DGRAM,0);
if(socked<0)
{
perror("socket failed!");
return 2;
}
struct sockaddr_in remote_addr;
memset(&remote_addr,0,sizeof(remote_addr));
remote_addr.sin_family=AF_INET;
remote_addr.sin_addr.s_addr=inet_addr(group_addr);
remote_addr.sin_port=htons(8888);
char buf[1024]="This is a group udp";
int length=0;
while(1)
{
memset(buf, 0, sizeof(buf));
length=sendto(socked,buf,strlen(buf),0,(struct sockaddr *)&remote_addr,sizeof(remote_addr));
printf("Send Message%s\n",buf);
}
close(socked);
return 0;
}