在python FTP脚本中构建错误检查函数

在python FTP脚本中构建错误检查函数,python,ftp,pyftpdlib,Python,Ftp,Pyftpdlib,我正在编写一个脚本,该脚本将“服务器”计算机中的多台“客户端”计算机连接起来,然后使用这些客户端处理多个文件,使用FTP(pyftplib和pyftpdlib)传输文件和结果 该脚本通过在服务器上创建3个文件夹来工作:文件、处理和结果。然后,客户端通过FTP连接到服务器,访问“文件”文件夹,获取要处理的文件,然后在处理时将其传输到“处理”文件夹。然后,当完成处理后,客户端从处理文件夹中删除该文件,并将结果复制到“results”文件夹 这在服务器端和客户端都正常工作。我遇到的问题是,如果其中一个

我正在编写一个脚本,该脚本将“服务器”计算机中的多台“客户端”计算机连接起来,然后使用这些客户端处理多个文件,使用FTP(pyftplib和pyftpdlib)传输文件和结果

该脚本通过在服务器上创建3个文件夹来工作:文件、处理和结果。然后,客户端通过FTP连接到服务器,访问“文件”文件夹,获取要处理的文件,然后在处理时将其传输到“处理”文件夹。然后,当完成处理后,客户端从处理文件夹中删除该文件,并将结果复制到“results”文件夹

这在服务器端和客户端都正常工作。我遇到的问题是,如果其中一个客户端中途断开连接而不产生错误(PC断开连接,断电),服务器将对此发出威胁,就好像客户端仍在处理文件一样,文件将保留在“处理”文件夹中。我想要的是一个错误检查功能,当这种情况发生时,“处理”文件夹中的文件将返回到“文件”文件夹

这是服务器FTP代码

def main():
    authorizer = DummyAuthorizer()
    authorizer.add_user('client', 'password', '.', perm='elradfmwM')
    authorizer.add_anonymous(os.getcwd())

    handler = FTPHandler
    handler.authorizer = authorizer
    handler.banner = "FTP Server."
    address = ('', port)
    server = FTPServer(address, handler)
    server.max_cons = 256
    server.max_cons_per_ip = 50
    server.serve_forever()


if __name__ == '__main__':
    main()
以下是客户端FTP代码:

while True:
    ftp = ftplib.FTP()
    ftp.connect(arguments.host_ip, arguments.host_port)
    ftp.login("client", "password")
    print ftp.getwelcome()
    ftp.retrlines('LIST')
    ftp.retrbinary('RETR Output.txt', open('Output.txt', 'wb').write)
    ftp.retrbinary('RETR dicionario.json', open('dicionario.json', 'wb').write)
    with open('dicionario.json') as json_file:
        json_data = json.load(json_file)
    receptor_file = json_data['--receptor']
    print 'Retrieving receptor file ' + receptor_file
    ftp.retrbinary('RETR ' + receptor_file, open(receptor_file, 'wb').write)
    ftp.cwd('Files')
    ftp.retrlines('LIST')
    filename = ftp.nlst()[0]
    print 'Getting ' + filename
    ftp.retrbinary('RETR ' + filename, open(filename, 'wb').write)
    with open("Output.txt", "a") as input_file:
        input_file.write('ligand = %s' %filename)
        input_file.close()
    ftp.delete(filename)
    ftp.cwd('../Processing')
    ftp.storbinary('STOR ' + filename, open(filename, 'rb'))
    ftp.quit()

    print "Processing"
    return_code = subprocess.call(calls the program for processing files)
    if return_code == 0:
        print """Done!"""
        ftp.connect(arguments.host_ip, arguments.host_port)
        ftp.login("client", "password")
        ftp.cwd('Results')
        ftp.storbinary('STOR ' + os.path.splitext(filename)[0] + '_out.pdbqt', open (os.path.splitext(filename)[0] + '_out.pdbqt'))
        ftp.cwd('../Processing')
        ftp.delete(filename)


        ftp.quit()
    else:
        print """Something is technically wrong..."""
        ftp.connect(arguments.host_ip, arguments.host_port)
        ftp.login("client", "password")
        ftp.cwd('Files')
        ftp.storbinary('STOR ' + filename, open(filename, 'rb'))
        ftp.cwd('../Processing')
        ftp.delete(filename)
        ftp.quit()

