在超时后恢复FTP下载
我正在从一个不太稳定的FTP服务器下载文件,这个服务器在传输文件时经常会超时。我想知道有没有办法重新连接并继续下载。我正在使用Python的ftplib库。以下是我使用的代码:
#! /usr/bin/python
import ftplib
import os
import socket
import sys
#--------------------------------#
# Define parameters for ftp site #
#--------------------------------#
site = 'a.really.unstable.server'
user = 'anonymous'
password = 'someperson@somewhere.edu'
root_ftp_dir = '/directory1/'
root_local_dir = '/directory2/'
#---------------------------------------------------------------
# Tuple of order numbers to download. Each web request generates
# an order numbers
#---------------------------------------------------------------
order_num = ('1','2','3','4')
#----------------------------------------------------------------#
# Loop through each order. Connect to server on each loop. There #
# might be a time out for the connection therefore reconnect for #
# every new ordernumber #
#----------------------------------------------------------------#
# First change local directory
os.chdir(root_local_dir)
# Begin loop through
for order in order_num:
print 'Begin Proccessing order number %s' %order
# Connect to FTP site
try:
ftp = ftplib.FTP( host=site, timeout=1200 )
except (socket.error, socket.gaierror), e:
print 'ERROR: Unable to reach "%s"' %site
sys.exit()
# Login
try:
ftp.login(user,password)
except ftplib.error_perm:
print 'ERROR: Unable to login'
ftp.quit()
sys.exit()
# Change remote directory to location of order
try:
ftp.cwd(root_ftp_dir+order)
except ftplib.error_perm:
print 'Unable to CD to "%s"' %(root_ftp_dir+order)
sys.exit()
# Get a list of files
try:
filelist = ftp.nlst()
except ftplib.error_perm:
print 'Unable to get file list from "%s"' %order
sys.exit()
#---------------------------------#
# Loop through files and download #
#---------------------------------#
for each_file in filelist:
file_local = open(each_file,'wb')
try:
ftp.retrbinary('RETR %s' %each_file, file_local.write)
file_local.close()
except ftplib.error_perm:
print 'ERROR: cannot read file "%s"' %each_file
os.unlink(each_file)
ftp.quit()
print 'Finished Proccessing order number %s' %order
sys.exit()
我遇到的错误是:
socket.error: [Errno 110] 连接超时
非常感谢任何帮助。
3 个回答
要做到这一点,你需要先保存中断的下载,然后找出文件中缺少的部分,下载这些缺失的部分,最后把它们连接起来。我不太确定具体怎么操作,但有一个叫DownThemAll的下载管理器可以在Firefox和Chrome上使用,它就是这么做的。虽然它的代码不是用Python写的(我想是JavaScript),但你可以看看它的代码,了解它是怎么实现的。
DownThemAll - http://www.downthemall.net/
下面是一个使用Python的ftplib库实现可恢复FTP下载的简单示例:
def connect():
ftp = None
with open('bigfile', 'wb') as f:
while (not finished):
if ftp is None:
print("Connecting...")
FTP(host, user, passwd)
try:
rest = f.tell()
if rest == 0:
rest = None
print("Starting new transfer...")
else:
print(f"Resuming transfer from {rest}...")
ftp.retrbinary('RETR bigfile', f.write, rest=rest)
print("Done")
finished = True
except Exception as e:
ftp = None
sec = 5
print(f"Transfer failed: {e}, will retry in {sec} seconds...")
time.sleep(sec)
建议进行更细致的异常处理。
上传的情况也是类似的:
处理Python ftplib FTP传输中的断开连接问题
通过FTP恢复下载,只用标准功能(可以参考RFC959)需要使用块传输模式(第3.4.2节),这个模式可以通过MODE B
命令来设置。虽然这个功能在技术上是符合规范的,但我不确定所有的FTP服务器软件都实现了这个功能。
在块传输模式下,和流传输模式不同,服务器会把文件分成一块一块发送,每一块都有一个标记。这个标记可以重新提交给服务器,以便重新开始一个失败的传输(第3.5节)。
规范中提到:
[...] 提供了一种重启程序,以保护用户免受严重系统故障的影响(包括主机、FTP进程或底层网络的故障)。
不过,据我所知,规范并没有定义标记的有效期限。它只说了以下内容:
标记信息对发送者有意义,但必须由控制连接的默认或协商语言中的可打印字符组成(ASCII或EBCDIC)。标记可以表示位数、记录数或任何其他信息,以便系统能够识别数据检查点。如果接收数据的系统实现了重启程序,它会在接收系统中标记这个标记对应的位置,并将这个信息返回给用户。
可以安全地假设,支持这个功能的服务器会提供在FTP会话之间有效的标记,但具体情况可能会有所不同。