如果不通过线程或其他方式使用某种异步计时器,任何库都不可能做到这一点。原因是,timeout
参数使用于httplib
, urllib2
和其他库设置timeout
在底层的socket
。这实际上做了什么解释在文档 http://pubs.opengroup.org/onlinepubs/009695399/functions/setsockopt.html.
SO_RCVTIMEO
设置超时值,该值指定输入函数完成之前等待的最长时间。它接受一个 timeval 结构,其中包含秒数和微秒数,指定等待输入操作完成的时间限制。如果接收操作已阻塞这么长时间不接收额外数据,如果没有收到数据,它应返回部分计数或设置为 [EAGAIN] 或 [EWOULDBLOCK] 的 errno。
加粗部分是关键。 Asocket.timeout
仅当在持续时间内未收到单个字节时才会引发timeout
窗户。换句话说,这是一个timeout
接收到的字节之间。
一个简单的函数使用threading.Timer
可以如下。
import httplib
import socket
import threading
def download(host, path, timeout = 10):
content = None
http = httplib.HTTPConnection(host)
http.request('GET', path)
response = http.getresponse()
timer = threading.Timer(timeout, http.sock.shutdown, [socket.SHUT_RD])
timer.start()
try:
content = response.read()
except httplib.IncompleteRead:
pass
timer.cancel() # cancel on triggered Timer is safe
http.close()
return content
>>> host = 'releases.ubuntu.com'
>>> content = download(host, '/15.04/ubuntu-15.04-desktop-amd64.iso', 1)
>>> print content is None
True
>>> content = download(host, '/15.04/MD5SUMS', 1)
>>> print content is None
False
除了检查之外None
,也可以捕获httplib.IncompleteRead
异常不在函数内部,而是在函数外部。如果 HTTP 请求没有Content-Length
header.