谢谢你的帮助

因此,在花了半个月的时间修改这段代码后,当客户端取消连接时,我终于让它工作了

首先,我必须让服务器识别每个客户机。我没有让他们只使用一个用户登录,而是为每个连接创建了特定的用户,具有两种不同的功能:

def handler_generation(size=9, chars=string.ascii_uppercase + string.digits):
    return ''.join(random.choice(chars) for i in range (size))
这将生成一个9个字符的登录名和密码

然后,我在pyftpdlib中创建了一个自定义处理程序,并使用on_login函数:

class MyHandler(FTPHandler):
    def on_login(self, username):
    if username == "client":
        user_login = handler_generation()
        user_password = handler_generation()
        global authorizer
        authorizer.add_user(user_login, user_password, '.', perm='elradfmwM')
        credentials = open("Credentials.txt",'w')
        credentials.write(user_login)
        credentials.write("\n")
        credentials.write(user_password)
        credentials.close()
    else:
        pass
因此,当客户端与“客户端”登录连接时,服务器生成一个9个字符的登录名和密码,并将其发送到“Credentials.txt”文件中的客户端。在客户端,它将执行以下操作:

ftp.login("client", "password")
    ftp.retrbinary('RETR Credentials.txt', open('Credentials.txt', 'wb').write)
    ftp.quit()
    with open('Credentials.txt') as credential_file:
        lines = credential_file.readlines()
        credential_login = lines[0].split("\n")[0]
        credential_password = lines[1].split("\n")[0]
    ftp.connect(arguments.host_ip, arguments.host_port)
    ftp.login(credential_login, credential_password)
因此,现在客户端都使用自己的特定登录进行连接。在客户端,我这样做是为了,对于完成的每个任务,客户端都会发送一个名为其特定登录名的文件。我还让客户端将自己的登录名附加到他们正在处理的文件中,以便于服务器查找该文件:

ftp.rename(filename, credential_login + filename)
然后,我使用了handler类的另一个函数on_disconnect:

def on_disconnect(self):
    if self.username == "client":
        pass
    else:
        if os.path.isfile(self.username):
            pass
        else:
            for fname in os.listdir("Processing"):
                if fname.startswith(self.username):
                    shutil.move("Processing/" + fname, "Files")
                    os.rename("Files/" + fname, "Files/" + fname[9::])

    print self.remote_ip, self.remote_port,self.username, "disconnected"
    pass
现在,每当客户机断开连接时,服务器都会搜索文件夹,以检查客户机是否发送了处理程序文件。如果它不在那里,服务器将把文件移到“Files”文件夹中,这是一个将要处理的文件放在其中的文件夹

为了使失败的客户端在不发送quit命令的情况下与服务器断开连接,我使用了pyftpdlib中的timeout函数。为了确保活动客户端不会意外超时,我在客户端中实现了一个线程,每N秒对服务器执行一次操作:

class perpetualTimer():

def __init__(self,t,hFunction):
    self.t=t
    self.hFunction = hFunction
    self.thread = Timer(self.t,self.handle_function)

def handle_function(self):
    self.hFunction()
    self.thread = Timer(self.t,self.handle_function)
    self.thread.start()

def start(self):
    self.thread.start()

def cancel(self):
    self.thread.cancel()

def NotIdle():
    Doing something here

t = perpetualTimer(10, NotIdle)
t.start()
(这段代码是我直接从这里的某个人那里抄来的)

瞧。现在,服务器和客户端都可以工作,并且都有自己的错误检查功能

我把这个答案放在这里,以防有人遇到类似的问题

谢谢