[Editado para aclarar que bind()
puede, de hecho, incluir una dirección de multidifusión.]
lo que la aplicación es unirse a varios grupos de multidifusión, y la recepción de los mensajes enviados a cualquiera de ellos, en el mismo puerto. SO_REUSEPORT
le permite vincular varios sockets al mismo puerto. Además del puerto, bind()
necesita una dirección IP. INADDR_ANY
es una dirección catch-all, pero también se puede usar una dirección IP, incluida una de multidifusión. En ese caso, solo los paquetes enviados a esa IP se entregarán al socket. Es decir. puede crear varios sockets, uno para cada grupo de multidifusión. bind()
cada socket al (group_addr, port), AND join group_addr. Luego, los datos dirigidos a diferentes grupos aparecerán en diferentes tomas, y podrá distinguirlo de esa manera.
He probado que los siguientes trabajos en FreeBSD:
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/param.h>
#include <unistd.h>
#include <errno.h>
int main(int argc, const char *argv[])
{
const char *group = argv[1];
int s = socket(AF_INET, SOCK_DGRAM, 0);
int reuse = 1;
if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse)) == -1) {
fprintf(stderr, "setsockopt: %d\n", errno);
return 1;
}
/* construct a multicast address structure */
struct sockaddr_in mc_addr;
memset(&mc_addr, 0, sizeof(mc_addr));
mc_addr.sin_family = AF_INET;
mc_addr.sin_addr.s_addr = inet_addr(group);
mc_addr.sin_port = htons(19283);
if (bind(s, (struct sockaddr*) &mc_addr, sizeof(mc_addr)) == -1) {
fprintf(stderr, "bind: %d\n", errno);
return 1;
}
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr(group);
mreq.imr_interface.s_addr = INADDR_ANY;
setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
char buf[1024];
int n = 0;
while ((n = read(s, buf, 1024)) > 0) {
printf("group %s fd %d len %d: %.*s\n", group, s, n, n, buf);
}
}
Si ejecuta varios de estos procesos, para diferentes direcciones de multidifusión, y enviar un mensaje a una de las direcciones, sólo el proceso relevante lo recibirán. Por supuesto, en su caso, es probable que desee tener todos los sockets en un proceso, y tendrá que usar select
o poll
o equivalente para leerlos todos.
No creo que pueda vincularse a una dirección de multidifusión; debe enlazar a su interfaz local (INADDR_ANY). – Gigi
Ver aquí (leer los 2 primeros comentarios): https://jira.jboss.org/jira/browse/JGRP-639 –
No puedo realizar pruebas en Linux, pero he escrito una pequeña prueba (incluida en la respuesta editada)), y verificó que funciona correctamente en FreeBSD. –