【问题标题】:urllib2 times out but doesn't close socket connectionurllib2 超时但不关闭套接字连接
【发布时间】:2010-01-26 03:18:36
【问题描述】:

我正在制作一个 python URL 抓取程序。出于我的目的,我希望它非常快地超时,所以我正在这样做

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

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

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

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

非常感谢。

【问题讨论】:

    标签: python http sockets timeout urllib2


    【解决方案1】:

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

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

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

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

    try:
      1/0
    except ZeroDivisionError:
      pass
    

    在你的 except 子句中。这是用其他东西替换当前异常的快速方法。

    【讨论】:

    • 嗯!一个非常有趣的想法。谢谢,但是不太好用;不过,我从来没有这样想过。我认为对于我的项目,我的整个推理有点太老套了。我最好不要依赖这个,而是终止服务器上的重复连接。
    【解决方案2】:

    这是一个 hack,但下面的代码有效。如果请求在另一个函数中并且它没有引发异常,那么套接字总是关闭的。

    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
    

    有人有更好的方法吗?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-30
      • 1970-01-01
      • 1970-01-01
      • 2013-05-16
      • 2011-05-11
      • 1970-01-01
      相关资源
      最近更新 更多