天天看點

Linux加入多點傳播組

多點傳播資料報隻應該由對它感興趣的應用接收。

廣播一般局限與區域網路内使用,而多點傳播既可以用于區域網路,也可以用于廣域網。

多點傳播位址

多點傳播位址需要對IPv4和IPv6分開讨論。

IPv4的D類位址(從224.0.0.0到239.255.255.255)是IPv4多點傳播位址。其中低28位為group ID,整個32位為group address。

一些特殊的IPv4多點傳播位址:

224.0.0.1:所有主機(all-hosts)組,所有具備多點傳播功能的裝置。

224.0.0.2:所有路由器(all-routers)組。

224.0.0.0到224.0.0.255之間的位址被稱為link local,路由器從不轉發以這些位址為目的位址的資料報。

IPv6多點傳播位址

IPv6多點傳播位址高位為ff。特殊的IPv6多點傳播位址

ff01::1到ff02::1位all-nodes組,與IPv4的all-hosts意思是一樣的。

ff01::2、ff02::2和ff05::2是all-routers組。

示例代碼

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/in.h>
#include <linux/if_ether.h>
#include <net/if.h>
#include <errno.h>

/**
 * Join multicast group, support both IPv4 and IPv6.
 * @param  sockfd socket descripter
 * @param  grp    sockaddr
 * @param  grplen sockaddr length
 * @return        0:on success; non-zero:on failed
 */
static int mcast_join(int sockfd, const struct sockaddr *grp, socklen_t grplen)
{
#if MCAST_JOIN_GROUP
    struct group_req req;
    req.gr_interface = ;
    if (grplen > sizeof(req.gr_group)) {
        errno = EINVAL;
        return -;
    }
    memcpy(&req.gr_group, grp, grplen);

    return (setsockopt(sockfd, IPPROTO_IP, MCAST_JOIN_GROUP, &req, sizeof(req)));
#else
    switch (grp->sa_family) {
    case AF_INET: {
        struct ip_mreq      mreq;
        struct ifreq        ifreq;
        memcpy(&mreq.imr_multiaddr,
               &((const struct sockaddr_in *) grp)->sin_addr,
               sizeof(struct in_addr));
        mreq.imr_interface.s_addr = htonl(INADDR_ANY);
        return (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
                           &mreq, sizeof(mreq)));
    }
#ifdef  IPV6
#ifndef IPV6_JOIN_GROUP /* APIv0 compatibility */
#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
#endif
    case AF_INET6: {
        struct ipv6_mreq    mreq6;
        memcpy(&mreq6.ipv6mr_multiaddr,
               &((const struct sockaddr_in6 *) grp)->sin6_addr,
               sizeof(struct in6_addr));
        mreq6.ipv6mr_interface = ;
        return (setsockopt(sockfd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
                           &mreq6, sizeof(mreq6)));
    }
#endif

    default:
        errno = EAFNOSUPPORT;
        return -;
    }
#endif
}

int main(int argc, char **argv)
{
    int fd = socket(AF_INET, SOCK_DGRAM, );
    struct sockaddr_in grp;
    bzero(&grp, sizeof(grp));
    grp.sin_family = AF_INET;
    grp.sin_addr.s_addr = inet_addr("224.0.0.1");;
    if (mcast_join(fd, (struct sockaddr*)(&grp), sizeof(grp)))
        perror("Join multicast group failed");
}
           

繼續閱讀