2016-04-12 36 views
-1

我正在研究一个脚本,它连接“服务器”计算机中的几台“客户端”计算机,然后使用这些客户端来处理多个文件,使用FTP(pyftplib和pyftpdlib )用于传输文件和结果。构建python FTP脚本中的错误检查功能

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

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

这里是服务器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() 

感谢您的帮助!

回答

0

所以,半个月与此代码摆弄之后,我终于取得了当客户端取消连接

首先,我不得不做出的服务器,以确定每个客户端的方式发挥作用。而不是使他们仅与一个用户登录的,我创建特定用户针对每个连接,具有2个不同的功能:

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) 

因此,现在客户端都与自己的特定登录连接。在客户端,我这样做是为了完成每个任务,客户端将发送一个文件命名为他们的具体登录。我也做了客户在文件中添加自己的登录名,他们处理很容易让服务器来查找文件:

​​

然后,我用的处理程序类的其他功能,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 

现在,无论客户端何时断开,服务器都会搜索文件夹以检查客户端是否发送了处理程序文件。如果不存在,服务器会将文件移动到“文件”文件夹,该文件夹是尚未处理的文件所在的文件夹。

为了使一个失败的客户端从服务器断开连接而不发送退出命令,我使用了pyftpdlib的超时功能。为了确保活动的客户端会不小心超时,我实现了在客户端线程,会做一些与服务器中的每个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() 

(这个特殊的代码我从别人直接复制这里)

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

我在这里提供这个答案,以防有人遇到类似问题。

谢谢!