UDP: escuchar el mismo puerto para dos transmisiones de multidifusión diferentes

Necesito escuchar 2 grupos de multidifusión diferentes usando el mismo puerto. Program A escuchará desde 230.0.0.1 y el Program B desde 230.0.0.2 . Ambos grupos de multidifusión usan el mismo port 2000 y no tengo control sobre él.

Cuando ejecuto mis progtwigs, recibo ambas transmisiones de multidifusión en cada progtwig, es decir, los paquetes de datos emitidos en 230.0.0.1 y 230.0.0.2 . Sospecho que el problema se debe al puerto común. Este es el código que estoy usando para suscribirme a la multidifusión:

 if( (sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0 ) { perror("socket"); return -1; } if( setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0 ) { perror("setsockopt SO_REUSEADDR"); return -1; } memset(&in_addr, 0, sizeof(in_addr)); in_addr.sin_family = AF_INET; in_addr.sin_addr.s_addr = htonl(INADDR_ANY); in_addr.sin_port = htons(2000); if( bind(sd, (struct sockaddr*)&in_addr, sizeof(in_addr)) < 0 ) { perror("bind"); return -1; } memset(&req, 0, sizeof(req)); inet_aton(intfc_ip, &req.imr_interface); inet_aton("230.0.0.1", &req.imr_multiaddr); if( setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &req, sizeof(req)) < 0 ) { perror("setsockopt IP_ADD_MEMBERSHIP"); return -1; } recv()... 

¿Cómo puedo filtrar un grupo multicast específico en cada progtwig?

Si cambias

 in_addr.sin_addr.s_addr = htonl(INADDR_ANY); 

a

 inet_aton(, &in_addr.sin_addr.s_addr); 

Podrías tener más éxito.

(Y si cambia su progtwig para trabajar con getaddrinfo() , lo hace a prueba de futuro).

“conectar” podría ser lo que necesitas después de todo. Normalmente, para conectar sockets TCP, la página de manual también sugiere que se puede usar para filtrar paquetes UDP de otras direcciones:

De la página man publicada aquí :

Si el socket sockfd es del tipo SOCK_DGRAM, entonces addr es la dirección a la que se envían los datagtwigs por defecto, y la única dirección desde la cual se reciben los datagtwigs.

El problema con el código de socket es que “recvfrom” solo le dará la dirección de origen desde donde se envió el paquete. No le indica la dirección IP a la que se envió el paquete. Desea poder inspeccionar la dirección de destino del paquete UDP para poder filtrar los paquetes que se enviaron a direcciones IP de multidifusión en las que no está interesado.

Hay una opción de socket que puede establecer seguida del uso de “recvmsg” en lugar de recv o recvfrom para obtener la dirección IP de destino a la que se envió el paquete.

1) Utilice setsockopt con IP_PKTINFO para permitir que la dirección IP de destino se transfiera al nivel de la aplicación para los datos recibidos en el socket.

 int enable = 1; setsockopt(sock, IPPROTO_IP , IP_PKTINFO , &enable, sizeof(enable)); 

2) Utilice recvmsg en lugar de recvfrom (o recv) para obtener la dirección de destino a la que se envió el paquete UDP. Tengo una función de ayuda llamada “recvfromex” que envuelve recvmsg y refleja la funcionalidad de recvfrom – espera que tenga un parámetro adicional para que la persona que llama obtenga la IP de destino del paquete.

Es un poco ventoso publicar, pero puedes mirar mi código C ++ de mi proyecto github y tomar lo que necesites.

Mira la función recvfromex aquí

Más ejemplo de código para la llamada setsockopt aquí (busque la función “EnablePktInfo” sobre cómo usar la llamada setsockopt con IP_PKTINFO). También contiene extensiones para IPV6 y BSD.

(de la respuesta de Receving múltiples transmisiones de multidifusión en el mismo puerto – C, Linux )

La página de manual de ip (7) describe una posible solución:

IP_MULTICAST_ALL (desde Linux 2.6.31)
Esta opción se puede usar para modificar la política de entrega de mensajes de multidifusión a sockets vinculados a la dirección de comodín INADDR_ANY. El argumento es un entero booleano (por defecto es 1). Si se establece en 1, el socket recibirá mensajes de todos los grupos que se han unido a nivel mundial en todo el sistema. De lo contrario, solo enviará mensajes de los grupos que se han unido explícitamente (por ejemplo, a través de la opción IP_ADD_MEMBERSHIP) en este socket en particular.

Luego, puede activar el filtro para recibir mensajes de grupos unidos usando:

 int mc_all = 0; if ((setsockopt(sock, IPPROTO_IP, IP_MULTICAST_ALL, (void*) &mc_all, sizeof(mc_all))) < 0) { perror("setsockopt() failed"); }