Время ожидания urllib2 истекло, но соединение с сокетом не закрывается - PullRequest
0 голосов
/ 26 января 2010

Я создаю программу для захвата URL на Python. Для моих целей я хочу, чтобы время действительно истекло, поэтому я делаю

urllib2.urlopen("http://.../", timeout=2)

Конечно, время истекает правильно, как и должно быть. Однако не нужно закрывать соединение с сервером, поэтому сервер считает, что клиент все еще подключен. Как я могу попросить urllib2 просто закрыть соединение после истечения времени ожидания?

Запуск gc.collect () не работает, и я бы не хотел использовать httplib, если не могу помочь.

Самое близкое, что я могу получить: первая попытка истечет. Сервер сообщает, что соединение закрылось , просто , поскольку время второй попытки истекло. Затем сервер сообщает о том, что соединение закрыто , просто , когда время третьей попытки истекло. До бесконечности.

Большое спасибо.

Ответы [ 2 ]

2 голосов
/ 26 января 2010

У меня есть подозрение, что сокет все еще открыт в кадрах стека. Когда Python вызывает исключение, он сохраняет кадры стека, чтобы отладчики и другие инструменты могли просматривать значения стека и интроспекции.

По историческим причинам, а теперь и для обратной совместимости, информация стека хранится (для каждого потока) в sys (см. Sys.exc_info (), sys.exc_type и другие). Это одна из вещей, которая была удалена в Python 3.0.

Для вас это означает, что стек еще жив и на него ссылаются. Там стек содержит локальные данные для некоторой функции, которая имеет открытый сокет. Вот почему розетка еще не закрыта. Только когда будет удалена трассировка стека, все будет собрано.

Чтобы проверить, так ли это, вставьте что-то вроде

try:
  1/0
except ZeroDivisionError:
  pass

в вашем исключении. Это быстрый способ заменить текущее исключение чем-то другим.

0 голосов
/ 26 января 2010

Это ТАКОЙ хак, но следующий код работает. Если запрос находится в другой функции и он не вызывает исключение, сокет всегда закрыт.

def _fetch(self, url):
    try:
        return urllib2.urlopen(urllib2.Request(url), timeout=5).read()
    except urllib2.URLError, e:
        if isinstance(e.reason, socket.timeout):
            return None
        else:
            raise e

def fetch(self, url):
    x = None
    while x is None:
        x = self._fetch(url)
        print "Timeout"
    return x

У кого-нибудь есть лучший способ?

...