2010-03-02 15 views
6

Estoy implementando un tipo de buscador de IP para un tipo particular de dispositivo multimedia de red. Quiero encontrar todos los dispositivos activos de ese tipo en la LAN, con su dirección IP y otros detalles.Recepción de respuesta (s) de N número de clientes en respuesta a una solicitud de difusión a través de UDP

El dispositivo tiene su propia forma de descubrimiento de dispositivos.

Funciona de la siguiente manera: Un cliente envía una solicitud de difusión a través de la LAN a través de UDP.
El número de puerto de destino es fijo.
En respuesta, todos los servidores en la LAN que entienden el formato de esta solicitud responderán a esta solicitud proporcionando información sobre ellos.

Estoy transmitiendo el mensaje de solicitud UDP usando sendto().

Ahora mi problema es que no sé cuántos dispositivos (es decir, servidores) responderán a la solicitud.

¿Cuántas veces tendré que llamar a recvfrom()?
¿Cuándo sabré que he manejado la respuesta de todos los dispositivos?
O, en general, ¿es recvfrom() la elección correcta para recibir respuesta de múltiples servidores?
¿Hay alguna forma mejor (o CORRECTA si estoy equivocado aquí) de lograr lo mismo?

Estoy programando en C/C++, planeando codificar para Windows y Linux.
Muchas gracias de antemano.

Editar: Así que con la ayuda de toda la programación de la red magos aquí, he encontrado la solución a mi problema :)
seleccione() es sólo la cosa para mí ...
Muchas gracias a todos ustedes que tomaron tiempo para ayudarme

+0

