urrlib2.urlopen: "Имя или услуга не известна" сохраняется при запуске скрипта без подключения к Интернету

У меня есть этот простой минимальный "рабочий" пример ниже, который открывает соединение с Google каждые две секунды. Когда я запускаю этот скрипт, когда у меня работает интернет-соединение, я получаю сообщение "Успешное", и когда я отключусь, я получаю сообщение "Сбой", и когда я снова подключись, снова получаю "Успех". Все идет нормально.

Однако, когда я запускаю сценарий, когда интернет отключен, я получаю сообщения о сбое, а когда я подключаюсь позже, я никогда не получаю сообщение "Успех". Я продолжаю получать ошибку:

ошибка urlopen [Errno -2] Имя или услуга неизвестны

Что происходит?

import urllib2, time

while True:
    try:
        print('Trying')
        response = urllib2.urlopen('http://www.google.com')
        print('Success')
        time.sleep(2)
    except Exception, e:
        print('Fail ' + str(e))
        time.sleep(2)

Ответ 1

Это происходит потому, что DNS-имя "www.google.com" не может быть разрешено. Если подключение к Интернету отсутствует, DNS-сервер, вероятно, недоступен для разрешения этой записи.

Кажется, я впервые понял ваш вопрос. Поведение, которое вы описываете, - это Linux, особенность glibc. Он только читает "/etc/resolv.conf" один раз, при загрузке. glibc может быть принудительно перечитать "/etc/resolv.conf" с помощью функции res_init().

Одним из решений было бы обернуть res_init() и вызвать ее перед вызовом getaddrinfo() (который косвенно используется urllib2.urlopen().

Вы можете попробовать следующее (по-прежнему предполагая, что вы используете Linux):

import ctypes
libc = ctypes.cdll.LoadLibrary('libc.so.6')
res_init = libc.__res_init
# ...
res_init()
response = urllib2.urlopen('http://www.google.com')

Разумеется, это можно оптимизировать, ожидая, пока "/etc/resolv.conf" не будет изменен до вызова функции res_init().

Другим решением было бы установить, например, nscd (daemon cache службы имен).