没有更多信息,我实际上无法调试您的问题,因此我只能提出最一般的答案。这可能对您来说不是必需的,但对任何人来说都足够了。
retrbinary
将阻塞直到整个文件完成。如果超过5分钟,则整个5分钟内都不会在控制通道上发送任何消息。您的客户端正在超时控制通道,或者服务器正在超时。因此,当您尝试与挂断时ftp.quit()
,它将永远挂起或引发异常。
您可以使用构造timeout
函数上的参数来控制一方的超时FTP
。某些服务器支持IDLE
命令,以允许您设置服务器端超时。但是,即使事实证明适当的超时也是可行的,您如何首先选择适当的超时时间呢?
您真正想做的是防止数据套接字上发生传输时控制套接字超时。但是如何?例如,如果您ftp.voidcmd('NOOP')
经常在回调函数中使用它,就足以保持连接正常运行……但是这也将迫使您阻塞直到服务器响应NOOP
,许多服务器在数据传输之前不会这样做已经完成,这意味着您将永远永久阻塞(或直到另一个超时),而不会获取数据。
处理两个套接字而一个不阻塞另一个套接字的标准技术是类似select.select
或的多路复用器。您可以在此处执行此操作,但是您将不得不放弃使用简单的retrbinary
接口,而是使用transfercmd
显式获取数据套接字。
例如:
def downloadFile(…):
ftp = FTP(…)
sock = ftp.transfercmd('RETR ' + filename)
def background():
f = open(…)
while True:
block = sock.recv(1024*1024)
if not block:
break
f.write(block)
sock.close()
t = threading.Thread(target=background)
t.start()
while t.is_alive():
t.join(60)
ftp.voidcmd('NOOP')
另一种解决方案是一次读取20MB,然后调用ftp.abort()
,并使用rest
参数恢复每个新retrbinary
文件的传输,直到到达文件末尾。但是,这样ABOR
可能会永远挂起NOOP
,因此并不能保证任何事情,更不用说服务器不必对此做出响应了。
您 可以 做的就是关闭整个连接(不是quit
,而是close
)。这对服务器来说不是很好,并且可能导致重新发送一些浪费的数据,并且如果过快地杀死套接字,还可能阻止TCP正常加速到全速运行。但它应该工作。