2008-12-12 18 views
12

Estoy tratando de obtener datos de multidifusión udp usando sockets y C++ (c). Tengo un servidor con 2 tarjetas de red, así que debo vincular el socket a una interfaz específica. Actualmente estoy probando en otro servidor que solo tiene una tarjeta de red.¿Cómo configurar un socket para multidifusión UDP con 2 tarjetas de red presentes?

Cuando uso INADDR_ANY puedo ver los datos udp, cuando me enlace a una interfaz específica, no veo ningún dato. La función inet_addr no está fallando (eliminé la comprobación del valor de retorno por ahora).

El código está debajo. En un servidor con una tarjeta de red, mi dirección IP es 10.81.128.44. Recibo de datos cuando corro como: ./client 225.0.0.37 12346

Esto me da ningún dato: ./client 225.0.0.37 12346 10.81.128.44

¿Alguna sugerencia? (Espero que el código se compila, quité los comentarios ...)

#include <stdlib.h> 
    #include <sys/types.h> 
    #include <sys/socket.h> 
    #include <netinet/in.h> 
    #include <arpa/inet.h> 
    #include <time.h> 
    #include <string.h> 
    #include <stdio.h> 

    #include <iostream> 
    #include <string> 

    using namespace std; 

    #define HELLO_PORT 12345 
    #define HELLO_GROUP "225.0.0.37" 
    #define MSGBUFSIZE 256 

    int main(int argc, char *argv[]) 
    { 
     string source_iface; 
     string group(HELLO_GROUP); 
     int port(HELLO_PORT); 

     if (!(argc < 2)) group = argv[1]; 
     if (!(argc < 3)) port = atoi(argv[2]); 
     if (!(argc < 4)) source_iface = argv[3]; 

     cout << "group: " << group << " port: " << port << " source_iface: " << source_iface << endl; 

     int fd; 
     if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 
     { 
      perror("socket"); 
      exit(1); 
     } 

     u_int yes = 1; 
     if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) 
     { 
      perror("Reusing ADDR failed"); 
      exit(1); 
     } 

     struct sockaddr_in addr; 
     memset(&addr, 0, sizeof(addr)); 
     addr.sin_family = AF_INET; 
     addr.sin_port = htons(port); 
     addr.sin_addr.s_addr = (source_iface.empty() ? htonl(INADDR_ANY) : inet_addr(source_iface.c_str())); 

    if (bind(fd,(struct sockaddr *)&addr, sizeof(addr)) < 0) 
    { 
     perror("bind"); 
     exit(1); 
    } 

    struct ip_mreq mreq; 
    mreq.imr_multiaddr.s_addr = inet_addr(group.c_str()); 
    mreq.imr_interface.s_addr = (source_iface.empty() ? htonl(INADDR_ANY) : inet_addr(source_iface.c_str())); 

    if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) 
    { 
     perror("setsockopt"); 
     exit(1); 
    } 

    socklen_t addrlen; 
    int nbytes; 
    char msgbuf[MSGBUFSIZE]; 

    while (1) 
    { 
     memset(&msgbuf, 0, MSGBUFSIZE); 

     addrlen = sizeof(addr); 
     if ((nbytes = recvfrom(fd, msgbuf, MSGBUFSIZE, 0, (struct sockaddr *)&addr, &addrlen)) < 0) 
     { 
      perror("recvfrom"); 
      exit(1); 
     } 
     cout.write(msgbuf, nbytes); 
     cout.flush(); 
    } 

    return 0; 
} 

Gracias por adelantado ...

Respuesta

3

Creo que es necesario agregar IP_MULTICAST_IF

struct ip_mreq   multi; 

    multi.imr_multiaddr.s_addr = inet_addr(group.c_str()); 
    multi.imr_interface.s_addr = (source_iface.empty() ? 
     htonl(INADDR_ANY): inet_addr(source_iface.c_str())); 

    status = setsockopt(me->ns_fd, IPPROTO_IP, IP_MULTICAST_IF, 
     (char *)&multi.imr_interface.s_addr, 
     sizeof(multi.imr_interface.s_addr)); 

Espero que ayude.

7

Después de algunas búsquedas y pruebas descubrí here que cuando vinculando udp socket multicast especificamos el puerto y dejamos la dirección vacía, p. especifique INADDR_ANY.

Así que el siguiente

addr.sin_family = AF_INET; 
addr.sin_port = htons(port); 
addr.sin_addr.s_addr = (source_iface.empty() ? 
         htonl(INADDR_ANY) : 
         inet_addr(source_iface.c_str())); 

debe verse como:

COMENTARIO: Si entiendo su código que debe ser vinculante a su dirección de multidifusión no la dirección de comodín. Si se vincula a la dirección de comodín, podrá recibir paquetes de unidifusión en su puerto de multidifusión. Al enlazar a su dirección de multidifusión, lo evitará y se asegurará de que solo obtenga paquetes de multidifusión en ese puerto.

EDITAR: Se ha corregido el código basado en comentario anterior, la unión a la dirección de multidifusión, almacenada en 'grupo', en contraposición a INADDR_ANY para recibir solamente los paquetes de multidifusión enviados a dirección de multidifusión.

addr.sin_family = AF_INET; 
addr.sin_port = htons(port); 
addr.sin_addr.s_addr = (group.empty() ? 
         htonl(INADDR_ANY) : 
         inet_addr(group.c_str())); 

Esto resolvió el problema. Agregar IP_MULTICAST_IF no ayudará porque eso es para seleccionar una interfaz específica para enviar datos udp, el problema anterior estaba en el lado de recepción.

+0

Si entiendo tu código, deberías enlazar a tu dirección de multidifusión, no a la dirección de comodín. Si se vincula a la dirección de comodín, podrá recibir paquetes de difusión única en su puerto de multidifusión. El enlace a su dirección de multidifusión evitará esto y se asegurará de que solo obtenga paquetes de multidifusión en ese puerto. –

+0

Su derecho, en realidad lo he descubierto hace un tiempo, simplemente no he actualizado la respuesta aquí. Gracias, he actualizado el código. – stefanB

Cuestiones relacionadas