3 InetAddress¶
InetAddress¶
Como seguramente ya sepamos, todo ordenador conectado a Internet, al que se conoce normalmente como host, debe tener una dirección IP. Una dirección IPv4 está formada por cuatro bytes sin signo separados por puntos, en un rango de 0 a 255, como por ejemplo ejemplo: 152.2.21.2
.
Por su parte, una dirección IPv6 está formada por ocho bloques de cuatro dígitos hexadecimales cada uno separados por el carácter dos puntos, no siendo obligatorio escribir los ceros a la izquierda de cada bloque, incluso aunque el bloque quede sin ningún dígito. Un ejemplo sería 2001:250:2FF::250:8BFF:FEDE:67C8
. En redes mixtas de IPv6 y IPv4, los últimos cuatro bytes de la dirección se escriben algunas veces con la dotación IPv4. Por ejemplo FEDC:BA98:7654:3210:FEDC:BA98:7654:3210
se puede escribir como FEDC:BA98:7654:3210:FEDC:BA98:118.84.50.16
.
Para evitar tener que recordar las direcciones IP, los diseñadores de Internet crearon el sistema DNS, que asocia un nombre legible a la dirección IP. Por ejemplo podemos asociar el nombre hermes.oit.unc.edu
a la IP 152.2.21.2
.
Los ordenadores que no tienen una dirección IP permanente, como la mayoría de los PC de nuestra casa, no suelen poseer un nombre de dominio asociado. Por otra parte, es posible que varios nombres de dominios apunten a una misma IP. Por ejemplo www.ibiblio.org
y helios.metalab.unc.edu
hacen referencia a la misma máquina. Puede suceder también que un mismo nombre de dominio apunte a varias direcciones IP, siendo responsabilidad del servidor DNS elegir aleatoriamente la máquina a la que direccionar cada petición. Esta funcionalidad es utilizada principalmente con portales web con mucha carga de peticiones. Por ejemplo www.oreilly.com
, apunta en realidad a dos máquinas, 208.201.239.36
y 208.201.239.37
.
Para que un equipo cliente pueda hacer uso de los nombres de dominio es necesario que tenga acceso a Internet y en concreto a algún servidor de dominios DNS. La mayoría de estos servidores sólo contienen la direcciones de su red local, más las direcciones de otros pocos servidores de dominios de otros sitios, de manera que si no es capaz de responder a una solicitud pasan la petición a otro servidor de dominios.
La clase InetAddress
representa en Java una dirección IP, tanto en formato IPv4 como en IPv6. Posee dos subclases, Inet4Address
y Inet6Address
, una para cada formato. Internamente, un objeto InetAddress
queda representado por el par de datos hostname / IP
.
Para crear un un objeto de esta clase, debemos tener en cuenta que NO tiene constructores públicos, sino que proporciona tres métodos estáticos factoría que retornan un objeto ya inicializado con alguna información:
getByName(hostName)
, que retorna un objetoInetAddress
con la dirección IP correspondiente a dicho nombre de máquina.getAllByName(hostName)
, que retorna unInetAddress[]
con las direcciones IP asociadas a dicho nombre de máquina.getLocalHost()
, que retorna unInetAddress
con la IP de la máquina en la que se está ejecutando.
Todos estos métodos realizan conexiones de red para obtener toda la información que necesitan, por ejemplo consultando a un servidor de DNS si es necesario, lanzando una excepción UnknownHostException
si no se puede encontrar el host indicado.
Dado que estas operaciones puede ser costosas en tiempo, la clase InetAddress
almacena en la caché el resultado de la búsqueda, para no tener que realizarla de nuevo si se crea otro objeto InetAddress
para el mismo host.
Existen otros dos métodos factoría estáticos que no chequean la dirección contra un servidor DNS, sino que simplemente almacenan en el objeto creado los datos que les proporcionamos:
getByAddress(ipAddressByteArray)
, en el que proporcionamos unbyte[]
con la IP.getByAddress(hostName, ipAddressByteArray)
, en la que proporcionamos el nombre de la máquina y unbyte[]
con la IP.
Estos métodos no garantizan que dicha máquina exista o que esté asociada la dicha IP. Lanzan la excepción UnknownHostException
si el byte[]
no tiene la longitud adecuada.
Si tenemos que conectarnos a una máquina que la que no conozcamos su hostname sino tan sólo su IP, podemos usar el método getByName(ipAddressString)
, que recibirá la representación en cadena de caracteres de la IP correspondiente. En este caso no se realizará petición al servidor DNS, sino que el hostname almacenado será la propia representación textual de la IP. Sólo si una vez obtenido el objeto InetAddress
consultamos el hostname directamente mediante el método getHostName()
o indirectamente mediante el método toString()
, se llevará a cabo el chequeo de la IP en el servidor DNS, y de hecho si no se encuentra, simplemente no se modifica el dato en el objeto InetAddress
y ni siquiera se genera la excepción UnknownHostException
.
En el siguiente código vemos un ejemplo de obtención de un objeto InetAddress
mediante la llamada al método factoría :
try {
InetAddress address = InetAddress.getByName("www.informaticasaladillo.es");
System.out.println(address);
}
catch (UnknownHostException e) {
System.out.println("No se puedo encontrar www.informaticasaladillo.es");
}
Una vez construido u obtenido un objeto InetAddress
podremos usar los siguientes métodos informativos:
getHostName()
: Retorna una cadena de caracteres con el hostname y la IP de un objetoInetAddress
. Si el objeto no posee hostname, se retorna la IP en su lugar. Algunas veces el servidor DNS utiliza como hostname un nombre corto, como por ejemplotitan
en vez del nombre completotitan.oit.unc.edu
. Es especialmente útil si hemos creado el objetoInetAddress
aportándole la IP al métodogetByName(ipAddressString)
, ya que nos va a permitir obtener el nombre del host.getAddress()
: Retorna la dirección IP de un objetoInetAddress
en forma debyte[]
, cuyo tamaño depende de si se trata de una IPv4 o IPv6. Debemos tener en cuenta que Java no define ningún tipo primitivounsigned byte
, por lo que este método retorna un array debyte
con signo. El problema es que en este tipo los valores mayores de 127 son tratados como número negativos. Así si queremos trabajar con los bytes retornados por este método, tendremos que convertir elbyte
con signo a un enteroint
mediante la siguiente instrucción:int unsignedByte = signedByte < 0 ? signedByte + 256 : signedByte;
getHostAddress()
: Retorna la dirección IP de un objetoInetAddress
en forma de cadena de caracteres.
Por otra parte, el método equals()
retornará true
si ambos objetos InetAddress
apuntan a la misma dirección IP, independientemente del hostname.
Algunas direcciones IP y algunos patrones de direcciones tienen un significado especial. Por ejemplo, 127.0.0.1
corresponde a la dirección de bucle de retorno (loopback) local y las direcciones en el rango 224.0.0.0
a 239.255.255.255
corresponden a direcciones de multidifusión (multicast). La clase InetAddress
incorpora varios métodos para comprobar si se trata de una dirección especial, como isAnyLocalAddress()
, isLoopbackAddress()
o isMulticastAddress()
.
Debemos tener en cuenta que la conexiones a un host pueden ser bloqueadas por diversos motivos, como firewalls, servidores proxy, routers mal configurados, etc. La clase InetAddress
proporciona el método isReachable(timeout)
para poder comprobar si el host referenciado en un objeto InetAddress
es accesible o no. Este método trata de conectarse al puerto de echo del host para descubrir si es accesible o no. Si recibe respuesta antes del tiempo en milisegundos pasado como parámetro, retornará true. Si se produce un error en la red se generará la excepción IOException
. Desgraciadamente este método no es muy fiable para la comprobación de un host en Internet, debido principalmente a los firewalls. Sin embargo sí que nos puede ser útil para comprobar la accesibilidad de un host dentro de una intranet.
Las clases Inet4Address
y Inet6Address
son subclases de InetAddress
y permiten distinguir entre los dos tipo de direcciones IP. Sin embargo, normalmente no tendremos que preocuparnos de si una IP es IPv4 o IPv6, ya que los métodos que vayan a usarlas no harán distinción entre ellas a la hora de especificarlas, por lo que habitualmente sólo trabajaremos con la clase InetAddress
. La clase Inet6Address
incorpora el método isIPv4CompatibleAddress()
, para comprobar si la IP es básicamente una IPv4 contenida dentro de una IPv6 (es decir, tiene el formato 0:0:0:0:0:0:0:xxxx
).