HOWTO · Python

Cómo corregir socket.gaierror: [Errno 8] nodename nor servname provided, or not known en Python

Diagnostica el socket.gaierror de Python comprobando el nombre de host, el servicio, el resolver y el destino del cliente, y luego verifica una conexión cliente-servidor local.

En esta página

socket.gaierror: [Errno 8] nodename nor servname provided, or not known significa que el sistema no pudo resolver un nombre o servicio proporcionado a una operación de socket. Comprueba primero el nombre de host y el puerto o servicio; después, confirma que la dirección sea adecuada para el lugar donde se ejecuta el servidor. El texto del error y su número pueden variar según el sistema operativo y el sistema de resolución.

Entender socket.gaierror y [Errno 8]

Python genera socket.gaierror cuando falla una búsqueda de dirección mediante el sistema de resolución. Es posible que el nombre de host esté mal escrito, que el sistema de resolución configurado no pueda encontrarlo o que no exista. También puede faltar el valor del servicio o no ser compatible. El texto mostrado para [Errno 8] depende de la plataforma; por eso, diagnostica los valores de entrada y el sistema de resolución en lugar de confiar en ese número exacto.

Reproducir el error con una búsqueda de nombre de host

Usa socket.getaddrinfo() para comprobar los mismos valores de host y servicio que tu aplicación pasa al conectarse como cliente. Si la búsqueda se realiza correctamente, este ejemplo muestra cuántas direcciones candidatas encontró; si falla, muestra el mensaje del sistema de resolución. Usa localhost, así que puedes probarlo sin depender de un nombre DNS público.

import socket

hostname = "localhost"
service = "http"

try:
    addresses = socket.getaddrinfo(hostname, service, type=socket.SOCK_STREAM)
except socket.gaierror as error:
    print(f"Could not resolve {hostname}:{service}: {error}")
else:
    print(f"Resolved {hostname}:{service} to {len(addresses)} address candidate(s)")

Comprobar el nombre de host y el servicio

Pasa un nombre de host o una dirección IP como valor de host, y un número de puerto o un nombre de servicio reconocido como valor de servicio. No pases una URL completa como https://example.com/path: el esquema y la ruta no forman parte del host de un socket. Comprueba si hay espacios, errores tipográficos o valores que quedan vacíos antes de llamar a la conexión. socket.gethostname() devuelve el nombre de host configurado para la máquina local; no garantiza que otra máquina pueda resolver ese nombre ni que corresponda al servidor al que quieres conectarte.

Diagnosticar DNS y la resolución de red

Si socket.getaddrinfo() falla con un nombre de host remoto, intenta resolver ese mismo nombre con las herramientas de diagnóstico de red habituales del sistema operativo y comprueba qué sistema de resolución está configurado en la máquina. Puedes compararlo con un nombre de host conocido como parte del diagnóstico, pero que uno se resuelva correctamente no demuestra que todos los nombres puedan resolverse. La búsqueda DNS y el establecimiento de una conexión de red son pasos distintos: que falle una conexión no demuestra por sí solo que no haya acceso a Internet. Los cortafuegos, el enrutamiento y un servidor detenido pueden afectar los intentos de conexión incluso después de que se resuelva el nombre.

socket.setdefaulttimeout() establece un tiempo de espera predeterminado para ciertas operaciones de socket. No selecciona un servidor DNS ni impone de forma fiable un tiempo de espera a la resolución de nombres del sistema. Configura DNS desde el sistema operativo o el entorno de red, no cambiando un valor predeterminado de los sockets de Python.

Corregir la dirección que usa el cliente

Si el servidor y el cliente se ejecutan en la misma máquina, vincula el servidor a 127.0.0.1 y conecta el cliente a esa misma dirección. localhost también es un nombre de bucle local. Estas direcciones no permiten acceder a un servidor que se ejecuta en otro equipo; un cliente remoto necesita el nombre de host o la dirección IP del servidor que pueda alcanzar, y el servidor debe escuchar en una interfaz accesible desde ese cliente.

El siguiente ejemplo completo inicia un pequeño servidor local, envía un mensaje y muestra la respuesta. Ilustra cómo hacer coincidir la dirección a la que se vincula el servidor con el destino del cliente.

import socket
import threading

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server:
    server.bind(("127.0.0.1", 0))
    server.listen()
    host, port = server.getsockname()

    def respond():
        with server.accept()[0] as connection:
            message = connection.recv(1024)
            connection.sendall(b"received: " + message)

    worker = threading.Thread(target=respond)
    worker.start()

    with socket.create_connection((host, port)) as client:
        client.sendall(b"ping")
        print(client.recv(1024).decode("ascii"))

    worker.join()

Verificar la conexión

Primero, confirma que socket.getaddrinfo() resuelva el host y el servicio. Después, comprueba que el servidor esté escuchando en la interfaz y el puerto esperados, y conecta usando una dirección accesible desde el cliente. En el ejemplo local, el servidor elige un puerto disponible y el cliente utiliza ese mismo puerto, así que no se necesita una entrada DNS pública ni un servicio externo. En una configuración remota, verifica por separado la dirección del servidor, la interfaz de escucha, las reglas del cortafuegos y el puerto. Una búsqueda correcta confirma que se resolvió el nombre; una conexión correcta confirma que, en ese intento, se pudo alcanzar un proceso que estaba escuchando.