无法从多播组获取数据

时间:2018-08-28 07:47:32

标签: c linux networking udp

怎么了?如果一个组的成员发送数据,那么他们的程序为什么不接收它?对于那些不了解该代码在Linux上运行的标签的人来说,我报告该代码在Linux。如果一切正常,为什么要调试代码。当我运行程序时,会出现一个新的组,使用ip -s maddr

可以很容易地进行检查。
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <ifaddrs.h>
#include <ctype.h>

char in[IFNAMSIZ];
const char *multi = "224.0.0.1";
const short port = 0;

static int
init_socket ( )
{
    int sock = socket ( AF_INET, SOCK_DGRAM, 0 );

    int ret;
    struct ifreq ifr;
    memset ( &ifr, 0, sizeof ifr );
    strncpy ( ifr.ifr_name, in, strlen ( in ) );
    ret = ioctl ( sock, SIOCGIFADDR, &ifr );
    if ( ret == -1 ) {
        perror ( "SIOCGIFADDR" );
        printf ( "%s\n", in );
        exit ( EXIT_FAILURE );
    }

    struct ip_mreqn ip;
    inet_aton ( multi, &ip.imr_multiaddr );
    memcpy ( &ip.imr_address, 
            &( ( struct sockaddr_in * ) &ifr.ifr_addr)->sin_addr, 
            sizeof ( struct in_addr ) );

    ip.imr_ifindex = if_nametoindex ( ifr.ifr_name );

    struct sockaddr_in s;
    memset ( &s, 0, sizeof s );
    s.sin_family = AF_INET;
    memcpy ( &s.sin_addr, 
            &( ( struct sockaddr_in * ) &ifr.ifr_addr)->sin_addr, 
            sizeof ( struct in_addr ) );
    s.sin_port = htons ( port );

    const int on = 1;
    ret = setsockopt ( sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on );
    if ( ret == -1 ) { 
        perror ( "setsockopt so_reuseaddr" ); 
        exit ( EXIT_FAILURE ); 
    }

    ret = setsockopt ( sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &ip, sizeof ip );
    if ( ret == -1 ) { 
        perror ( "setsockopt ip_add_membership" ); 
        exit ( EXIT_FAILURE ); 
    }

//  bind ( sock, ( struct sockaddr * ) &s, sizeof ( s ) );
    return sock;
}
const int length = 16384;
void *reader ( void *data )
{
    int sock = *( (int *) data );
    char buf [ length ];
    while ( 1 ) {
        read ( sock, buf, length );
        printf ( "%s\n", buf );
    }
}

static int
check_buf ( const char *b )
{
    for ( ; *b != 0; b++ ) {
        if ( *b == 10 || *b == 13 ) continue;
        if ( !isdigit ( *b ) ) {
            return -1;
        }
    }
    return 0;
}
static void
get_interface ( )
{
    struct ifaddrs *ifs, *ifa;
    if ( getifaddrs ( &ifs ) == -1 ) {
        perror ( "getifaddrs" );
        exit ( EXIT_FAILURE );
    }
    char buf[10];

    int n = 0;
    while ( in[0] == 0 ) {
        int number = 1;
        for ( ifa = ifs; ifa != NULL; ifa = ifa->ifa_next, number++ ) {
            if ( ifa->ifa_addr == NULL ) continue;
            int family = ifa->ifa_addr->sa_family;

            if ( family == AF_INET ) {
                if ( n == 0 ) printf ( "%d: %s\n", number, ifa->ifa_name );
            }
            if ( n == number ) {
                strncpy ( in, ifa->ifa_name, strlen ( ifa->ifa_name ) );
                return;
            }
        }
        fgets ( buf, 10, stdin ); 
        int ret = check_buf ( &buf[0] );
        if ( ret != -1 ) n = atoi ( buf );
    }
}

int main ( )
{
    get_interface ( );
    int sock = init_socket ( );

    pthread_t pt;

    pthread_create ( &pt, NULL, reader, &sock );

    struct sockaddr_in s;
    s.sin_family = AF_INET;
    inet_aton ( multi, &s.sin_addr );
    s.sin_port = htons ( port );
    char buf [ length ];
    while ( 1 ) {
        printf ( "> " );
        fgets ( buf, length, stdin );
//      write ( sock, buf, strlen ( buf ) );
        sendto ( sock, buf, strlen ( buf ), 0, ( struct sockaddr * ) &s, sizeof s );
    }

    close ( sock );
}

所以我正在等待您的帮助。

1 个答案:

答案 0 :(得分:0)

您需要在多播地址上使用bind。

struct sockaddr_in s;
s.sin_family = AF_INET;
inet_aton ( "224.0.0.2", &s.sin_addr );
s.sin_port = htons ( 12345 );
bind ( sock, ( struct sockaddr * ) &s, sizeof s );