我们有一个服务器程序偶尔会挂起在 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/