Creo que, después de la fase de descubrimiento, ¿desea comunicarse con estos dispositivos? ¿Por qué no usar la multidifusión IP desde el principio (ver http://en.wikipedia.org/wiki/Multicast)? –

+0

El servidor está implementado en firmware. No tengo más opción que seguir el protocolo establecido por el fabricante del dispositivo.Tengo que transmitir la solicitud a través de UDP :( – puffadder

+0

Esto realmente me hace pensar en 'UPNP' o' Universal Plug and Play', http://fr.wikipedia.org/wiki/Universal_Plug_and_Play –

Respuesta

2

¿Cuántas veces tendré que llamar a recvfrom()? ¿Cuándo sabré que he manejado la respuesta de todos los dispositivos/servidores?

Si usted no sabe el número de dispositivos/servidores, no se puede saber cuántas veces se tendrá que llamar recvfrom() o cuando usted ha manejado todas las respuestas.

Puede considerar el uso de un bucle select() (hasta el tiempo de espera) y llamar al recvfrom() cuando haya datos disponibles para leer. Esto podría estar en el hilo principal o en un hilo separado.

Si los datos llegan más rápido de lo que se pueden procesar, perderá los datagramas. Esto dependerá en gran medida de la velocidad con la que se analizan y almacenan los datos después de que se reciben. Si el procesamiento de los datos es una operación intensiva, puede ser necesario hacer el procesamiento en un hilo separado o almacenar los datos hasta que el ciclo de recepción expire y luego proceder con el procesamiento.

Dado que el UDP no es confiable, el bucle para retransmitir algunas veces debería ayudar a explicar parte de la pérdida y el procesamiento debe dar cuenta de los duplicados.

El siguiente pseudocódigo es cómo podría abordar el problema:


/* get socket to receive responses */ 
sd = socket(...); 

do 
{ 
    /* set receive timeout */ 
    timeout.tv_sec = 5;  

    /* broadcast request */ 
    sendto(...); 

    /* wait for responses (or timeout) */ 
    while(select(sd+1, &readfds, NULL, NULL, &timeout) > 0) 
    { 
     /* receive the response */ 
     recvfrom(...); 

     /* process the response (or queue for another thread/later processing) */ 
     ... 

     /* reset receive timeout */ 
     timeout.tv_sec = 5; 
    } 

    /* process any response queued for later (and not another thread) */ 

} while (necessary); 

o, en general, es recvfrom() la opción correcta para recibir respuesta por parte de varios servidores?

recvfrom() se usa comúnmente con sockets de modo sin conexión porque permite que la aplicación recupere la dirección de origen de los datos recibidos.

+1

Si todos los servidores respondieran al al mismo tiempo, ¿cómo se manejaría? – puffadder

+0

Gracias por la respuesta. Pero, ¿realmente necesito un hilo para procesar cada respuesta? ¿Hay alguna otra salida? – puffadder

+0

Las respuestas contienen la dirección IP y la identificación del dispositivo de los respondedores, entre otras cosas Quiero analizar las respuestas y almacenar los datos necesarios – puffadder

2

Utilice un select(2)/poll(2) con un tiempo de espera en un bucle, disminuyendo el tiempo de espera cada vez que recibe una respuesta de un dispositivo. Tendría que pensar en el tiempo de espera apropiado.

Como alternativa, si puede reconocer/analizar el mensaje de respuesta de descubrimiento, simplemente agregue el dispositivo a la lista al recibir dicho mensaje.

Probablemente tenga que ocuparse de los tiempos de espera de todos modos para cuando los dispositivos se registren pero fallen en un momento posterior.

2

Si no sabe cuántos servidores van a responder, entonces no sabe cuántas veces tiene que llamar a recvfrom(). Probablemente me volvería a manejar esto con un bucle de selección() con un tiempo de espera adecuado, algo así como lo siguiente, que es completamente probado y probablemente lleno de estúpidos errores:

/* create and bind socket */ 

fd_set fds; 
struct timeval tv; 

tv.tv_sec = 2; 
tv.tv_usec = 0; 
FD_ZERO(&fds); 
FD_SET(sock, &fds); 
int ret; 

while((ret = select(sock + 1, &fds, NULL, NULL, &tv)) > 0) { 
    char buf[BUFLEN]; 
    struct sockaddr addr; 

    if(recvfrom(sock, buf, BUFLEN, MSG_DONTWAIT, &addr, sizeof(struct sockaddr)) > 0) { 
     /* handle response */ 
    } else { 
     /* handle error */ 
    }   
} 
if(ret < 0) { 
    /* handle error */ 
} else { 
    /* select() timed out; we're theoretically done */ 
} 

Esto mantendrá llamando recvfrom() hasta que no respuesta tiene recibido durante 2 segundos, lo que por supuesto significa que se bloqueará durante un mínimo de 2 segundos. Dependiendo del protocolo subyacente, probablemente pueda salirse con un tiempo de espera mucho más corto; de hecho, puedes disminuirlo en cada respuesta. Se requerirán algunas pruebas y ajustes para encontrar la configuración óptima. No necesita preocuparse de que los servidores respondan al mismo tiempo; la capa de Ethernet manejará eso.

+0

¿Necesito necesariamente "enlazar" para usar la función de selección? Actualmente no estoy vinculando el socket ... – puffadder

+0

@pufadder - No, no necesitas 'bind'. 'select()' toma un conjunto de descriptores de archivo, y recibirá un descriptor de archivo para agregar al conjunto cuando cree el socket. – jschmier

+0

Incluso si sabe cuántos servidores iban a responder, no sabe cuántos mensajes va a recibir. Algunos de los paquetes pueden ser eliminados en el camino. – nos

0

No puede saber. Es incognoscible

Presumiblemente, de su descripción: I want to find out all the alive devices, los dispositivos pueden hacer la transición de muertos a vivos y viceversa en cualquier momento que lo deseen. Esto significa que tendrá que sondear continuamente: es decir, enviará la solicitud de transmisión cada pocos segundos (pero no con demasiada frecuencia) y verá quién responde.

Si he entendido bien, que UDP es inherentemente poco fiable, que van a tener para la reconversión de algunos fiabilidad en la parte superior de la UDP:

  • Enviar la transmisión cada pocos segundos, ya que los dispositivos puede no recibirlo todo el tiempo.
  • Es posible que no reciba sus respuestas, pero es posible que la próxima vez.
  • Una respuesta confirma que un dispositivo está activo.
  • Espere 'n' no respuestas antes de declarar un dispositivo muerto.

¿Conoces la cantidad máxima de dispositivos posibles? Si lo haces, es posible que tengas que llamar a recvfrom() muchas veces.

Cuestiones relacionadas