urllib2超时但没有关闭套接字连接

时间:2010-01-26 03:18:36

标签: python http sockets timeout urllib2

我正在制作一个python URL抓取程序。为了我的目的,我希望它真的很快超时,所以我正在做

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

当然它应该正确地超时。但是,它并不打算关闭与服务器的连接,因此服务器认为客户端仍然连接。如何让urllib2在超时后关闭连接?

运行gc.collect()不起作用,如果我无法帮助它,我不想使用httplib。

我能得到的最接近的是:第一次尝试会超时。服务器报告连接关闭只是,因为第二次尝试超时。然后,服务器报告连接关闭只是,因为第三次尝试超时。无限无限。

非常感谢。

2 个答案:

答案 0 :(得分:2)

我怀疑套接字在堆栈帧中是否仍处于打开状态。当Python引发异常时,它会存储堆栈帧,因此调试器和其他工具可以查看堆栈和内省值。

由于历史原因,现在为了向后兼容性,堆栈信息(在每个线程的基础上)存储在sys中(请参阅sys.exc_info(),sys.exc_type和其他)。这是Python 3.0中已删除的内容之一。

这对你来说意味着堆栈仍然存在并被引用。堆栈包含一些具有打开套接字的函数的本地数据。这就是套接字尚未关闭的原因。只有当移除堆栈跟踪时,才会对所有内容进行gc'ed。

要测试是否是这种情况,请插入类似

的内容
try:
  1/0
except ZeroDivisionError:
  pass
你的except子句中的

。这是用其他东西替换当前异常的快速方法。

答案 1 :(得分:0)

这是一个黑客,但以下代码有效。如果请求在另一个函数中并且它没有引发异常,则套接字始终关闭。

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

任何人都有更好的方法吗?