Python-Behandlung socket.error: [Errno 104] Verbindung durch Peer zurückgesetzt

78

Bei Verwendung von Python 2.7 mit urllib2zum Abrufen von Daten von einer API wird der Fehler angezeigt [Errno 104] Connection reset by peer. Was verursacht den Fehler und wie soll der Fehler behandelt werden, damit das Skript nicht abstürzt?

ticker.py

def urlopen(url):
    response = None
    request = urllib2.Request(url=url)
    try:
        response = urllib2.urlopen(request).read()
    except urllib2.HTTPError as err:
        print "HTTPError: {} ({})".format(url, err.code)
    except urllib2.URLError as err:
        print "URLError: {} ({})".format(url, err.reason)
    except httplib.BadStatusLine as err:
        print "BadStatusLine: {}".format(url)
    return response

def get_rate(from_currency="EUR", to_currency="USD"):
    url = "https://finance.yahoo.com/d/quotes.csv?f=sl1&s=%s%s=X" % (
        from_currency, to_currency)
    data = urlopen(url)
    if "%s%s" % (from_currency, to_currency) in data:
        return float(data.strip().split(",")[1])
    return None


counter = 0
while True:

    counter = counter + 1
    if counter==0 or counter%10:
        rateEurUsd = float(get_rate('EUR', 'USD'))

    # does more stuff here

Zurück verfolgen

Traceback (most recent call last):
  File "/var/www/testApp/python/ticker.py", line 71, in <module>
    rateEurUsd = float(get_rate('EUR', 'USD'))
  File "/var/www/testApp/python/ticker.py", line 29, in get_exchange_rate
    data = urlopen(url)
  File "/var/www/testApp/python/ticker.py", line 16, in urlopen
    response = urllib2.urlopen(request).read()
  File "/usr/lib/python2.7/urllib2.py", line 126, in urlopen
    return _opener.open(url, data, timeout)
  File "/usr/lib/python2.7/urllib2.py", line 406, in open
    response = meth(req, response)
  File "/usr/lib/python2.7/urllib2.py", line 519, in http_response
    'http', request, response, code, msg, hdrs)
  File "/usr/lib/python2.7/urllib2.py", line 438, in error
    result = self._call_chain(*args)
  File "/usr/lib/python2.7/urllib2.py", line 378, in _call_chain
    result = func(*args)
  File "/usr/lib/python2.7/urllib2.py", line 625, in http_error_302
    return self.parent.open(new, timeout=req.timeout)
  File "/usr/lib/python2.7/urllib2.py", line 406, in open
    response = meth(req, response)
  File "/usr/lib/python2.7/urllib2.py", line 519, in http_response
    'http', request, response, code, msg, hdrs)
  File "/usr/lib/python2.7/urllib2.py", line 438, in error
    result = self._call_chain(*args)
  File "/usr/lib/python2.7/urllib2.py", line 378, in _call_chain
    result = func(*args)
  File "/usr/lib/python2.7/urllib2.py", line 625, in http_error_302
    return self.parent.open(new, timeout=req.timeout)
  File "/usr/lib/python2.7/urllib2.py", line 400, in open
    response = self._open(req, data)
  File "/usr/lib/python2.7/urllib2.py", line 418, in _open
    '_open', req)
  File "/usr/lib/python2.7/urllib2.py", line 378, in _call_chain
    result = func(*args)
  File "/usr/lib/python2.7/urllib2.py", line 1207, in http_open
    return self.do_open(httplib.HTTPConnection, req)
  File "/usr/lib/python2.7/urllib2.py", line 1180, in do_open
    r = h.getresponse(buffering=True)
  File "/usr/lib/python2.7/httplib.py", line 1030, in getresponse
    response.begin()
  File "/usr/lib/python2.7/httplib.py", line 407, in begin
    version, status, reason = self._read_status()
  File "/usr/lib/python2.7/httplib.py", line 365, in _read_status
    line = self.fp.readline()
  File "/usr/lib/python2.7/socket.py", line 447, in readline
    data = self._sock.recv(self._rbufsize)
