python - 进程在 urllib2 套接字重置时挂起

标签 python python-2.7

我们有一个服务器程序偶尔会挂起在 read 调用上 urllib2 连接重置时的套接字,如下所示:

Traceback (most recent call last):
  File "run.py", line 112, in fetch_stuff
    raw = response.read()
  File "/usr/lib/python2.7/socket.py", line 351, in read
    data = self._sock.recv(rbufsize)
  File "/usr/lib/python2.7/httplib.py", line 573, in read
    s = self.fp.read(amt)
  File "/usr/lib/python2.7/socket.py", line 380, in read
    data = self._sock.recv(left)
error: [Errno 104] Connection reset by peer

编辑:对于挂起,我的意思是程序没有崩溃并且在几个小时后仍然处于事件状态,但是,它似乎在打印了一条错误消息后仍然卡住了。

但是,据我所知,库句柄之外的代码句柄 异常正确:

for i in range(retries):
    try:
        response = urllib2.urlopen(url)
        raw = response.read() # fails here
        ...
    except urllib2.HTTPError as e:
        logging.error("HTTP Error for url=%s (code=%s, message=%s, headers=%s)" % (url, e.code, e.msg, e.hdrs))
    except Exception as e:
        logging.exception(e)
else:
    logging.error(('Connection failed after {} tries').format(retries))
    sys.exit(0)

我不明白为什么这会挂起整个过程 进步。我们现在尝试将 timeout 参数设置为 urlopen, 但我怀疑这能否解决问题。

那么,由于到目前为止我还没有找到有用的链接 (except maybe this answer),是否有一个(明显的)修复方法,我们是否应该使用另一个库,...?

此外,实际发生了什么?我知道连接已重置,但接下来会发生什么?

最佳答案

除非您在非阻塞套接字上工作,否则读取调用是阻塞的。因此,您的进程在调用 read() 时被阻塞。

由于某种原因,连接的另一端发送了一个设置了 RST 标志的数据包,关闭了连接。当操作系统检测到此事件时,recv 系统调用返回 ECONNRESET,定义在 linux/include/errno.h 中,对应于错误代码 104。

Python 使用 errno 模块 (https://docs.python.org/2/library/errno.html#module-errno) 翻译错误代码并引发异常。正如预期的那样,错误代码 104 是 errno.ECONNRESET:

>>> import errno
>>> print errno.ECONNRESET
104

然后您将捕获该异常并调用

logging.exception(e)

打印堆栈跟踪。之后,要么继续循环,要么跟随 else 分支。鉴于您的输出,我不清楚会发生什么。

这很容易重现。非常简单的客户端代码:

import urllib2
import logging

r = urllib2.urlopen("http://localhost:8080")
try:
   print "Reading!" 
   r.read()
except Exception as e:
    logging.exception(e)

在服务器端,直接从命令行:

➜  ~ [1] at 22:50:53 [Wed 12] $ nc -l -p 8080

一旦建立连接,客户端就会阻塞读取调用。一旦检测到某些流量,tcpkill 可用于通过 RST 标志终止连接:

~ [1] at 22:51:19 [Wed 12] $ sudo tcpkill -i lo port 8080

而且,正如预期的那样,客户端的结果是:

➜  ~ [1] at 23:12:37 [Wed 12] $ python m.py
Reading!
ERROR:root:[Errno 104] Connection reset by peer
Traceback (most recent call last):
  File "m.py", line 7, in <module>
    r.read()
  File "/usr/lib/python2.7/socket.py", line 351, in read
    data = self._sock.recv(rbufsize)
  File "/usr/lib/python2.7/httplib.py", line 561, in read
    s = self.fp.read(amt)
  File "/usr/lib/python2.7/httplib.py", line 1302, in read
    return s + self._file.read(amt - len(s))
  File "/usr/lib/python2.7/socket.py", line 380, in read
    data = self._sock.recv(left)
error: [Errno 104] Connection reset by peer

添加超时不会解决太多问题。如果您的连接被重置,而您的进程在读取调用时被阻止(即使有超时),结果将完全相同。我认为您应该首先尝试了解为什么要重置连接。但是,读取已使用 RST 标志关闭的套接字是一个您无法避免且应该处理的事件。

关于python - 进程在 urllib2 套接字重置时挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26893870/

相关文章:

python - odoo 10.0 中的日期添加

python - 将数组范围作为参数传递给函数?

python - 如何在跟踪列标题的同时逐行读取 CSV 文件?

python - 在 Numpy 图像中查找子图像

python - 多个子域的 Django 多 session cookie 域

python - 使用多个数据框创建 pandas 数据框

python - 在 debian 上安装 Igraph 0.7 时出错

python - 如何将列表中的项目设置为特定变量?

python - 深集python字典

python - Gittle - "unexpected keyword argument ' pkey'”