La lectura de un flujo hecho por urllib2 nunca se recupera cuando se interrumpe la conexión

Al intentar hacer que una de mis aplicaciones de Python sea un poco más robusta en caso de interrupciones de la conexión, descubrí que llamar a la función de lectura de un flujo http hecho por urllib2 puede bloquear el script para siempre.

Pensé que la función de lectura agotará el tiempo y eventualmente generará una excepción, pero esto no es así cuando la conexión se interrumpió durante una llamada a la función de lectura.

Aquí está el código que causará el problema:

import urllib2 while True: try: stream = urllib2.urlopen('http://sofes.miximages.com/python/nav_logo4.png') while stream.read(): pass print "Done" except: print "Error" 

(Si prueba la secuencia de comandos, probablemente deba interrumpir la conexión varias veces antes de alcanzar el estado desde el cual la secuencia de comandos nunca se recupera)

Vi el guión a través de Winpdb e hice una captura de pantalla del estado desde el cual el guión nunca se recupera (incluso si la red está disponible nuevamente).

Winpdb http://img10.imageshack.us/img10/6716/urllib2.jpg

¿Hay alguna forma de crear un script de Python que continúe funcionando de manera confiable incluso si se interrumpe la conexión de la red? (Preferiría evitar hacer esto dentro de un hilo adicional).

Intenta algo como:

 import socket socket.setdefaulttimeout(5.0) ... try: ... except socket.timeout: (it timed out, retry) 

Buena pregunta, estaría realmente interesado en encontrar una respuesta. La única solución que se me ocurre es usar el truco de señal que se explica en los documentos de Python . En tu caso será más como:

 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://sofes.miximages.com/python/nav_logo4.png') except IOError: # try to read again or print an error pass signal.alarm(0) # Disable the alarm