3

因此,我已经能够使用多处理将多个文件一次上传到具有以下两个功能的给定服务器:

import ftplib,multiprocessing,subprocess

def upload(t):
    server=locker.server,user=locker.user,password=locker.password,service=locker.service #These all just return strings representing the various fields I will need.
    ftp=ftplib.FTP(server)
    ftp.login(user=user,passwd=password,acct="")
    ftp.storbinary("STOR "+t.split('/')[-1], open(t,"rb"))
    ftp.close() # Doesn't seem to be necessary, same thing happens whether I close this or not

def ftp_upload(t=files,server=locker.server,user=locker.user,password=locker.password,service=locker.service):
    parsed_targets=parse_it(t)
    ftp=ftplib.FTP(server)
    ftp.login(user=user,passwd=password,acct="")
    remote_files=ftp.nlst(".")
    ftp.close()
    files_already_on_server=[f for f in t if f.split("/")[-1] in remote_files]
    files_to_upload=[f for f in t if not f in files_already_on_server]
    connections_to_make=3 #The maximum connections allowed the the server is 5, and this error will pop up even if I use 1
    pool=multiprocessing.Pool(processes=connections_to_make)
    pool.map(upload,files_to_upload)

我的问题是我(非常经常地)最终会遇到以下错误:

File "/usr/lib/python2.7/multiprocessing/pool.py", line 227, in map
    return self.map_async(func, iterable, chunksize).get()
  File "/usr/lib/python2.7/multiprocessing/pool.py", line 528, in get
    raise self._value
ftplib.error_temp: 421 Too many connections (5) from this IP

注意:还有一个偶尔会出现超时错误,但我正在等待它再次抬起它丑陋的头,到时候我会发布它。

当我使用命令行(即“ftp -inv”、“open SERVER”、“user USERNAME PASSWORD”、“mput *.rar”)时,即使我有(例如)3 个实例,我也没有收到此错误立即运行。

我已经阅读了 ftplib 和 multiprocessing 文档,但我无法弄清楚是什么导致了这些错误。这有点问题,因为我经常备份大量数据和大量文件。

  1. 有什么方法可以避免这些错误,还是有另一种方法可以让 /a 脚本做到这一点?
  2. 有没有办法告诉脚本如果它有这个错误,它应该等待一秒钟,然后恢复它的工作?
  3. 有没有办法让脚本按照它们在列表中的相同顺序上传文件(当然速度差异意味着它们并不总是4个连续文件,但目前顺序似乎基本上是随机的)?
  4. 有人可以解释为什么/如何同时与该服务器建立的连接比脚本要求的多吗?

所以,只是处理异常似乎是有效的(除了偶尔的递归错误......仍然不知道那里到底发生了什么)。

根据#3,我并不是希望它是 100% 的,只是脚本会选择列表中的下一个文件来上传(因此进程速度的差异可能/仍然会导致订单不完全顺序的,比当前系统中的可变性要小,当前系统似乎几乎是无序的)。

4

2 回答 2

4

您可以尝试为每个进程使用一个ftp实例:

def init(*credentials):
    global ftp
    server, user, password, acct = credentials
    ftp = ftplib.FTP(server)
    ftp.login(user=user, passwd=password, acct=acct)

def upload(path):
    with open(path, 'rb') as file:
        try:
            ftp.storbinary("STOR " + os.path.basename(path), file)
        except ftplib.error_temp as error: # handle temporary error
            return path, error
        else:
            return path, None

def main():
    # ...
    pool = multiprocessing.Pool(processes=connections_to_make,
                                initializer=init, initargs=credentials)
    for path, error in pool.imap_unordered(upload, files_to_upload):
        if error is not None:
           print("failed to upload %s" % (path,))
于 2013-02-24T17:01:15.990 回答
1

具体回答(2)有没有办法告诉脚本如果它有这个错误,它应该等待一秒钟,然后恢复它的工作?

是的。

ftplib.error_temp: 421 Too many connections (5) from this IP

这是一个例外。你可以抓住它并处理它。虽然 python 不支持尾调用,所以这是一种可怕的形式,它可以像这样简单:

def upload(t):
    server=locker.server,user=locker.user,password=locker.password,service=locker.service #These all just return strings representing the various fields I will need.
    try:
        ftp=ftplib.FTP(server)
        ftp.login(user=user,passwd=password,acct="")
        ftp.storbinary("STOR "+t.split('/')[-1], open(t,"rb"))
        ftp.close() # Doesn't seem to be necessary, same thing happens whether I close this or not
    except ftplib.error_temp:
        ftp.close()
        sleep(2)
        upload(t)

至于您的问题(3),如果这是您想要的,请串行上传,而不是并行上传。

我期待您发布更新,并回答 (4)。我唯一想到的是通过 ftp 连接到该 IP 的其他进程。

于 2013-02-24T16:18:21.570 回答