分享

21、多播

 gljin_cn 2014-04-01
1、基本概念
单播地址标识单个IP接口,广播地址标识某个子网的所有IP接口,多播地址标识一组IP接口。单播和广播是寻址方案的两个极端(要么单个要么全部),多播则意在两者之间提供一种折中的方案。另外,广播一般局限于局域网内使用,而多播则既可用于局域网也可跨广域网使用。
2、多播地址
IPV3的D类地址(224.0.0.0-239.255.255.255)是IPV4多播地址
224.0.0.1:是所有主机组,子网上所有具有多播能力的接口必须在所有具有多播能力的接口上加入该组
224.0.0.2:是所有路由器组。子网上所有多播路由器必须在所有具有多播能力的接口上加入该组
224.0.0.0-224.0.0.255:称为链路局部的多播地址。这些地址是为低级拓扑发现和维护协议保留的。
3.、原理
发送者向一个多播地址发送,如果主机想接受,则加入以该多播地址标识的多播组,即可以接收到。发送和接收与UDP相同。
4、源码

/*
 * mcast.h
 *
 *  Created on: 2012-7-16
 *      Author: keyamign
 */

#ifndef MCAST_H_
#define MCAST_H_
#include<netinet/in.h>

int mcast_join(int sockfd,const struct sockaddr* grp,socklen_t grplen,const char *ifname,u_int ifindex);
#endif /* MCAST_H_ */

/*
 * mcast_join.c
 *
 *  Created on: 2012-7-16
 *      Author: keyamign
 */

#include<net/if.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<sys/ioctl.h>
#include<netinet/in.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>

typedef struct sockaddr SA;

int mcast_join(int sockfd, const SA *grp, socklen_t grplen, const char *ifname,
u_int ifindex) {
#ifdef MCAST_IOIN_GROUP
printf("IP 无关\n");
struct group_req req;
if (ifindex > 0) {
req.gr_interface = ifindex;
} else if (ifname != NULL) {
if ((req.gr_interface = if_nametoindex(ifname)) == 0) {
errno = ENXIO;
return (-1);
}
} else
req.gr_interface = 0;
if (grplen > sizeof(req.gr_group)) {
errno = EINVAL;
return -1;
}
memcpy(&req.gr_group, grp, grplen);
return (setsockopt(sockfd, IPPROTO_TCP, MCAST_JOIN_GROUP, &req, sizeof(req)));
#else
switch (grp->sa_family) {
case AF_INET: {
printf("IPV4\n");
struct ip_mreq mreq;
struct ifreq ifreq;
memcpy(&mreq.imr_multiaddr,
&((const struct sockaddr_in*) grp)->sin_addr,
sizeof(struct in_addr));
if (ifindex > 0) {
if (if_indextoname(ifindex, ifreq.ifr_ifrn.ifrn_name) == NULL) {
errno = ENXIO;
return (-1);
}
goto doioctl;
} else if (ifname != NULL) {
strncpy(ifreq.ifr_ifrn.ifrn_name, ifname, IFNAMSIZ);
doioctl: if (ioctl(sockfd, SIOCGIFADDR, &ifreq) < 0)
return (-1);
memcpy(&mreq.imr_interface,
&((struct sockaddr_in *) &ifreq.ifr_ifru)->sin_addr,
sizeof(struct in_addr));
} else
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
return (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,
sizeof(mreq)));
}
#ifdef IPV6
case AF_INET6: {
printf("IPV6\n");
struct ipv6_mreq mreq6;
memcpy(&mreq6.ipv6mr_multiaddr,
&((const struct sockaddr_in6) grp)->sin6_addr,
sizeof(struct in6_addr));
if (ifindex > 0) {
mreq6.ipv6mr_interface = ifindex;
} else if (ifname != NULL) {
if ((mreq6.ipv6mr_interface = if_nametoindex(ifname)) == 0) {
errno = ENXIO;
return (-1);
}
} else
mreq6.ipv6mr_interface = 0;
return (setsockopt(sockfd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6,
sizeof(mreq6)));
}
#endif
default:
errno = EAFNOSUPPORT;
return (-1);
}
#endif
}

#include"mcast.h"
#include<sys/types.h>
#include<sys/socket.h>
#include<sys/ioctl.h>
#include<netinet/in.h>
#include<stdio.h>
#include<string.h>

#define MAXLINE 1024

int main() {
int sendfd, recvfd;
const int on = 1;
socklen_t salen;
struct sockaddr_in sa,recvsa;
char buf[MAXLINE],sendbuf[MAXLINE],recvbuf[MAXLINE];

if ((sendfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
perror("socket error");
if ((recvfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
perror("socket error");

bzero(&sa, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(8080);
strcpy(buf, "239.255.1.2");
if (inet_pton(AF_INET, buf, &sa.sin_addr) <= 0)
perror("inet_pton error");
    salen=sizeof(sa);

setsockopt(recvfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
bind(recvfd,(struct sockaddr*)&sa,salen);
mcast_join(recvfd,(struct sockaddr*)&sa,salen,NULL,0);
strcpy(sendbuf,"himan");
sendto(sendfd,sendbuf,7,0,(struct sockaddr*)&sa,salen);
sleep(2);
bzero(recvbuf,sizeof(recvbuf));
bzero(buf,sizeof(buf));
bzero(&recvsa,sizeof(recvsa));
recvfrom(recvfd,recvbuf,1024,0,(struct sockaddr*)&recvsa,&salen);
printf("from %s:%s\n",inet_ntop(AF_INET,&recvsa.sin_addr,buf,MAXLINE),recvbuf);

}

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多