Saltar al contenido

Obtener la dirección IP de la máquina actual usando Java

Te recomendamos que revises esta solución en un ambiente controlado antes de enviarlo a producción, un saludo.

Solución:

Esto podría ser un poco complicado en el caso más general.

En la cara de eso, InetAddress.getLocalHost() debería darle la dirección IP de este host. El problema es que un host podría tener muchas interfaces de red y una interfaz podría estar vinculada a más de una dirección IP. Y para colmo, no se podrá acceder a todas las direcciones IP fuera de su máquina o su LAN. Por ejemplo, podrían ser direcciones IP para dispositivos de red virtual, direcciones IP de red privada, etc.

Lo que esto significa es que la dirección IP devuelta por InetAddress.getLocalHost() puede que no sea el adecuado para usar.

¿Cómo puedes lidiar con esto?

  • Un enfoque es utilizar NetworkInterface.getNetworkInterfaces() para obtener todas las interfaces de red conocidas en el host y luego iterar sobre las direcciones de cada NI.
  • Otro enfoque es (de alguna manera) obtener el FQDN publicitado externamente para el host y usar InetAddress.getByName() para buscar la dirección IP principal. (Pero, ¿cómo se obtiene y cómo se maneja con un equilibrador de carga basado en DNS?)
  • Una variación de lo anterior es obtener el FQDN preferido de un archivo de configuración o un parámetro de línea de comando.
  • Otra variación es obtener la dirección IP preferida de un archivo de configuración o un parámetro de línea de comando.

En resumen, InetAddress.getLocalHost() normalmente funcionará, pero es posible que deba proporcionar un método alternativo para los casos en los que su código se ejecuta en un entorno con redes “complicadas”.


Puedo obtener todas las direcciones IP asociadas a todas las interfaces de red, pero ¿cómo las distingo?

  • Cualquier dirección en el rango 127.xxx.xxx.xxx es una dirección de “bucle invertido”. Solo es visible para “este” host.
  • Cualquier dirección en el rango 192.168.xxx.xxx es una dirección IP privada (también conocida como local del sitio). Estos están reservados para su uso dentro de una organización. Lo mismo se aplica a las direcciones 10.xxx.xxx.xxx y de 172.16.xxx.xxx a 172.31.xxx.xxx.
  • Las direcciones en el rango 169.254.xxx.xxx son direcciones IP locales de enlace. Estos están reservados para su uso en un solo segmento de red.
  • Las direcciones en el rango de 224.xxx.xxx.xxx a 239.xxx.xxx.xxx son direcciones de multidifusión.
  • La dirección 255.255.255.255 es la dirección de transmisión.
  • Algo más deberían ser una dirección IPv4 pública de punto a punto válida.

De hecho, la API InetAddress proporciona métodos para probar direcciones de loopback, local de enlace, local de sitio, multidifusión y difusión. Puede utilizarlos para determinar cuál de las direcciones IP que obtiene es la más adecuada.

import java.net.DatagramSocket;
import java.net.InetAddress;

try(final DatagramSocket socket = new DatagramSocket())
  socket.connect(InetAddress.getByName("8.8.8.8"), 10002);
  ip = socket.getLocalAddress().getHostAddress();

De esta forma funciona bien cuando hay varias interfaces de red. Siempre devuelve la IP saliente preferida. El destino 8.8.8.8 no es necesario estar accesible.

Connect en un socket UDP tiene el siguiente efecto: establece el destino para Enviar / Recv, descarta todos los paquetes de otras direcciones y, que es lo que usamos, transfiere el socket al estado “conectado”, configura sus campos apropiados. Esto incluye verificar la existencia de la ruta al destino de acuerdo con la tabla de enrutamiento del sistema y configurar el punto final local en consecuencia. La última parte parece no estar documentada oficialmente, pero parece un rasgo integral de la API de sockets de Berkeley (un efecto secundario del estado “conectado” de UDP) que funciona de manera confiable tanto en Windows como en Linux en todas las versiones y distribuciones.

Por lo tanto, este método proporcionará la dirección local que se usaría para conectarse al host remoto especificado. No hay una conexión real establecida, por lo tanto, la IP remota especificada puede ser inalcanzable.

Editar:

Como dice @macomgil, para MacOS puedes hacer esto:

Socket socket = new Socket();
socket.connect(new InetSocketAddress("google.com", 80));
System.out.println(socket.getLocalAddress());

Publicar aquí el código de solución de ambigüedad de IP probado de https://issues.apache.org/jira/browse/JCS-40 (InetAddress.getLocalHost () ambiguo en sistemas Linux):

/**
 * Returns an InetAddress object encapsulating what is most likely the machine's LAN IP address.
 * 

* This method is intended for use as a replacement of JDK method InetAddress.getLocalHost, because * that method is ambiguous on Linux systems. Linux systems enumerate the loopback network interface the same * way as regular LAN network interfaces, but the JDK InetAddress.getLocalHost method does not * specify the algorithm used to select the address returned under such circumstances, and will often return the * loopback address, which is not valid for network communication. Details * here. *

* This method will scan all IP addresses on all network interfaces on the host machine to determine the IP address * most likely to be the machine's LAN address. If the machine has multiple IP addresses, this method will prefer * a site-local IP address (e.g. 192.168.x.x or 10.10.x.x, usually IPv4) if the machine has one (and will return the * first site-local address if the machine has more than one), but if the machine does not hold a site-local * address, this method will return simply the first non-loopback address found (IPv4 or IPv6). *

* If this method cannot find a non-loopback address using this selection algorithm, it will fall back to * calling and returning the result of JDK method InetAddress.getLocalHost. *

* * @throws UnknownHostException If the LAN address of the machine cannot be found. */ private static InetAddress getLocalHostLANAddress() throws UnknownHostException try InetAddress candidateAddress = null; // Iterate all NICs (network interface cards)... for (Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements();) NetworkInterface iface = (NetworkInterface) ifaces.nextElement(); // Iterate all IP addresses assigned to each card... for (Enumeration inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements();) InetAddress inetAddr = (InetAddress) inetAddrs.nextElement(); if (!inetAddr.isLoopbackAddress()) if (inetAddr.isSiteLocalAddress()) // Found non-loopback site-local address. Return it immediately... return inetAddr; else if (candidateAddress == null) // Found non-loopback address, but not necessarily site-local. // Store it as a candidate to be returned if site-local address is not subsequently found... candidateAddress = inetAddr; // Note that we don't repeatedly assign non-loopback non-site-local addresses as candidates, // only the first. For subsequent iterations, candidate will be non-null. if (candidateAddress != null) // We did not find a site-local address, but we found some other non-loopback address. // Server might have a non-site-local address assigned to its NIC (or it might be running // IPv6 which deprecates the "site-local" concept). // Return this non-loopback candidate address... return candidateAddress; // At this point, we did not find a non-loopback address. // Fall back to returning whatever InetAddress.getLocalHost() returns... InetAddress jdkSuppliedAddress = InetAddress.getLocalHost(); if (jdkSuppliedAddress == null) throw new UnknownHostException("The JDK InetAddress.getLocalHost() method unexpectedly returned null."); return jdkSuppliedAddress; catch (Exception e) UnknownHostException unknownHostException = new UnknownHostException("Failed to determine LAN address: " + e); unknownHostException.initCause(e); throw unknownHostException;

Agradecemos que desees auxiliar nuestra función poniendo un comentario o dejando una puntuación te estamos agradecidos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *