la lecture d'un flux créé par urllib2 ne se rétablit jamais lorsque la connexion a été interrompue
Question
Tout en essayant de rendre une de mes applications python un peu plus robuste en cas d'interruptions de connexion, j'ai découvert que l'appel de la fonction de lecture d'un flux http créé par urllib2 pouvait bloquer le script pour toujours.
Je pensais que la fonction de lecture expirerait et finirait par déclencher une exception, mais cela ne semble pas être le cas lorsque la connexion a été interrompue au cours d'un appel de la fonction de lecture.
Voici le code qui causera le problème:
import urllib2
while True:
try:
stream = urllib2.urlopen('http://www.google.de/images/nav_logo4.png')
while stream.read(): pass
print "Done"
except:
print "Error"
(Si vous essayez le script, vous devrez probablement interrompre la connexion plusieurs fois avant d'atteindre l'état dans lequel le script ne récupérera jamais.)
J'ai regardé le script via Winpdb et créé une capture d'écran de l'état dans lequel le script ne récupère jamais (même si le réseau était à nouveau disponible).
Winpdb http://img10.imageshack.us/img10/6716/urllib2.jpg
Existe-t-il un moyen de créer un script python qui continuera à fonctionner de manière fiable même si la connexion réseau était interrompue? (Je préférerais éviter de faire cela dans un fil supplémentaire.)
La solution
Essayez quelque chose comme:
import socket
socket.setdefaulttimeout(5.0)
...
try:
...
except socket.timeout:
(it timed out, retry)
Autres conseils
Bonne question, je serais vraiment intéressé à trouver une réponse. La seule solution à laquelle je pouvais penser consiste à utiliser l'astuce signal expliquée dans les documents python . . Dans votre cas, cela ressemblera davantage à:
import signal
import urllib2
def read(url):
stream = urllib2.urlopen(url)
return stream.read()
def handler(signum, frame):
raise IOError("The page is taking too long to read")
# Set the signal handler and a 5-second alarm
signal.signal(signal.SIGALRM, handler)
signal.alarm(5)
# This read() may hang indefinitely
try:
output = read('http://www.google.de/images/nav_logo4.png')
except IOError:
# try to read again or print an error
pass
signal.alarm(0) # Disable the alarm