Pregunta

  1. Tienes varios adaptadores de red.
  2. Vincule un socket UDP a un puerto local, sin especificar una dirección.
  3. Reciba paquetes en uno de los adaptadores.

¿Cómo se obtiene la dirección IP local del adaptador que recibió el paquete?

La pregunta es: "¿Cuál es la dirección IP del adaptador del receptor?" no la dirección del remitente que obtenemos en el

receive_from( ..., &senderAddr, ... );

llamar.

¿Fue útil?

Solución

Podrías enumerar todos los adaptadores de red, obtener sus direcciones IP y comparar la parte cubierta por la máscara de subred con la dirección del remitente.

Como:

IPAddress FindLocalIPAddressOfIncomingPacket( senderAddr )
{
    foreach( adapter in EnumAllNetworkAdapters() )
    {
        adapterSubnet = adapter.subnetmask & adapter.ipaddress;
        senderSubnet = adapter.subnetmask & senderAddr;
        if( adapterSubnet == senderSubnet )
        {
            return adapter.ipaddress;
        }
    }
}

Otros consejos

Buen día,

Supongo que ha realizado el enlace utilizando INADDR_ANY para especificar la dirección.

Si este es el caso, entonces la semántica de INADDR_ANY es tal que se crea un socket UDP en el puerto especificado en todas sus interfaces.El socket recibirá todos los paquetes enviados a todas las interfaces en el puerto especificado.

Al realizar envíos utilizando este socket, se utiliza la interfaz con el número más bajo.El campo de dirección del remitente saliente se establece en la dirección IP de la primera interfaz saliente utilizada.

La primera interfaz saliente se define como la secuencia cuando realiza ifconfig -a.Probablemente será eth0.

HTH.

Saludos, Rob

La solución proporcionada por timbo Se supone que los rangos de direcciones son únicos y no se superponen.Si bien este suele ser el caso, no es una solución genérica.

Existe una excelente implementación de una función que hace exactamente lo que después se proporciona en el libro de Steven "Programación de red UNIX" (Sección 20.2) Esta es una función basada en RecvmSg (), en lugar de RecvFrom ().Si su socket tiene habilitada la opción IP_RECVIF, recvmsg() devolverá el índice de la interfaz en la que se recibió el paquete.Esto luego se puede utilizar para buscar la dirección de destino.

El código fuente está disponible aquí.La función en cuestión es 'recvfrom_flags()'

Desafortunadamente, las llamadas API sendto y recvfrom están fundamentalmente rotas cuando se usan con sockets vinculados a "Cualquier IP" porque no tienen ningún campo para información de IP local.

Entonces, ¿qué puede hacer usted al respecto?

  1. Puede adivinar (por ejemplo, basándose en la tabla de enrutamiento).
  2. Puede obtener una lista de direcciones locales y vincular un socket separado a cada dirección local.
  3. Puede utilizar API más nuevas que admitan esta información.Hay dos partes en esto, primero debe usar la opción de socket relavent (ip_recvif para IPv4, ipv6_recvif para IPv6) para indicarle a la pila que desea esta información.Luego debe usar una función diferente (recvmsg en Linux y varios otros sistemas similares a Unix, WSArecvmsg en Windows) para recibir el paquete.

Ninguna de estas opciones es genial.Obviamente, adivinar producirá respuestas incorrectas en ocasiones.La vinculación de sockets separados aumenta la complejidad de su software y causa problemas si la lista de direcciones locales cambia mientras se ejecuta su programa.Las API más nuevas son la solución técnica correcta, pero pueden reducir la portabilidad. (En particular, parece que WSArecvmsg no está disponible en Windows XP) y puede requerir modificaciones en la biblioteca contenedora de sockets que está utilizando.

Editar parece que me equivoqué, parece que la documentación de MS es engañosa y que WSArecvmsg está disponible en Windows XP.Ver https://stackoverflow.com/a/37334943/5083516

ssize_t
     recvfrom(int socket, void *restrict buffer, size_t length, int flags,
         struct sockaddr *restrict address, socklen_t *restrict address_len);

     ssize_t
     recvmsg(int socket, struct msghdr *message, int flags);

[..]
     If address is not a null pointer and the socket is not connection-oriented, the
     source address of the message is filled in.

Código real:

int nbytes = recvfrom(sock, buf, MAXBUFSIZE, MSG_WAITALL, (struct sockaddr *)&bindaddr, &addrlen);

fprintf(stdout, "Read %d bytes on local address %s\n", nbytes, inet_ntoa(bindaddr.sin_addr.s_addr));

espero que esto ayude.

Prueba esto:

gethostbyname("localhost");
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top