HOWTO · Python

Python에서 socket.gaierror: [Errno 8] nodename nor servname provided, or not known을 수정하는 방법

호스트 이름, 서비스, 리졸버 및 클라이언트 대상을 확인하여 Python socket.gaierror를 진단한 다음 로컬 클라이언트-서버 연결을 확인합니다。

이 페이지의 내용

socket.gaierror: [Errno 8] nodename nor servname provided, or not known은 소켓 작업에 전달된 이름이나 서비스를 시스템이 확인하지 못했다는 뜻입니다. 먼저 호스트 이름과 포트 또는 서비스 값을 확인한 다음, 서버가 실행되는 위치에 적합한 주소인지 살펴보세요. 오류 문구와 번호는 운영체제와 이름 확인자에 따라 달라질 수 있습니다.

socket.gaierror와 [Errno 8] 이해하기

시스템 이름 확인자를 통한 주소 조회에 실패하면 Python은 socket.gaierror를 발생시킵니다. 호스트 이름의 철자가 틀렸거나, 설정된 이름 확인자가 해당 이름을 찾을 수 없거나, 이름이 비어 있을 수 있습니다. 서비스 값이 없거나 지원되지 않는 경우도 있습니다. 표시되는 [Errno 8] 문구는 플랫폼에 따라 다르므로, 특정 번호에만 의존하지 말고 입력값과 이름 확인자를 진단하세요.

호스트 이름 조회로 오류 재현하기

socket.getaddrinfo()를 사용해 애플리케이션이 클라이언트 연결에 전달하는 것과 동일한 호스트 및 서비스 값을 확인하세요. 다음 예제는 조회에 성공하면 주소 후보의 개수를 출력하고, 실패하면 이름 확인자가 반환한 메시지를 표시합니다. 공개 DNS 이름에 의존하지 않고 실행할 수 있도록 localhost를 사용합니다.

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)")

호스트 이름과 서비스 확인하기

호스트 값에는 호스트 이름이나 IP 주소를, 서비스 값에는 포트 번호나 인식 가능한 서비스 이름을 전달하세요. https://example.com/path 같은 전체 URL은 전달하지 마세요. 스킴과 경로는 소켓 호스트의 일부가 아닙니다. 연결을 호출하기 전에 공백이나 오타가 없는지, 값이 빈 문자열로 바뀌지는 않는지 확인하세요. socket.gethostname()은 로컬 컴퓨터에 설정된 호스트 이름을 반환하지만, 다른 컴퓨터에서 그 이름을 확인할 수 있는지 또는 의도한 서버를 가리키는지는 보장하지 않습니다.

DNS와 네트워크 이름 확인 진단하기

원격 호스트 이름에 대해 socket.getaddrinfo()가 실패하면 운영체제의 일반 네트워크 진단 도구로 같은 이름을 조회해 보고, 컴퓨터에 설정된 이름 확인자도 확인하세요. 알려진 호스트 이름과 비교하는 것은 진단 목적으로만 사용하세요. 한 이름의 조회가 성공해도 모든 이름이 확인된다는 뜻은 아닙니다. DNS 조회와 네트워크 연결 수립은 별개의 단계입니다. 연결 실패만으로 인터넷에 접속할 수 없다고 판단할 수는 없습니다. 이름 확인에 성공한 뒤에도 방화벽, 라우팅 또는 서버 중단으로 연결이 실패할 수 있습니다.

socket.setdefaulttimeout()은 일부 소켓 작업의 기본 제한 시간을 설정합니다. DNS 서버를 선택하는 기능은 없으며, 시스템 이름 확인에 안정적으로 시간 제한을 적용하지도 않습니다. Python 소켓의 기본값을 바꾸는 대신 운영체제나 네트워크 환경에서 DNS를 설정하세요.

클라이언트가 사용할 주소 수정하기

서버와 클라이언트가 같은 컴퓨터에서 실행된다면 서버를 127.0.0.1에 바인딩하고 클라이언트도 같은 주소로 연결하세요. localhost 역시 로컬 루프백 이름입니다. 이 주소로는 다른 컴퓨터에서 실행 중인 서버에 연결할 수 없습니다. 원격 클라이언트에는 서버에 도달할 수 있는 호스트 이름이나 IP 주소가 필요하며, 서버도 해당 클라이언트에서 접근 가능한 인터페이스에서 수신 대기해야 합니다.

다음 완전한 예제는 간단한 로컬 서버를 시작하고 메시지 하나를 보낸 뒤 응답을 출력합니다. 서버의 로컬 바인딩 주소와 클라이언트의 대상 주소를 일치시키는 방법을 보여 줍니다.

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()

연결 확인하기

먼저 socket.getaddrinfo()로 호스트와 서비스가 확인되는지 살펴보세요. 그런 다음 서버가 예상한 인터페이스와 포트에서 수신 대기 중인지 확인하고, 클라이언트에서 도달 가능한 주소로 연결하세요. 로컬 예제에서는 서버가 사용 가능한 포트를 선택하고 클라이언트가 바로 그 포트를 사용하므로 공개 DNS 항목이나 외부 서비스가 필요하지 않습니다. 원격 환경에서는 서버 주소, 수신 대기 인터페이스, 방화벽 규칙, 포트를 각각 확인하세요. 조회가 성공하면 이름 확인이 된 것이고, 연결이 성공하면 해당 시도에서 수신 대기 중인 서버에 도달한 것입니다.