使用普通套接字对ipv6多播有什么要求?

时间:2017-01-26 17:27:58

标签: c++ linux networking ipv6 multicast

我正在处理旧的代码库,其中ipv6多播似乎不起作用。当我尝试将套接字绑定到ff01 :: 1时,它会失败。套接字是在我的以太网接口中创建的。

将套接字绑定到in6addr_any,即“::”,导致绑定成功,但除了应用程序本身发送的数据包之外,没有收到任何数据包,使用给定的套接字(设置了IPV6_MULTICAST_LOOP)。这些数据包似乎永远不会离开应用程序。当尝试在以太网接口中捕获数据包时,它们在wireshark中不可见。只有传入的外部多播数据包可见。他们都没有达到我的申请。

System是Ubuntu 16.04 with Linux 4.4.0。

设置代码示例:

    #define MCASTADDRC "ff01::1"

    int mcast::bind_mcast(const char *interface) {

    this->net = socket(AF_INET6, SOCK_DGRAM, 0);        
    inet_pton(AF_INET6,MCASTADDRC,&this->multicast.ipv6mr_multiaddr); 

    this->ifaceaddr.sin6_family = AF_INET6;
    this->ifaceaddr.sin6_port = htons(SRVPORT);
    this->ifaceaddr.sin6_addr = in6addr_any;

    // interface for multicast
    this->mcastaddr.sin6_family = AF_INET6;
    this->mcastaddr.sin6_port = htons(SRVPORT);
    this->mcastaddr.sin6_addr = this->multicast.ipv6mr_multiaddr;


    int opcoes = fcntl(this->net, F_GETFL, 0);

    if ( fcntl(this->net, F_SETFL, opcoes | O_NONBLOCK) == -1 ) {
        // fail
        return(false);
    }

    if (bind(net, (struct sockaddr *) &this->ifaceaddr, sizeof(this->ifaceaddr)) == -1 ) {
        // fail                    
        return(false);
    }

    this->ifaceindex = if_nametoindex(interface);
    this->multicast.ipv6mr_interface = this->ifaceindex;
    this->ifaceaddr.sin6_scope_id = this->ifaceindex;

    int mcast_loop = 1;
    if (setsockopt(this->net, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &mcast_loop, sizeof(mcast_loop))) {
        //fail
        return(false);
    }

    if (setsockopt(this->net, IPPROTO_IPV6, IPV6_MULTICAST_IF, &this->ifaceindex, sizeof(this->ifaceindex))) {
        //fail
        return(false);
    }

    if (setsockopt(this->net, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &this->multicast, sizeof(this->multicast))) {
        //fail
        return(false);
    }
    int optval = 6000000;
    int optlen = sizeof(optval);
    if (setsockopt(this->net, SOL_SOCKET, SO_RCVBUF, &optval, sizeof(optval))) {

        exit(0);
    }
    if (getsockopt(this->net, SOL_SOCKET, SO_RCVBUF, &optval, (socklen_t *)&optlen)) {
        // fail
        exit(0);
    }

    if(optval < 262142) {   
        // buffer is too small, we failed 
        exit(0);
    }

    return(true); // success

}

1 个答案:

答案 0 :(得分:4)

IPv6组播地址中的12-15位(从0开始)指定了组播范围。

ff01::/16形式的多播地址范围为1,表示接口本地。不能通过任何网络链路发送此类数据包。这就是为什么您无法从其他主机接收任何包含此类地址的数据包的原因。

您需要使用具有不同范围值的地址。 2的范围可以通过本地网络发送,但不能通过路由器发送,而e(15)的范围可以全局路由。

此外,在程序运行时运行netstat -ng以确保您已在正确的接口上加入正确的多播组。

有关详细信息,请参阅维基百科页面multicast addresses