Python-Socketserver实现FTP,文件上传下载
Posted 谁吃了我的唐僧肉
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python-Socketserver实现FTP,文件上传下载相关的知识,希望对你有一定的参考价值。
一、Socketserver实现FTP,文件上传、下载
目录结构
1、socketserver实现ftp文件上传下载,可以同时多用户登录、上传、下载
效果图:
二、上面只演示了下载,上传也是一样的,来不及演示了,上代码
1、客户端
1 import socket,hashlib,os,json,sys,time 2 3 4 5 class Ftpclient(object): 6 7 8 def __init__(self): 9 self.client = socket.socket() 10 11 def connect(self,ip,port): 12 self.client.connect((ip, port)) 13 14 15 def help(self): 16 msg=\'\'\' 17 ls 18 19 pwd 20 21 cd .. 22 23 get filename 24 25 put filename 26 27 \'\'\' 28 print(msg) 29 30 31 def interactive(self): 32 """ 33 客户端入口 34 :return: 35 """ 36 while True: 37 verify = self.authenticate() #服务器端认证 38 if verify: 39 while True: 40 cmd = input(\'输入命令 >>\').strip() 41 if len(cmd) == 0:continue 42 cmd_str = cmd.split()[0] 43 if hasattr(self,\'cmd_%s\' %cmd_str): 44 func = getattr(self,\'cmd_%s\' %cmd_str) 45 func(cmd) 46 else: 47 self.help() 48 49 50 def cmd_put(self,*args): 51 """ 52 上传文件 53 :param args: 54 :return: 55 """ 56 cmd_solit = args[0].split() 57 start_time = self.alltime() # 开始时间 58 if len(cmd_solit) > 1: 59 filename = cmd_solit[1] 60 if os.path.isfile(filename): 61 filesize = os.stat(filename).st_size 62 msg_dic = { 63 \'filename\':filename, 64 \'size\':filesize, 65 \'overridden\':True, 66 \'action\':cmd_solit[0] 67 } 68 69 self.client.send( json.dumps(msg_dic).encode(\'utf-8\')) 70 server_respinse=self.client.recv(1024) #防止粘包,等服务器确认返回 71 print(\'文件开始上传\',server_respinse) 72 client_size = 0 73 f = open(filename,\'rb\') 74 for line in f: 75 client_size += self.client.send(line) 76 self.processBar(client_size,filesize) #进度条 77 else: 78 print(\'文件传输完毕,大小为 %s\'%client_size) 79 end_time = self.alltime() # 结束时间 80 print(\'本次上传花费了%s 秒\'%self.alltime(end_time,start_time)) 81 f.close() 82 else: 83 print(filename,\'文件不存在\') 84 else: 85 print(\'输入有误!\') 86 87 88 def cmd_get(self,*args): 89 """ 90 下载文件 91 :param args: 92 :return: 93 """ 94 cmd_solit = args[0].split() 95 start_time = self.alltime() # 开始时间 96 filename = cmd_solit[1] 97 if len(cmd_solit) > 1: 98 msg_dic = { 99 \'filename\': filename, 100 \'size\': \'\', 101 \'overridden\': True, 102 \'action\': cmd_solit[0], 103 \'file_exist\':\'\' 104 } 105 self.client.send(json.dumps(msg_dic).encode(\'utf-8\')) 106 self.data = self.client.recv(1024).strip() 107 108 cmd_dic = json.loads(self.data.decode(\'utf-8\')) 109 print(cmd_dic) 110 if cmd_dic[\'file_exist\']: 111 if os.path.isfile(filename): 112 f = open(filename + \'.new\', \'wb\') 113 else: 114 f = open(filename, \'wb\') 115 116 self.client.send(b\'200 ok\') #防止粘包,等服务器确认返回 117 client_size = 0 118 filesize = cmd_dic[\'size\'] 119 m = hashlib.md5() 120 while client_size < filesize: 121 data=self.client.recv(1024) 122 f.write(data) 123 client_size +=len(data) 124 m.update(data) 125 self.processBar(client_size, filesize) 126 else: 127 print(\'下载完毕\') 128 end_time = self.alltime() # 结束时间 129 print(\'本次下载花费了%s 秒\' % self.alltime(end_time, start_time)) 130 f.close() 131 new_file_md5 = m.hexdigest() 132 server_file_md5 = self.client.recv(1024) 133 print(\'MD5\', server_file_md5,new_file_md5) 134 135 else: 136 print(\'下载的 %s文件不存在\'%filename) 137 138 else: 139 print(\'输入有误!\') 140 141 142 def cmd_dir(self,*arge): 143 cmd_solit = arge[0].split() 144 if len(cmd_solit) > 0: 145 msg_dic = { 146 \'action\': cmd_solit[0] 147 } 148 self.client.send(json.dumps(msg_dic).encode()) 149 cmd_dir = self.client.recv(1024) 150 print(cmd_dir.decode()) 151 152 else: 153 print(\'输入错误!\') 154 155 156 157 def alltime(self,*args): 158 """ 159 计算上传、下载时间 160 :param args: 161 :return: 162 """ 163 if args: 164 return round(args[0] - args[1]) 165 else: 166 return time.time() 167 168 169 def processBar(self,num, total): 170 """ 171 进度条 172 :param num:文件总大小 173 :param total: 已存入文件大小 174 :return: 175 """ 176 rate = num / total 177 rate_num = int(rate * 100) 178 if rate_num == 100: 179 r = \'\\r%s>%d%%\\n\' % (\'=\' * int(rate_num /3), rate_num,) 180 else: 181 r = \'\\r%s>%d%%\' % (\'=\' * int(rate_num /3), rate_num,) 182 sys.stdout.write(r) 183 sys.stdout.flush 184 185 186 def authenticate(self): 187 """ 188 用户加密认证 189 :return: 190 """ 191 username = input(\'输入用户名:>>\') 192 password = input(\'输入密码:>>\') 193 m = hashlib.md5() 194 if len(username) > 0 and len(password) >0: 195 username = \'\'.join(username.split()) 196 password = \'\'.join(password.split()) 197 m.update(username.encode(\'utf-8\')) 198 m.update(password.encode(\'utf-8\')) 199 200 m = { 201 \'username\':username, 202 \'password\':password, 203 \'md5\':m.hexdigest() 204 } 205 self.client.send(json.dumps(m).encode(\'utf-8\')) 206 server_user_md5 = self.client.recv(1024).strip() 207 print(server_user_md5.decode()) 208 if server_user_md5.decode() == \'success\': 209 print(\'登录成功!\') 210 return \'ok\' 211 else: 212 print(\'用户名密码错误!\') 213 else: 214 print(\'请输入用户名密码\') 215 216 217 218 f = Ftpclient() 219 f.connect(\'localhost\',9999) 220 f.interactive()
2、服务器端
1 import socketserver,json,os,hashlib,sys,paramiko 2 3 import settings 4 5 class Mysocketserver(socketserver.BaseRequestHandler): 6 7 8 9 def put(self,*args): 10 \'\'\' 11 接受客户端上传文件 12 :return: 13 \'\'\' 14 cmd_dic = args[0] 15 filename = cmd_dic[\'filename\'] #获取文件名 16 filesize= cmd_dic[\'size\'] #获取文件大小(字节) 17 18 if os.path.isfile(filename): #判断文件是否存在 19 f = open(filename + \'.new\',\'wb\') 20 else: 21 f = open(filename, \'wb\') 22 23 self.request.send(b\'200 ok\') #防止粘包 24 print(\'%s 文件开始上传\' % self.client_address[0]) 25 received_size = 0 26 while received_size < filesize: 27 data = self.request.recv(1024) 28 f.write(data) 29 received_size += len(data) 30 else: 31 print(\'文件传输完毕\',filename) 32 33 34 def get(self, *args): 35 \'\'\' 36 客户端下载文件 37 :return: 38 \'\'\' 39 msg_dic = { 40 \'filename\': \'\', 41 \'size\': \'\', 42 \'overridden\': True, 43 \'action\': \'\', 44 \'file_exist\': \'\' 45 } 46 47 cmd_solit = args[0] 48 filename = cmd_solit[\'filename\'] 49 file_exist = os.path.isfile(filename) 50 msg_dic[\'file_exist\'] = file_exist 51 print(file_exist) 52 if file_exist: 53 filesize = os.stat(filename).st_size 54 55 msg_dic[\'filename\'] = filename 56 msg_dic[\'size\'] = filesize 57 msg_dic[\'action\'] = cmd_solit[\'action\'] 58 59 self.request.send(json.dumps(msg_dic).encode(\'utf-8\')) 60 server_respang = self.request.recv(1024) #防止粘包 61 print(\'开始传输\',server_respang) 62 f = open(filename,\'rb\') 63 m = hashlib.md5() 64 for lien in f: 65 m.update(lien) 66 self.request.send(lien) 67 else: 68 print(\'传输完成\') 69 f.close() 70 self.request.send(m.hexdigest().encode()) 71 else: 72 print(\'文件不存在\') 73 self.request.send(json.dumps(msg_dic).encode(\'utf-8\')) 74 75 76 77 def client_authentication(self): 78 """ 79 客户端认证 80 :return: 81 """ 82 self.client_user= self.request.recv(1024).strip() 83 client_xinxi = json.loads(self.client_user.decode(\'utf-8\')) 84 try: 85 with open(settings.school_db_file + client_xinxi[\'username\'],\'rb\') as f: 86 data = json.load(f) 87 if data[\'md5\'] == client_xinxi[\'md5\']: #判断用户输入是否和服务器端MD5是否一致 88 print(\'验证成功!\') 89 self.request.send(\'success\'.encode()) 90 return \'success\' 91 else: 92 self.request.send(\'error\'.encode()) 93 except Exception as e: 94 print(\'没有此用户\',e) 95 self.request.send(\'error\'.encode()) 96 97 98 def dir(self,*args): 99 """ 100 查看目录 101 :param args: 102 :return: 103 """ 104 cmd_split = args[0] 105 dd=cmd_split[\'action\'] 106 result_os = os.popen(dd).read() 107 self.request.send(result_os.encode()) 108 109 110 111 def handle(self): 112 """ 113 服务器端入口 114 :return: 115 """ 116 while True: 117 try: 118 success = self.client_authentication() 119 if success: 120 self.data=self.request.recv(1024).strip() 121 cmd_dic = json.loads(self.data.decode(\'utf-8\')) 122 action = cmd_dic[\'action\'] 123 if hasattr(self,action): 124 func = getattr(self,action) 125 func(cmd_dic) 126 except ConnectionResetError as e: 127 print(\'连接断开\',self.client_address[0]) 128 break 129 130 131 132 if __name__ == \'__main__\': 133 134 HOST,PORT=\'localhost\',9999 135 server=socketserver.ThreadingTCPServer((HOST,PORT),Mysocketserver) 136 server.serve_forever()
settings.py 文件
1 import os 2 3 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 4 5 DB_FILE = os.path.join(BASE_DIR, "data\\\\") 6 7 school_db_file = os.path.join(DB_FILE) 8 print(school_db_file)
data里两个做测试的文件,
1 alex 文件内容: 2 {"username": "alex", "password": "123456", "md5": "94e4ccf5e2749b0bfe0428603738c0f9"}
kml123456文件内容: {"username": "kml123456", "password": python-socketServer多并发