一、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 = ' %s>%d%% ' % ('=' * int(rate_num /3), rate_num,) 180 else: 181 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": "123456","md5": "a791650e70ce08896e3dafbaa7598c26"}
到这里差不多就没了,