我们有一个服务器程序偶尔挂在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
编辑:挂起我的意思是程序没有崩溃,几个小时后仍然处于活动状态,但是,在打印出一条错误消息之后,它似乎仍然停滞不前。
但是,AFAIK代码处理库句柄之外 例外正确:
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),是否有(明显的)修复,如果我们使用另一个库,...?
另外,实际发生了什么?我知道连接已重置,但接下来会发生什么?
答案 0 :(得分:3)
除非您正在使用非阻塞套接字,否则读取调用将被阻止。因此,您的进程在read()调用中被阻止。
由于某种原因,连接的另一端发送一个设置了RST标志的数据包,关闭连接。当OS检测到此事件时,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标志关闭的套接字是一个你无法避免的事件,你应该处理它。