目录结构
1、socketserver实现ftp文件上传下载,可以同时多用户登录、上传、下载
效果图:
二、上面只演示了下载,上传也是一样的,来不及演示了,上代码
1、客户端
import socket,hashlib,os,json,sys,time class Ftpclient(object): def __init__(self): self.client = socket.socket() def connect(self,ip,port): self.client.connect((ip, port)) def help(self): msg=\'\'\' ls pwd cd .. get filename put filename \'\'\' print(msg) def interactive(self): \"\"\" 客户端入口 :return: \"\"\" while True: verify = self.authenticate() #服务器端认证 if verify: while True: cmd = input(\'输入命令 >>\').strip() if len(cmd) == 0:continue cmd_str = cmd.split()[0] if hasattr(self,\'cmd_%s\' %cmd_str): func = getattr(self,\'cmd_%s\' %cmd_str) func(cmd) else: self.help() def cmd_put(self,*args): \"\"\" 上传文件 :param args: :return: \"\"\" cmd_solit = args[0].split() start_time = self.alltime() # 开始时间 if len(cmd_solit) > 1: filename = cmd_solit[1] if os.path.isfile(filename): filesize = os.stat(filename).st_size msg_dic = { \'filename\':filename, \'size\':filesize, \'overridden\':True, \'action\':cmd_solit[0] } self.client.send( json.dumps(msg_dic).encode(\'utf-8\')) server_respinse=self.client.recv(1024) #防止粘包,等服务器确认返回 print(\'文件开始上传\',server_respinse) client_size = 0 f = open(filename,\'rb\') for line in f: client_size += self.client.send(line) self.processBar(client_size,filesize) #进度条 else: print(\'文件传输完毕,大小为 %s\'%client_size) end_time = self.alltime() # 结束时间 print(\'本次上传花费了%s 秒\'%self.alltime(end_time,start_time)) f.close() else: print(filename,\'文件不存在\') else: print(\'输入有误!\') def cmd_get(self,*args): \"\"\" 下载文件 :param args: :return: \"\"\" cmd_solit = args[0].split() start_time = self.alltime() # 开始时间 filename = cmd_solit[1] if len(cmd_solit) > 1: msg_dic = { \'filename\': filename, \'size\': \'\', \'overridden\': True, \'action\': cmd_solit[0], \'file_exist\':\'\' } self.client.send(json.dumps(msg_dic).encode(\'utf-8\')) self.data = self.client.recv(1024).strip() cmd_dic = json.loads(self.data.decode(\'utf-8\')) print(cmd_dic) if cmd_dic[\'file_exist\']: if os.path.isfile(filename): f = open(filename + \'.new\', \'wb\') else: f = open(filename, \'wb\') self.client.send(b\'200 ok\') #防止粘包,等服务器确认返回 client_size = 0 filesize = cmd_dic[\'size\'] m = hashlib.md5() while client_size < filesize: data=self.client.recv(1024) f.write(data) client_size +=len(data) m.update(data) self.processBar(client_size, filesize) else: print(\'下载完毕\') end_time = self.alltime() # 结束时间 print(\'本次下载花费了%s 秒\' % self.alltime(end_time, start_time)) f.close() new_file_md5 = m.hexdigest() server_file_md5 = self.client.recv(1024) print(\'MD5\', server_file_md5,new_file_md5) else: print(\'下载的 %s文件不存在\'%filename) else: print(\'输入有误!\') def cmd_dir(self,*arge): cmd_solit = arge[0].split() if len(cmd_solit) > 0: msg_dic = { \'action\': cmd_solit[0] } self.client.send(json.dumps(msg_dic).encode()) cmd_dir = self.client.recv(1024) print(cmd_dir.decode()) else: print(\'输入错误!\') def alltime(self,*args): \"\"\" 计算上传、下载时间 :param args: :return: \"\"\" if args: return round(args[0] - args[1]) else: return time.time() def processBar(self,num, total): \"\"\" 进度条 :param num:文件总大小 :param total: 已存入文件大小 :return: \"\"\" rate = num / total rate_num = int(rate * 100) if rate_num == 100: r = \'\\r%s>%d%%\\n\' % (\'=\' * int(rate_num /3), rate_num,) else: r = \'\\r%s>%d%%\' % (\'=\' * int(rate_num /3), rate_num,) sys.stdout.write(r) sys.stdout.flush def authenticate(self): \"\"\" 用户加密认证 :return: \"\"\" username = input(\'输入用户名:>>\') password = input(\'输入密码:>>\') m = hashlib.md5() if len(username) > 0 and len(password) >0: username = \'\'.join(username.split()) password = \'\'.join(password.split()) m.update(username.encode(\'utf-8\')) m.update(password.encode(\'utf-8\')) m = { \'username\':username, \'password\':password, \'md5\':m.hexdigest() } self.client.send(json.dumps(m).encode(\'utf-8\')) server_user_md5 = self.client.recv(1024).strip() print(server_user_md5.decode()) if server_user_md5.decode() == \'success\': print(\'登录成功!\') return \'ok\' else: print(\'用户名密码错误!\') else: print(\'请输入用户名密码\') f = Ftpclient() f.connect(\'localhost\',9999) f.interactive()
2、服务器端
import socketserver,json,os,hashlib,sys,paramiko import settings class Mysocketserver(socketserver.BaseRequestHandler): def put(self,*args): \'\'\' 接受客户端上传文件 :return: \'\'\' cmd_dic = args[0] filename = cmd_dic[\'filename\'] #获取文件名 filesize= cmd_dic[\'size\'] #获取文件大小(字节) if os.path.isfile(filename): #判断文件是否存在 f = open(filename + \'.new\',\'wb\') else: f = open(filename, \'wb\') self.request.send(b\'200 ok\') #防止粘包 print(\'%s 文件开始上传\' % self.client_address[0]) received_size = 0 while received_size < filesize: data = self.request.recv(1024) f.write(data) received_size += len(data) else: print(\'文件传输完毕\',filename) def get(self, *args): \'\'\' 客户端下载文件 :return: \'\'\' msg_dic = { \'filename\': \'\', \'size\': \'\', \'overridden\': True, \'action\': \'\', \'file_exist\': \'\' } cmd_solit = args[0] filename = cmd_solit[\'filename\'] file_exist = os.path.isfile(filename) msg_dic[\'file_exist\'] = file_exist print(file_exist) if file_exist: filesize = os.stat(filename).st_size msg_dic[\'filename\'] = filename msg_dic[\'size\'] = filesize msg_dic[\'action\'] = cmd_solit[\'action\'] self.request.send(json.dumps(msg_dic).encode(\'utf-8\')) server_respang = self.request.recv(1024) #防止粘包 print(\'开始传输\',server_respang) f = open(filename,\'rb\') m = hashlib.md5() for lien in f: m.update(lien) self.request.send(lien) else: print(\'传输完成\') f.close() self.request.send(m.hexdigest().encode()) else: print(\'文件不存在\') self.request.send(json.dumps(msg_dic).encode(\'utf-8\')) def client_authentication(self): \"\"\" 客户端认证 :return: \"\"\" self.client_user= self.request.recv(1024).strip() client_xinxi = json.loads(self.client_user.decode(\'utf-8\')) try: with open(settings.school_db_file + client_xinxi[\'username\'],\'rb\') as f: data = json.load(f) if data[\'md5\'] == client_xinxi[\'md5\']: #判断用户输入是否和服务器端MD5是否一致 print(\'验证成功!\') self.request.send(\'success\'.encode()) return \'success\' else: self.request.send(\'error\'.encode()) except Exception as e: print(\'没有此用户\',e) self.request.send(\'error\'.encode()) def dir(self,*args): \"\"\" 查看目录 :param args: :return: \"\"\" cmd_split = args[0] dd=cmd_split[\'action\'] result_os = os.popen(dd).read() self.request.send(result_os.encode()) def handle(self): \"\"\" 服务器端入口 :return: \"\"\" while True: try: success = self.client_authentication() if success: self.data=self.request.recv(1024).strip() cmd_dic = json.loads(self.data.decode(\'utf-8\')) action = cmd_dic[\'action\'] if hasattr(self,action): func = getattr(self,action) func(cmd_dic) except ConnectionResetError as e: print(\'连接断开\',self.client_address[0]) break if __name__ == \'__main__\': HOST,PORT=\'localhost\',9999 server=socketserver.ThreadingTCPServer((HOST,PORT),Mysocketserver) server.serve_forever()
settings.py 文件
import os BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) DB_FILE = os.path.join(BASE_DIR, \"data\\\\\") school_db_file = os.path.join(DB_FILE) print(school_db_file)
data里两个做测试的文件,
alex 文件内容:
{\”username\”: \”alex\”, \”password\”: \”123456\”, \”md5\”: \”94e4ccf5e2749b0bfe0428603738c0f9\”}
kml123456文件内容:
{\”username\”: \”kml123456\”, \”password\”: \”123456\”,\”md5\”: \”a791650e70ce08896e3dafbaa7598c26\”}
到这里差不多就没了,
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持自学编程网。