Python 처리 socket.error : [Errno 104] 피어에서 연결 재설정


79

urllib2API에서 데이터를 검색하기 위해 Python 2.7을 사용할 때 오류가 발생 [Errno 104] Connection reset by peer합니다. 오류의 원인은 무엇이며 스크립트가 충돌하지 않도록 오류를 어떻게 처리해야합니까?

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

역 추적

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

아치 리눅스에서는 get_rate가 잘 작동합니다. 필터링되고 있지 않습니까? 브라우저에 해당 URL을로드 할 수 있습니까?
korylprince

@korylprince 브라우저에서 잘 작동하며 스크립트는 오류가 나타나기 시작하기 전에 잠시 동안 잘 실행됩니다. 오류를 피할 수없는 경우 충돌하지 않도록 오류를 어떻게 처리하고 검색된 가장 최근 값을 사용해야합니까?
Athena Wisdom

답변:


133

"피어에 의한 연결 재설정"은 전화를 다시 연결하는 것과 동일한 TCP / IP입니다. 단순히 답장하지 않고 한 사람 만 매달리는 것보다 더 예의 바르다. 그러나 진정으로 정중 한 TCP / IP 변환기가 기대하는 FIN-ACK가 아닙니다. ( 다른 SO 답변에서 )

그래서 당신은 그것에 대해 아무것도 할 수 없습니다. 그것은 서버의 문제입니다.

그러나 try .. except블록을 사용 하여 해당 예외를 처리 할 수 있습니다 .

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.

4
서버 관리자가 일반적으로이 방법을 사용하여 클라이언트의 잠재적 인 스크래핑 요청을 차단하는 것이 사실입니까, 아니면 의도하지 않은 버그 일 가능성이 더 높습니까? 지금은 내가 ... 고의 또는하지 차단하고있어 궁금
Blaszard

경우에 따라 시스템의 다른 부분의 버그로 인해 발생할 수 있습니다. 제 경우에는 서버 측에 CLOSE_WAIT tcp 연결이 많았고 그 수가 서버 응용 프로그램에서 제공 할 수있는 것보다 많았습니다 (자바는 한 번에 최대 50 개의 연결을 허용 함). 따라서 내 서버 측 응용 프로그램은 약 50 CLOSE_WAIT 연결이 중단 된 후 연결을 재설정하여 새 연결 시도를 거부했습니다.
u.unver34

원어민이 아닙니다. "전화를 다시 꽂아"는 무엇입니까? 평균?
피노키오

1
@Pinocchio 나도 원어민이 아니지만 이것은 내 언어로도 존재하며 쓸모없는 전화 기술을 나타냅니다. en.wikipedia.org/wiki/Telephone_hook 오래된 전화의 경우 전화를 들었을 때 후크가 자동으로 켜졌습니다. 연결. 전화를 고리에 다시 넣으면 연결이 끊어졌습니다. 따라서 기본적으로 현대 언어에서는 "연결 해제 / 빨간색 버튼을 누르고 통화에서 나가기"를 의미합니다.
Bunyk

13

time.sleep코드에 몇 가지 호출 을 추가 할 수 있습니다 .

서버 측은 보안 문제로 시간 단위 (시간, 일, 초) 당 요청 수를 제한하는 것 같습니다. 얼마나 많은지 추측하고 (카운터가있는 다른 스크립트를 사용합니까?)이 제한을 초과하지 않도록 스크립트를 조정해야합니다.

코드 충돌을 방지 try .. except하려면 urllib2 호출 주위 에서이 오류를 포착하십시오 .


1

ConnectionResetError를 사용하여 except 절에서 직접 오류를 포착하는 방법이 있습니다. 올바른 오류를 분리하는 것이 좋습니다. 이 예제는 또한 시간 초과를 포착합니다.

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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.