在Linux上侦听IPv6组播 [英] Listening for IPv6 multicasts on Linux

查看:166
本文介绍了在Linux上侦听IPv6组播的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图得到一个简单的多播示例在Linux上工作(我
试过RHEL 4 2.6.9和Ubuntu 8.04 2.6.24)。一般的想法是
,我想服务器绑定到单播地址,然后添加
本身到组ff02 :: 1。然后我想它收到
多播发送到ff02 :: 1。下面的代码适用于Mac OS X 10.5(在
实际上,运行在OS X上的服务器获取从Linux
客户端发送的组播),但我不能让Linux服务器端工作。它不
获得任何多播。如果我改变代码绑定到::(INADDR6_ANY)
而不是单播地址(我尝试了链路本地和全局
地址),它确实获得多播。我想知道如果有人
可以指出我做错了什么。

I'm trying to get a simple multicasting example to work on Linux (I've tried both RHEL 4 2.6.9 and Ubuntu 8.04 2.6.24). The general idea is that I would like the server to bind to a unicast address and then add itself to the group ff02::1. I would then like it to receive multicasts sent to ff02::1. The code below works on Mac OS X 10.5 (in fact, a server running on OS X gets multicasts sent from Linux clients), but I can't get the Linux server side to work. It doesn't get any multicasts. If I change the code to bind to :: (INADDR6_ANY) rather than a unicast address (I've tried both link-local and global addresses), it does get the multicasts. I was wondering if someone could point out what I'm doing wrong.

服务器:

memset( &hint, 0, sizeof( hint ) );

hint.ai_family = AF_INET6;
hint.ai_socktype = SOCK_DGRAM;

// argv[1] is either a link-local or a global address
err = getaddrinfo( argv[1], NULL, &hint, &info );

if( err != 0 ) {
    perror( "getaddrinfo" );
    exit( 1 );
}

struct sockaddr_in6 * addr = (struct sockaddr_in6*)info->ai_addr;
//addr->sin6_addr = in6addr_any; // if this is uncommented, multicasts are received
addr->sin6_port = htons( 7890 );
s = socket( AF_INET6, SOCK_DGRAM, 0 );

if( bind( s, (struct sockaddr*) addr, info->ai_addrlen ) != 0 ) {
    close( s );
    perror( "bind" );
    exit( 1 );
}

if( getaddrinfo( "ff02::1", NULL, &hint, &multi ) != 0 ) {
    close( s );
    perror( "getaddrinfo" );
    exit( 1 );
}

struct ipv6_mreq mreq;
memset( &mreq, 0, sizeof(mreq) );
memcpy( &mreq.ipv6mr_multiaddr, &((struct sockaddr_in6 *) multi->ai_addr)->sin6_addr, sizeof(mreq.ipv6mr_multiaddr) );
mreq.ipv6mr_interface = 2; // 2 happens to be the interface ID; I've tried other values here
freeaddrinfo( multi );

if( setsockopt( s, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq) ) != 0 ) {
    close( s );
    perror( "IPV6_JOIN_GROUP" );
    exit( 1 );
}

for( ; ; ) {
    char data[6];
    size_t len;

    len = recvfrom( s, data, 5, 0, NULL, NULL );
    data[5] = '\0';

    printf( "Received %s\n", data );

    if( strcmp( data, "exitt" ) == 0 ) {
        break;
    }
}

客户端代码如下:

memset( &hint, 0, sizeof( hint ) );

hint.ai_family = AF_INET6;
hint.ai_socktype = SOCK_DGRAM;
hint.ai_protocol = 0;

err = getaddrinfo( "ff02::1", NULL, &hint, &info );

if( err != 0 ) {
    perror( "getaddrinfo" );
    return 0;
}

struct sockaddr_in6 * addr = (struct sockaddr_in6*)info->ai_addr;
addr->sin6_port = htons( 7890 );
addr->sin6_scope_id = 2; // 2 happens to be the interface ID
s = socket( AF_INET6, SOCK_DGRAM, 0 );

for( ; ; ) {
    char data[6];
    size_t len;

    scanf( "%5s", data );
    data[5] = '\0';
    printf( "Sending %s\n", data );
    if( sendto( s, data, 5, 0, info->ai_addr, info->ai_addrlen ) != 5 ) {
        printf( "Error sending\n" );
    }

    if( strcmp( data, "exitt" ) == 0 ) {
        break;
    }
}

close( s );


推荐答案

绑定过滤入站地址,适配器地址,您只能获取匹配目标地址的数据包:即单播数据包,如果绑定到多播地址,您将只获得组播数据包;要获取组播和单播数据包,您必须绑定到INADDR_ANY或IN6ADDR_ANY。

Binding filters incoming addresses, so if you bind to an adapter address you only get packets with matching destination address: i.e. unicast packets, if you bind to a multicast address you will only get multicast packets; to get multicast and unicast packets you must bind to INADDR_ANY or IN6ADDR_ANY.

这篇关于在Linux上侦听IPv6组播的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