Paramiko无法下载大于1GB的大文件

2024-05-14 11:20:49 发布

您现在位置:Python中文网/ 问答频道 /正文

def download():
if os.path.exists( dst_dir_path ) == False:
    logger.error( "Cannot access destination folder %s. Please check path and permissions. " % ( dst_dir_path ))
    return 1
elif os.path.isdir( dst_dir_path ) == False:
    logger.error( "%s is not a folder. Please check path. " % ( dst_dir_path ))
    return 1

file_list = None
#transport = paramiko.Transport(( hostname, port)) 
paramiko.util.log_to_file('paramiko.log')
ssh = paramiko.SSHClient() 
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 
#transport
try:
    ssh.connect( hostname, username=username, password=password, timeout=5.0) 
    #transport.connect(username=username, password=password ) 
except Exception, err:
    logger.error( "Failed to connect to the remote server. Reason: %s" % ( str(err) ) )
    return 1

try:
    #sftp = paramiko.SFTPClient.from_transport(transport)
    sftp = ssh.open_sftp() 
except Exception, err:
    logger.error( "Failed to start SFTP session from connection to %s. Check that SFTP service is running and available. Reason: %s" % ( hostname, str(err) ))
    return 1

try:    
    sftp.chdir(src_dir_path)
    #file_list = sftp.listdir(path="%s" % ( src_dir_path ) )
    file_list = sftp.listdir()

except Exception, err:
    logger.error( "Failed to list files in folder %s. Please check path and permissions. Reason: %s" % ( src_dir_path, str(err) ))
    return 1
match_text = re.compile( file_mask )
download_count = 0
for file in file_list:         
    # Here is an item name... but is it a file or directory?         
    #logger.info( "Downloading file %s." % ( file ) )
    if not re.match( file_mask, file ):
        continue
    else:
        logger.info( "File \"%s\" name matched file mask \"%s\". matches %s.Processing file..." % ( file, file_mask, (match_text.match( file_mask ) ) ) )
    src_file_path = "./%s" % ( file )
    dst_file_path = "/".join( [ dst_dir_path, file]   )
    retry_count = 0
    while True:
        try:
            logger.info( "Downloading file %s to %s."  % ( file, dst_file_path ) )
            #sftp.get( file, dst_file_path, callback=printTotals ) #sftp.get( remote file, local file )
            sftp.get( file, dst_file_path) #sftp.get( remote file, local file )
            logger.info( "Successfully downloaded file %s to %s."  % ( file, dst_file_path ) )
            download_count += 1
            break
        except Exception, err:
            if retry_count == retry_threshold:
                logger.error( "Failed to download %s to %s. Reason: %s." % ( file, dst_file_path, str(err) ) )
                sftp.close() 
                #transport.close()
                return 1
            else:
                logger.error( "Failed to download %s to %s. Reason: %s." % ( file, dst_file_path, str(err) ) )
                retry_count +=1

sftp.close() 
transport.close() 
logger.info( "%d files downloaded." % ( download_count ) )
return 0

当我运行下面的函数时,它会下载源文件约3分钟,然后关闭会话,即使下载的1-1.6GB文件只有38-41MB(不同)。

从Paramiko日志文件来看,SSh连接在SFTP会话关闭时保持打开状态:

DEB [20120913-10:05:00.894] thr=1 paramiko.transport: Switch to new keys ... DEB [20120913-10:05:06.953] thr=1 paramiko.transport: Rekeying (hit 401 packets, 1053444 bytes received) DEB [20120913-10:05:07.391] thr=1 paramiko.transport: kex algos:['diffie-hellman-group1-sha1', 'diffie-hellman-group-exchange-sha1'] server key:['ssh-dss'] client encrypt:['aes256-ctr', 'aes192-ctr', 'aes128-ctr', 'aes256-cbc', 'aes192-cbc', 'aes128-cbc', 'twofish-cbc', 'blowfish-cbc', '3des-cbc', 'arcfour'] server encrypt:['aes256-ctr', 'aes192-ctr', 'aes128-ctr', 'aes256-cbc', 'aes192-cbc', 'aes128-cbc', 'twofish-cbc', 'blowfish-cbc', '3des-cbc', 'arcfour'] client mac:['hmac-sha1', 'hmac-sha1-96', 'hmac-md5', 'hmac-md5-96', 'umac-64@openssh.com'] server mac:['hmac-sha1', 'hmac-sha1-96', 'hmac-md5', 'hmac-md5-96', 'umac-64@openssh.com'] client compress:['zlib@openssh.com', 'zlib', 'none'] server compress:['zlib@openssh.com', 'zlib', 'none'] client lang:[''] server lang:[''] kex follows?False DEB [20120913-10:05:07.421] thr=1 paramiko.transport: Ciphers agreed: local=aes128-ctr, remote=aes128-ctr DEB [20120913-10:05:07.421] thr=1 paramiko.transport: using kex diffie-hellman-group1-sha1; server key type ssh-dss; cipher: local aes128-ctr, remote aes128-ctr; mac: local hmac-sha1, remote hmac-sha1; compression: local none, remote none DEB [20120913-10:05:07.625] thr=1 paramiko.transport: Switch to new keys ... INF [20120913-10:05:10.374] thr=2 paramiko.transport.sftp: [chan 1] sftp session closed. DEB [20120913-10:05:10.388] thr=2 paramiko.transport: [chan 1] EOF sent (1)

在这一点之后,脚本将退出并出现此异常(来自sftp.get()try/except块)

There are insufficient resources to complete the request

