多播数据报只应该由对它感兴趣的应用接收。
广播一般局限与局域网内使用,而多播既可以用于局域网,也可以用于广域网。

多播地址

多播地址需要对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 = 0;
    if (grplen > sizeof(req.gr_group)) {
        errno = EINVAL;
        return -1;
    }
    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 = 0;
        return (setsockopt(sockfd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
                           &mreq6, sizeof(mreq6)));
    }
#endif

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

int main(int argc, char **argv)
{
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    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");
}
Logo

更多推荐