【发布时间】:2011-12-23 16:13:20
【问题描述】:
概述
我正在使用 Python 2.7.1 urllib2 包中的 urlopen 从 Windows XP 机器到远程 Apache 网络服务器(例如 Mac OS X 的内置网络共享)执行 HTTP POST。发送的数据包含一些标识符、数据和校验和,如果发送了所有数据,则服务器以确认响应。数据中的校验和可用于检查是否一切正常。
问题
通常这很好用,但有时互联网连接不好,通常是因为发送数据的客户端使用 wifi 或 3G 连接。这会导致互联网连接丢失一段任意时间。 urlopen 包含一个超时选项,以确保这不会阻止您的程序并且可以继续。
这就是我想要的,但问题是 urlopen 不会阻止套接字继续发送超时发生时它仍然必须发送的任何数据。我已经通过尝试向我的笔记本电脑发送大量数据来测试这个(使用我将在下面显示的代码),我会在两个显示活动中看到网络活动,然后我会停止笔记本电脑上的无线,等待直到功能超时,然后重新激活无线,然后数据传输将继续,但程序将不再监听响应。我什至尝试退出 Python 解释器,但它仍然会发送数据,因此控制权会以某种方式移交给 Windows。
原因
超时(据我所知)是这样工作的:
它检查“空闲响应时间”
([Python-Dev] Adding socket timeout to urllib2)
如果将超时设置为 3,它将打开连接,启动计数器,然后尝试发送数据并等待响应,如果在收到响应之前的任何时间点计时器耗尽,则会调用超时异常。请注意,就超时计时器而言,数据的发送似乎不算作“活动”。
(urllib2 times out but doesn't close socket connection)
(Close urllib2 connection)
显然,当一个套接字被关闭/取消引用/垃圾收集时,它会调用它的“关闭”函数,该函数等待所有数据在关闭套接字之前发送。但是还有一个关闭功能,它应该立即停止套接字,防止发送更多数据。
(socket.shutdown vs socket.close)
(http://docs.python.org/library/socket.html#socket.socket.close)
我想要什么
我希望在发生超时时“关闭”连接。否则我的客户将无法判断数据是否正确接收,它可能会尝试再次发送。我宁愿直接终止连接并稍后再试,因为知道数据(可能)没有成功发送(如果校验和不匹配,服务器可以识别这一点)。
这是我用来测试的部分代码。 try..except 部分还没有像我预期的那样工作,任何帮助也很感激。正如我之前所说,我希望程序在引发超时(或任何其他)异常后立即关闭套接字。
from urllib import urlencode
from urllib2 import urlopen, HTTPError, URLError
import socket
import sys
class Uploader:
def __init__(self):
self.URL = "http://.../"
self.data = urlencode({'fakerange':range(0,2000000,1)})
print "Data Generated"
def upload(self):
try:
f = urlopen(self.URL, self.data, timeout=10)
returncode = f.read()
except (URLError, HTTPError), msg:
returncode = str(msg)
except socket.error:
returncode = "Socket Timeout!"
else:
returncode = 'Im here'
def main():
upobj = Uploader()
returncode = upobj.upload()
if returncode == '100':
print "Success!"
else:
print "Maybe a Fail"
print returncode
print "The End"
if __name__ == '__main__':
main()
【问题讨论】:
-
一个想法是在客户端创建一个超时管理器,这样说:如果我在 x 秒内没有从服务器返回成功状态,我将关闭现有连接并稍后重试。
-
@Hoff 这就是 urlopen 中的超时应该做的,或者至少这是我所期望的。但是它不会关闭现有的连接,它会继续在后台运行,即使 python 完全退出。我不知道如何(如果可能的话)制作一个单独的程序来查找这些超时连接并关闭它们,你如何引用它们?我认为的主要问题是,当发生超时异常时,您无法再访问 urlopen 的套接字以将其关闭。
标签: python sockets timeout http-post urllib2