socket.error: [Errno 104] Connection reset by peer
error: Forever detected script exited with code: 1
Athena Weisheit
quelle
Unter Arch Linux funktioniert get_rate gut für mich. Sind Sie sicher, dass Sie nicht gefiltert werden? Können Sie diese URL in einen Browser laden?
Korylprince
@korylprince In einem Browser funktioniert es einwandfrei, und das Skript wird eine Weile einwandfrei ausgeführt, bevor der Fehler auftritt. Wenn ich den Fehler nicht vermeiden kann, wie soll der Fehler behandelt werden, damit er nicht abstürzt und wahrscheinlich den zuletzt abgerufenen Wert verwendet?
Athena Weisheit

Antworten:

132

"Verbindung durch Peer zurückgesetzt" ist das TCP / IP-Äquivalent zum erneuten Zuschlagen des Telefons. Es ist höflicher als nur nicht zu antworten und einen hängen zu lassen. Aber es ist nicht das FIN-ACK, das von der wirklich höflichen TCP / IP-Konversation erwartet wird. ( Aus einer anderen SO-Antwort )

Sie können also nichts dagegen tun, es ist das Problem des Servers.

Sie können jedoch try .. exceptblock verwenden, um diese Ausnahme zu behandeln:

from socket import error as SocketError
import errno

try:
    response = urllib2.urlopen(request).read()
except SocketError as e:
    if e.errno != errno.ECONNRESET:
        raise # Not error we are looking for
    pass # Handle error here.
Bunyk
quelle
4
Stimmt es, dass der Administrator des Servers diese Methode normalerweise verwendet, um die potenziellen Scraping-Anforderungen eines Clients zu blockieren, oder handelt es sich eher um einen unbeabsichtigten Fehler? Jetzt frage ich mich, ob ich absichtlich blockiert bin oder nicht ...
Blaszard
In einigen Fällen kann dies auf einen Fehler in einem anderen Teil des Systems zurückzuführen sein. In meinem Fall gab es auf meiner Serverseite viele CLOSE_WAIT-TCP-Verbindungen, und die Anzahl war größer, als die Serveranwendung bereitstellen konnte (Java erlaubt maximal 50 Verbindungen gleichzeitig). Meine serverseitige Anwendung lehnte also nur neue Verbindungsversuche ab, indem sie die Verbindung zurücksetzte, nachdem ungefähr 50 CLOSE_WAIT-Verbindungen hängen geblieben waren.
u.unver34
kein englischer Muttersprachler. Was bedeutet "das Telefon wieder auf den Haken schlagen". bedeuten?
Pinocchio
1
@Pinocchio Ich bin auch kein Muttersprachler, aber dies existiert auch in meiner Sprache und bezieht sich auf veraltete Telefontechnologie: en.wikipedia.org/wiki/Telephone_hook Bei alten Telefonen wird beim Abheben eines Telefons der Haken automatisch eingeschaltet Verbindung. Wenn Sie das Telefon wieder auflegen, wird die Verbindung getrennt. Im Grunde bedeutet dies in der modernen Sprache "Trennen / Rote Taste drücken, Anruf verlassen".
Bunyk
13

Sie können versuchen time.sleep, Ihrem Code einige Aufrufe hinzuzufügen .

Es scheint, dass die Serverseite die Anzahl der Anforderungen pro Zeiteinheit (Stunde, Tag, Sekunde) als Sicherheitsproblem begrenzt. Sie müssen erraten, wie viele (möglicherweise ein anderes Skript mit einem Zähler verwenden?) Und Ihr Skript anpassen, um diese Grenze nicht zu überschreiten.

Versuchen Sie, diesen Fehler mit try .. exceptden urllib2-Aufrufen abzufangen , um zu verhindern, dass Ihr Code abstürzt .

Felix Martinez
quelle
1

Es gibt eine Möglichkeit, den Fehler direkt in der Except-Klausel mit ConnectionResetError abzufangen, um den richtigen Fehler besser zu isolieren. In diesem Beispiel wird auch das Timeout erfasst.

from urllib.request import urlopen 
from socket import timeout

url = "http://......"
try: 
    string = urlopen(url, timeout=5).read()
except ConnectionResetError:
    print("==> ConnectionResetError")
    pass
except timeout: 
    print("==> Timeout")
    pass
Cyril
quelle