9.15. Nombres y DNS¶
Cada página hasta ahora ha usado direcciones IP numéricas – 192.168.1.20 y similares. Las aplicaciones reales casi nunca hacen eso. Los servidores se llaman example.com o api.example.com, y la aplicación busca el nombre en tiempo de ejecución para encontrar una IP a la que enviar paquetes. Esa búsqueda es el Sistema de Nombres de Dominio (Domain Name System), o DNS.
9.15.1. A qué se resuelve un nombre¶
Un nombre no es más que una etiqueta. example.com no contiene en sí ninguna información de IP – hay que buscarlo, igual que se busca un número de teléfono en una guía telefónica. La infraestructura DNS es la guía telefónica distribuida de internet, y el resultado de una búsqueda es una o más direcciones IP a las que la cámara puede conectarse.
example.com -> 93.184.216.34
Un mismo nombre a menudo se resuelve en varias direcciones (para balanceo de carga, redundancia geográfica, versiones IPv4 e IPv6 del mismo servicio). Cualquiera de ellas funciona; la aplicación elige una y la prueba, recurriendo a la siguiente si esa falla.
9.15.2. Cómo se produce la búsqueda¶
Cuando la cámara solicita example.com:
La cámara envía un pequeño datagrama UDP (sí, UDP – véase UDP – envía un paquete y cruza los dedos) a su servidor DNS configurado. La dirección del servidor DNS provino del mismo intercambio DHCP que le entregó a la cámara su propia IP.
Es posible que el servidor DNS ya tenga la respuesta en caché (se le ha preguntado recientemente). Si es así, responde de inmediato.
Si no, el servidor DNS recorre la jerarquía global de DNS: pregunta a los servidores raíz por
.com, pregunta a esos servidores porexample.com, pregunta a esos servidores por el nombre. Todo el recorrido del árbol queda oculto para la cámara; la cámara ve una consulta y una respuesta.El servidor DNS almacena el resultado en caché para la próxima vez y devuelve la respuesta a la cámara como otro datagrama UDP.
Todo el intercambio suele tardar unos pocos milisegundos con la caché caliente, hasta un centenar o así con la caché fría.
9.15.3. La interfaz de Python¶
La función getaddrinfo() realiza la búsqueda y devuelve una dirección lista para pasar a un constructor de socket:
import socket
addr = socket.getaddrinfo("example.com", 80)[0][-1]
print(addr)
# ('93.184.216.34', 80)
La firma es getaddrinfo(host, port). El valor de retorno es una lista de tuplas de 5 elementos (una por dirección resuelta); el [0] elige la primera y el [-1] elige el último campo, que es la tupla (ip, port) que se puede pasar directamente a un socket:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect(socket.getaddrinfo("example.com", 80)[0][-1])
s.send(b"GET / HTTP/1.0\r\nHost: example.com\r\n\r\n")
...
La mayoría del código de cámara que se comunica con un servidor remoto empieza con esa única línea. Los ayudantes de asyncio (asyncio.open_connection()) realizan la búsqueda internamente si se pasa un nombre en lugar de una IP numérica, de modo que el código asíncrono normalmente no llama directamente a getaddrinfo().
9.15.4. Qué puede salir mal¶
Ningún servidor DNS accesible. Si el Wi-Fi acaba de levantarse y el enlace es inestable, la primera llamada a
getaddrinfo()puede agotar el tiempo de espera. Se generaOSError; reintenta una vez que el enlace sea estable.El nombre no existe. Un error tipográfico o un nombre obsoleto generan
OSErrordespués de que el servidor DNS devuelva «no existe tal nombre». El código de error distingue esto de «servidor DNS inaccesible», pero para la mayoría de las aplicaciones de cámara la política de reintentar/rendirse es la misma.La dirección devuelta no funciona. El DNS puede devolver una dirección que ya no aloja el servicio. La solución es recurrir a la siguiente entrada de la lista de resultados de
getaddrinfo(), o volver a buscar el nombre más tarde (la caché de DNS probablemente se habrá actualizado para entonces).Portales cautivos. Algunas redes Wi-Fi interceptan el DNS y devuelven la IP de la página del portal cautivo para todo. La cámara parecerá conectarse, pero los datos que reciba de vuelta no coincidirán con lo que enviaría el servicio real. No es común en entornos desplegados, pero es algo que ocurre en el Wi-Fi de congresos y redes similares.
9.15.5. El propio nombre de la cámara¶
Las páginas hasta ahora han buscado los nombres de otros dispositivos. La cámara también tiene un nombre propio que anuncia a la red local cuando solicita una dirección. El valor predeterminado es un identificador genérico que varía según la placa; network.hostname() lo sobrescribe con algo que el resto de la red reconocerá:
import network
network.hostname("kitchen-cam")
# ... then bring the link up as usual ...
Establece el hostname antes de levantar la interfaz, para que el nombre salga como parte de la solicitud inicial de dirección de la cámara en lugar de después.
Ahora ocurren dos cosas una vez que la cámara se ha unido a la red. Primero, la mayoría de los routers domésticos registran en su propia búsqueda local los hostnames a los que entregan direcciones, de modo que otros dispositivos pueden alcanzar la cámara como kitchen-cam – sin tener que conocer la dirección numérica que el router le haya asignado. (Las redes empresariales pueden o no respetar esto; el comportamiento depende del router.) Segundo, la cámara misma ejecuta de fábrica un respondedor mDNS, de modo que el mismo nombre también es accesible como kitchen-cam.local en cualquier red cuyos clientes entiendan mDNS – lo que hace la mayoría de los sistemas operativos de escritorio modernos.
Nota
Pasa el hostname desnudo a network.hostname() – solo "kitchen-cam", sin el sufijo .local. La forma .local es lo que mDNS añade en el momento de la búsqueda; incorporarla al hostname hace que la cámara anuncie kitchen-cam.local como un hostname normal, lo cual no es lo que ninguno de los dos lados de la búsqueda espera.
9.15.6. Cuando los nombres no bastan¶
Hay algunas situaciones con las que el DNS no ayuda:
Descubrimiento en la red local. El DNS estándar responde preguntas sobre nombres registrados en el directorio global; no sabe nada de los dispositivos del segmento local. Multicast DNS (mDNS) es el sistema que cubre ese hueco. Cada dispositivo participante se une a un grupo de multidifusión especial en la red local y escucha consultas; cuando un dispositivo solicita un nombre que termina en
.local, el dispositivo propietario de ese nombre responde directamente. Sin servidor central, sin configuración de DNS. Bonjour en dispositivos Apple, Avahi en Linux y Windows 10+ hablan todos el mismo protocolo – por eso el nombrekitchen-cam.localque configuró la sección anterior se resuelve en una red doméstica sin nada adicional configurado.El lado de la cámara en ese intercambio es el respondedor, y ya está en marcha. Lo que la cámara no tiene es un resolutor – la otra mitad, que permitiría a un script preguntar a la red «¿dónde está
printer.local?» y obtener una respuesta. El código mDNS incluido es solo respondedor (los dispositivos embebidos son normalmente aquello que se encuentra, no quien hace la búsqueda). Cuando el descubrimiento tiene que fluir en la otra dirección, la difusión UDP (véase UDP – envía un paquete y cruza los dedos) es la respuesta más sencilla para el caso del segmento local, o un módulo en Python puro como cbrand/micropython-mdns añade un resolutor completo.Nombres IPv6.
getaddrinfo()devuelve resultados tanto IPv4 como IPv6 si ambos están disponibles. Elige la familia que pueda usar el socket de la aplicación.
Para la mayoría del código del lado de la cámara, getaddrinfo es una sola línea al principio de cualquier función que abra una conexión de red. Los ejemplos de otras partes de esta sección que se ejecutaron contra "192.168.1.20" funcionarían todos de la misma manera contra un nombre público como "api.example.com" – solo hay que resolverlo primero.