在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)而不是一个单播地址(我已经尝试链接本地和全球地址),它确实得到多播。 我想知道如果有人能指出我做错了什么。

服务器:

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。