2009-05-01 12 views
8

Próbując uczynić jedną z moich aplikacji Pythona nieco bardziej niezawodną w przypadku przerw w łączeniu odkryłem, że wywołanie funkcji odczytu strumienia http utworzonego przez urllib2 może blokować skrypt na zawsze.czytanie strumienia utworzonego przez urllib2 nigdy się nie odtwarza, gdy połączenie zostało przerwane

Myślałem, że funkcja odczytu będzie działać w określonym czasie i ostatecznie zgłosi wyjątek, ale nie będzie to miało miejsca, gdy połączenie zostanie przerwane podczas wywołania funkcji odczytu.

Oto kod, który spowoduje, że problem:

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" 

(Jeśli wypróbować skrypt prawdopodobnie trzeba przerywać połączenia kilka razy, zanim będzie można dotrzeć do stanu, z którego scenariusz nigdy nie odzyskuje)

Obejrzałem skrypt za pośrednictwem Winpdb i zrobiłem zrzut ekranu stanu, z którego skrypt nigdy się nie wyodrębnia (nawet jeśli sieć była ponownie dostępna).

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

Czy istnieje sposób, aby utworzyć skrypt Pythona, który będzie nadal działać, nawet jeśli niezawodne połączenie sieciowe, ale przerwał? (Wolałbym tego uniknąć w dodatkowym wątku).

+0

+1 dla dobrze pisemne pytanie –

Odpowiedz

6

Spróbuj coś takiego:

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

Wygląda na to, że to rozwiązało mój problem. Dziękuję Ci! – Martin

+0

Działa to, z wyjątkiem tego, że wkracza w proces wieloprocesowy z powodu [Błąd 6056] (http://bugs.python.org/issue6056). Czy istnieje inny sposób na dodanie limitu czasu do urllib2 bez wpływu na domyślny limit czasu gniazd? – UsAaR33

2

Dobre pytanie, byłbym bardzo zainteresowany znalezieniem odpowiedzi. Jedynym sposobem obejścia tego problemu jest użycie sztuczki sygnałowej wyjaśnionej w python docs. W twoim przypadku to będzie więcej takich jak:

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 
+0

To wygląda bardzo obiecująco, ale przyzwyczajenie praca dla mnie, ponieważ ja pracuję na komputerze z systemem Windows. – Martin

+0

ah, rozumiem. Rozwiązanie Alexa wygląda jednak obiecująco. –

Powiązane problemy