使用普通套接字进行 ipv6 多播有哪些要求?

What are the requirements for ipv6 multicasting using plain sockets?

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

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

系统是 Ubuntu 16.04 和 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

}

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

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

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

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

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