以下に、2秒ごとに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)
これは、DNS名「www.google.com」を解決できないために発生します。インターネット接続がない場合、DNSサーバーに到達してこのエントリを解決できない可能性があります。
初めてあなたの質問を読み間違えたようです。 Linuxでの動作は、glibcの特殊性です。ロード時に「/etc/resolv.conf」を1回だけ読み取ります。 glibcは、res_init()
関数を介して「/etc/resolv.conf」を強制的に再読み取りすることができます。
1つの解決策は、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(ネームサービスキャッシュデーモン)。
私にとって、それはプロキシの問題でした。 urllib.requestをインポートする前に以下を実行すると役に立ちました
import os
os.environ['http_proxy']=''
response = urllib.request.urlopen('http://www.google.com')