我相信你可以通过在操作系统级别调整您的TCP设置摆脱挂状态,但假设您的应用程序不会在专用(并由您维护)机器上工作,您应该寻求更通用的解决方案。
你问:
是否有可能只在没有数据发送超时通过插座/收到了一定的时间也许
而这正是行为socket.settimeout
(或传递给urllib2
的那个)会给你。与基于SIGALRM的超时(即使在数据传输缓慢时会终止)相反,只有在定义的时间段内没有数据传输时,传递到套接字的超时才会发生。如果socket.send
或socket.recv
的呼叫应该返回部分计数,如果在此期间某些(但不是全部)数据已传输,并且urllib2
然后将使用后续呼叫来传输剩余数据。
说了这样的话,如果POST调用将在多个send
调用中执行,并且任何(但不是第一个)调用都会在不发送任何数据的情况下阻塞并超时,那么您的POST调用仍可能在上传中途的某个地方终止。您给人的印象是它不会被您的应用程序正确处理,但我认为它应该,因为它类似于强制终止该流程或者简单地将连接断开。
您是否测试过并确认socket.settimeout
不能解决您的问题?或者你只是不确定行为是如何实施的?如果前者是正确的,请你提供更多的细节?我相当肯定你只需设置超时时间是安全的,因为python只是使用低级BSD套接字实现,其行为如上所述。为了给您更多的参考,请看setsockopt
手册页和SO_RCVTIMEO
或SO_SNDTIMEO
选项。我期望socket.settimeout
恰好使用这些功能和选项。
---编辑---(提供一些测试代码)
所以我能够得到Requests
模块和测试与urllib2
沿着行为。我已经运行了服务器,它在每个recv
调用之间增加间隔接收数据块。如预期的那样,当间隔达到指定的超时时间时,客户端超时。例如:
服务器
import socket
import time
listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
listener.bind(("localhost", 12346))
listener.listen(1)
sock,_ = listener.accept()
interval = 0.5
while 1:
interval += 1 # increase interval by 1 second
time.sleep(interval)
# Get 1MB but will be really limited by the buffer
data = sock.recv(1000000)
print interval, len(data)
if not data:
break
客户(请求模块)
import requests
data = "x"*100000000 # 100MB beefy chunk
requests.post("http://localhost:12346", data=data, timeout=4)
客户(urllib2的模块)
import urllib2
data = "x"*100000000 # 100MB beefy chunk
urllib2.urlopen("http://localhost:12346", data=data, timeout=4)
输出(服务器)
> 1.5 522832
> 2.5 645816
> 3.5 646180
> 4.5 637832 <--- Here the client dies (4.5 seconds without data transfer)
> 5.5 294444
> 6.5 0
两个客户提出的异常:按预期工作
# urllib2
URLError: timeout('timed out',)
# Requests
Timeout: TimeoutError("HTTPConnectionPool(host='localhost', port=12346): Request timed out. (timeout=4)",)
一切!如果不通过超时作为参数,urllib2
也反应良好socket.setdefaulttimeout
,但Requests
没有。这并不令人惊讶,因为内部实现根本不需要使用默认值,并且可以根据传递的参数或使用非阻塞套接字简单地覆盖它。
我一直在使用运行此如下:
OSX 10.8.3
Python 2.7.2
Requests 1.1.0
首先 - *为什么*它永远阻挡? – 2013-03-18 16:58:46
@CodePainters我不知道 - 理想情况下,我会解决实际问题,我会继续尝试,但它可能是一个服务器端问题(我不控制),直到我找到原因, d喜欢设置一些作为后备的东西,以便上传永远不会冻结,并在此期间作为修补程序发布。 – GP89 2013-03-18 17:02:38