Obtener la dirección IP de la máquina actual usando Java
Estoy intentando desarrollar un sistema en el que hay diferentes nodos que se ejecutan en diferentes sistemas o en diferentes puertos del mismo sistema.
Ahora todos los nodos crean un Socket con una IP de destino como la IP de un nodo especial conocido como nodo de arranque. Luego, los nodos crean los suyos propios ServerSocket
y comienzan a escuchar las conexiones.
El nodo de arranque mantiene una lista de nodos y los devuelve al ser consultado.
Ahora lo que necesito es que el nodo registre su IP en el nodo de arranque. Intenté usarlo cli.getInetAddress()
una vez que el cliente se conecta al ServerSocket
nodo de arranque, pero no funcionó.
- Necesito que el cliente registre su IP PPP si está disponible;
- De lo contrario, la IP de la LAN si está disponible;
- De lo contrario, debe registrar 127.0.0.1 suponiendo que sea la misma computadora.
Usando el código:
System.out.println(Inet4Address.getLocalHost().getHostAddress());
o
System.out.println(InetAddress.getLocalHost().getHostAddress());
La dirección IP de mi conexión PPP es: 117.204.44.192 pero lo anterior me devuelve 192.168.1.2
EDITAR
Estoy usando el siguiente código:
Enumeration e = NetworkInterface.getNetworkInterfaces();
while(e.hasMoreElements())
{
NetworkInterface n = (NetworkInterface) e.nextElement();
Enumeration ee = n.getInetAddresses();
while (ee.hasMoreElements())
{
InetAddress i = (InetAddress) ee.nextElement();
System.out.println(i.getHostAddress());
}
}
Puedo obtener todas las direcciones IP asociadas a todos NetworkInterface
los correos electrónicos, pero ¿cómo las distingo? Este es el resultado que obtengo:
127.0.0.1
192.168.1.2
192.168.56.1
117.204.44.19
Esto podría resultar un poco complicado en el caso más general.
A primera vista, InetAddress.getLocalHost()
debería proporcionarle 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 todas las direcciones IP serán accesibles 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 es posible que la dirección IP devuelta por InetAddress.getLocalHost()
no sea la correcta.
¿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 anunciado externamente para el host y usarlo
InetAddress.getByName()
para buscar la dirección IP principal. (Pero ¿cómo se obtiene y cómo se maneja un balanceador 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 ejecute 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". Sólo 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 172.16.xxx.xxx a 172.31.xxx.xxx.
- Las direcciones en el rango 169.254.xxx.xxx son direcciones IP locales de enlace. Están reservados para su uso en un único segmento de red.
- Las direcciones en el rango 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.
- Cualquier otra cosa debe ser una dirección IPv4 pública punto a punto válida.
De hecho, la API InetAddress proporciona métodos para probar direcciones de bucle invertido, enlace local, sitio local, multidifusión y transmisión. Puede utilizarlos para determinar cuál de las direcciones IP que obtiene es la más apropiada.
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();
}
Esta forma funciona bien cuando hay varias interfaces de red. Siempre devuelve la IP saliente preferida. No es necesario que el destino 8.8.8.8
sea alcanzable.
Connect
en un socket UDP tiene el siguiente efecto: establece el destino para Envío/Recepción, 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.
Entonces, este método proporcionará la dirección local que se utilizará para conectarse al host remoto especificado. No se ha establecido una conexión real, por lo que es posible que no se pueda acceder a la IP remota especificada.
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());