python3: socket.gethostbyaddr(): неизвестный хост и ошибка поиска имени хоста

Я использую socket.gethostbyaddr() в python3 для преобразования IP в имя хоста.

Мне нужно различать 3 случая:

1) success (IP resolved to hostname)
2) IP address has no DNS record
3) DNS server is temporarily unavailable

Я использую простую функцию:

def host_lookup(addr):
    try:
        return socket.gethostbyaddr(addr)[0]
    except socket.herror:
        return None

а затем я хочу вызвать эту функцию из моего основного кода:

res = host_lookup('45.82.153.76')

if "case 1":
    print('success')
else if "case 2":
    print('IP address has no DNS record')
else if "case 3":
    DNS server is temporarily unavailable
else:
    print('unknown error')

Когда я пытаюсь socket.gethostbyaddr() в консоли Python, я получаю разные коды ошибок в каждом случае:

>>> socket.gethostbyaddr('45.82.153.76')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
socket.herror: [Errno 1] Unknown host

и когда я намеренно делаю DNS недоступным:

>>> socket.gethostbyaddr('45.82.153.76')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
socket.herror: [Errno 2] Host name lookup failure

Итак, как я могу различать эти случаи в моем коде выше?


person 400 the Cat    schedule 13.11.2019    source источник


Ответы (1)


socket.herror является подклассом OSError, который предоставляет доступ к числовому коду ошибки errno:

import socket

def host_lookup(addr):
    return socket.gethostbyaddr(addr)[0]

try:
    res = host_lookup("45.82.153.76")
    print('Success: {}'.format(res))
except socket.herror as e:
    if e.errno == 1:
        print('IP address has no DNS record')
    elif e.errno == 2:
        print('DNS server is temporarily unavailable')
    else:
        print('Unknown error')
person gparis    schedule 13.11.2019
comment
Используйте import errno и символические коды ошибок вместо числовых. Делает код более легким для чтения и более надежным. - person Patrick Mevzek; 13.11.2019
comment
@ Патрик Мевзек - не могли бы вы показать пример, как использовать символические коды ошибок вместо числовых? - person 400 the Cat; 16.11.2019
comment
import errno; print errno.ENOENT == 2 покажет True. См. docs.python.org/3.7/library/errno.html или аналогичный полный список доступных переменных. - person Patrick Mevzek; 16.11.2019
comment
Однако в этом случае номера ошибок не являются стандартными системными символами errno. но те из h_errno. Наверное, лучше объявить их самостоятельно: HOST_NOT_FOUND = 1; TRY_AGAIN = 2; NO_RECOVERY = 3; NO_DATA = 4; NO_ADDRESS = NO_DATA. - person gparis; 18.11.2019