2010-01-26 3 views
0

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

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

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

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

Ближайшее, что я могу получить, это: первая попытка будет тайм-аут. Сервер сообщает, что соединение закрыто только как вторая попытка тайм-аута. Затем сервер сообщает, что соединение закрыто только в качестве третьей попытки тайм-аута. Ad infinitum.

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

ответ

2

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

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

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

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

try: 
    1/0 
except ZeroDivisionError: 
    pass 

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

+0

Хм! Очень интересная мысль. Спасибо, но это не совсем работает; тем не менее, я так и не думал об этом. Я думаю, что для моего проекта все мои рассуждения просто слишком хаки. Было бы лучше, если бы я не полагался на это и вместо этого просто прекратил дублировать соединения на сервере. – Michael

0

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

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 

У любого человека есть лучший способ?