系统本身有千兆字节的可用磁盘空间,所以这不是问题所在。

parakmiko失败的相同传输在FileZilla和Java应用程序上也很好,这些都是我几年前为进行SFTP传输而编写的。所以我认为这是帕拉米科的问题。

这是在WindowsXP和WindowsServer2003上运行的。

我试过修补Paramko 1.17,以便它更频繁地刷新密钥,但是传输仍然抛出了一个例外。 Python2.7.3 帕拉米科1.7带补丁 Windows 2003服务器

有什么想法?

其他信息: 它在WindowsXPSP3和Windows2003服务器上失败,行为和错误消息完全相同。 系统版本信息 Windows XP工作站:“2.7.3(默认值,2012年4月10日,23:31:26)[MSC v.1500 32位(Intel)] Windows 2003服务器:“2.7.3(默认值,2012年4月10日,23:31:26)[MSC v.1500 32位(Intel)] 我修补了packet.py文件以缩短密钥续订之间的时间。它对sftp.get()的行为没有影响。


Tags: topathparamikodirloggerhmacsha1file
3条回答

我有一个非常类似的问题,在我的情况下,这个文件只有大约400MB,但在下载大约35MB之后,它会一直失败。下载的字节数并不总是完全相同,但在大约35-40 MB的某个地方,文件将停止传输,大约一分钟后,我会得到“没有足够的资源来完成请求”错误。

通过WinSCP或PSFTP下载文件运行良好。

我试过螺旋胶带的方法,但很慢。我的400 MB文件的下载速度大约需要4个小时,这对于这个特定的应用程序来说是一个不可接受的时间段。

而且,有一次,当我们第一次建立这个系统时,一切都很好。但服务器管理员对SFTP服务器做了一些更改,这时出现了问题。我不确定更改是什么,但是由于使用WinSCP/other SFTP方法仍然可以正常工作,所以我认为尝试从服务器端攻击它不会有什么效果。

我不会假装明白为什么,但以下是对我有用的:

  1. 我下载并安装了当前版本的Paramiko(此时为1.11.1)。最初这一点都没有影响,但我想我会提到它,以防它是解决方案的一部分。

  2. 异常的堆栈跟踪为:

    File "C:\Python26\lib\site-packages\paramiko\sftp_client.py", line 676, in get
        size = self.getfo(remotepath, fl, callback)
    File "C:\Python26\lib\site-packages\paramiko\sftp_client.py", line 645, in getfo
        data = fr.read(32768)
    File "C:\Python26\lib\site-packages\paramiko\file.py", line 153, in read
        new_data = self._read(read_size)
    File "C:\Python26\lib\site-packages\paramiko\sftp_file.py", line 157, in _read
        data = self._read_prefetch(size)
    File "C:\Python26\lib\site-packages\paramiko\sftp_file.py", line 138, in _read_prefetch
        self._check_exception()
    File "C:\Python26\lib\site-packages\paramiko\sftp_file.py", line 483, in _check_exception
        raise x
    
  3. 在sftp_file.py中翻了翻,我注意到了这一点(当前版本的第43-45行):

    # Some sftp servers will choke if you send read/write requests larger than
    # this size.
    MAX_REQUEST_SIZE = 32768
    
  4. 一时兴起,我试着将MAX_REQUEST_的大小改为1024,瞧,我可以下载整个文件了!

  5. 在我通过将MAX_REQUEST_SIZE更改为1024来工作之后,我尝试了一系列介于1024和32768之间的其他值,以查看它是否影响性能或其他方面。但是,当值明显大于1024(1025还可以,但1048最终失败)时,我迟早会得到错误。

除了Screwtape的答案之外,还值得一提的是,您应该使用.read([block size in bytes])来限制块的大小

lazy method for reading big file

我对2.4中没有块大小的file.read()有真正的问题,但是2.7有可能确定正确的块大小。

SFTP协议没有流式传输文件数据的方法;相反,它有一种从打开的文件中的特定偏移量请求数据块的方法。下载文件的简单方法是请求第一个块,将其写入磁盘,然后请求第二个块,依此类推。这是可靠的,但非常缓慢。

相反,Paramiko使用了一个性能技巧:当您调用.get()时,它会立即向文件中的每个块发送一个请求,并记住它们应该写入的偏移量。然后,当每个响应到达时,它确保将其写入磁盘上的正确偏移量。有关更多信息,请参见Paramiko文档中的SFTPFile.prefetch()SFTPFile.readv()方法。我怀疑它在下载1GB文件时存储的簿记信息可能会导致。。。资源不足,生成“资源不足”消息。

如果您只是调用.open()来获取SFTPFile实例,则不使用.get(),而是调用该对象上的.read(),或者将其交给Python标准库函数shutil.copyfileobj()来下载内容。这将避免Paramiko预取缓存,并允许您下载文件,即使它不是很快。

即:

 def lazy_loading_ftp_file(sftp_host_conn, filename):
    """
        Lazy loading ftp file when exception simple sftp.get call
        :param sftp_host_conn: sftp host
        :param filename: filename to be downloaded
        :return: None, file will be downloaded current directory
    """
    import shutil
    try:
        with sftp_host_conn() as host:
            sftp_file_instance = host.open(filename, 'r')
            with open(filename, 'wb') as out_file:
                shutil.copyfileobj(sftp_file_instance, out_file)
            return {"status": "sucess", "msg": "sucessfully downloaded file: {}".format(filename)}
    except Exception as ex:
        return {"status": "failed", "msg": "Exception in Lazy reading too: {}".format(ex)}

相关问题 更多 >

    热门问题