python day 14: 作业:开发一个能够多用户上传文件的FTP脚本
程序员文章站
2022-05-09 17:58:15
python day 14 2019/10/19 [TOC] 1. 要求 FTP: 1,单独功能实现(进度条,断点续传) 2,整合 3,bin,config,db,lib程序目录 2. 自己写的程序目录 3. models模块 4. settings模块 5. tcp_server模块 6. cli ......
目录
python day 14
2019/10/19
1. 要求
ftp:
1,单独功能实现(进度条,断点续传)
2,整合
3,bin,config,db,lib程序目录
2. 自己写的程序目录
3. models模块
import os, sys sys.path.append(os.path.dirname(os.path.dirname(__file__))) import socketserver import socket import hashlib import pickle from config import settings import subprocess import chardet def down_file(conn): conn.sendall('请输入文件路径'.encode('utf-8')) filename = conn.recv(1024).decode('utf-8') print(filename) path = os.path.join(settings.file_db_dir, filename) if not os.path.exists(path): conn.sendall(b'1000') filesize = int(conn.recv(1024).decode('utf-8')) print(filesize) conn.sendall(b'ack') has_data = 0 content = bytes('',encoding='iso-8859-1') while has_data<filesize: ret = conn.recv(1024) # print(chardet.detect(ret)) content += ret has_data += len(ret) f = open(path,'wb') f.write(content) f.close() else: conn.sendall(b'1001') exist_file_size=os.stat(path).st_size conn.sendall(str(exist_file_size).encode('utf-8')) def do_command(conn): conn.sendall('请输入命令'.encode('utf-8')) com1 = conn.recv(1024).decode('utf-8') # ipconfig print(com1) result = subprocess.check_output(com1) # linux系统是以utf-8默认编码,windows是以gbk默认编码,所以此处result是以gbk编码的bytes,折腾了两个小时 # print(result.decode('gbk')) conn.sendall(str(len(result)).encode('utf-8')) # 1638 print(conn.recv(1024)) # b'lan' conn.sendall('ack'.encode('utf-8')) print(conn.recv(1024)) # b'ack' result = result.decode('gb2312').encode('utf-8') # print(chardet.detect(result)) conn.sendall(result) def login(conn, name, pwd): m = hashlib.md5(bytes('lan', encoding='utf-8')) m.update(bytes(pwd, encoding='utf-8')) hex1 = m.hexdigest() path = os.path.join(settings.client_db_dir, name) result = pickle.load(open(path, 'rb')) username, password = result.split('$') if username == name and password == hex1: conn.sendall('登录成功'.encode('utf-8')) return 1 else: conn.sendall('密码错误'.encode('utf-8')) return 0 def register(conn, name, pwd): m = hashlib.md5(bytes('lan', encoding='utf-8')) m.update(bytes(pwd, encoding='utf-8')) hex1 = m.hexdigest() s1 = '$'.join([name, hex1]) print(s1) path = os.path.join(settings.client_db_dir, name) pickle.dump(s1, open(path, 'wb')) conn.sendall('用户{0}注册成功'.format(name).encode('utf-8')) def connect_user(conn, addr1): inp = '请输入用户名与密码'.encode('utf-8') conn.sendall(inp) name = conn.recv(1024).decode('utf-8') pwd = conn.recv(1024).decode('utf-8') inp2 = '1是登录;2是注册,请输入数字进行选择'.encode('utf-8') conn.sendall(inp2) ret = conn.recv(1024).decode('utf-8') print('来自%s的消息:\n>>>%s' % (addr1[0], ret)) if ret == '2': register(conn, name, pwd) if ret == '1': result = login(conn, name, pwd) if result: while true: inp3 = '3是执行命令;4是上传文件,请输入数字进行选择'.encode('utf-8') conn.sendall(inp3) ret2 = conn.recv(1024).decode('utf-8') print('来自%s的消息:\n>>>%s' % (addr1[0], ret2)) if ret2 == '3': do_command(conn) elif ret2 == '4': down_file(conn) elif ret == 'q': break class myserver(socketserver.baserequesthandler): def handle(self): conn, addr2 = self.request, self.client_address connect_user(conn, addr2) # size_str = conn.recv(1024).decode('utf-8') # total_size_int = int(size_str) # print('来自%s的消息:\n>>>文件大小是%s' % (addr[0], total_size_int)) # has_data = 0 # file_name = conn.recv(1024).decode('utf-8') # print('来自%s的消息:\n>>>文件名字是%s' % (addr[0], file_name)) # conn.sendall('ack'.encode('utf-8')) # f = open(file_name, 'wb') # while true: # if has_data == total_size_int: # break # ret = conn.recv(1024) # f.write(ret) # has_data += len(ret) # f.close() # class mysocket(socket.socket): # def __init__(self, family=-1, type=-1, proto=-1, fileno=none): # self.name = none # self.pwd = none # super().__init__(family, type, proto, fileno) # # def login(self, user, pwd): # if self.name == user and self.pwd == pwd: # return true # else: # return false # # def register(self, user, pwd): # self.name = user # m = hashlib.md5() # m.update(bytes(pwd, encoding='utf-8')) # password = m.hexdigest() # self.pwd = password if __name__ == '__main__': addr = ('192.168.131.1', 9999,) tcp_server = socketserver.threadingtcpserver(addr, myserver) tcp_server.serve_forever()
4. settings模块
import os base_dir = os.path.dirname(os.path.dirname(__file__)) client_db_dir = os.path.join(base_dir, 'db', 'client') file_db_dir= os.path.join(base_dir, 'db', 'file')
5. tcp_server模块
import os, sys sys.path.append(os.path.dirname(os.path.dirname(__file__))) import pickle from lib.models import * def main(): addr = ('192.168.131.1', 9999,) tcp_server = socketserver.threadingtcpserver(addr, myserver) tcp_server.serve_forever() if __name__ == '__main__': main()
6. client模块
import os, sys import socket sys.path.append(os.path.dirname(os.path.dirname(__file__))) from lib.models import * import hashlib import getpass import chardet import pickle def recv_com(obj): file_size = int(obj.recv(1024).decode('utf-8')) print(file_size) # 1857 has_data = 0 obj.sendall('lan'.encode('utf-8')) print(obj.recv(1024)) # b'ack obj.sendall(b'ack') ret3 = '' while has_data < file_size: data = obj.recv(1024) # print(chardet.detect(data)) ret3 += data.decode('utf-8') has_data += len(data) # has_data = len(obj.recv(1024)) 这里还会再执行一次接收数据动作,所以就是这里卡住了。 print(ret3) def load_file(obj): command1 = obj.recv(1024).decode('utf-8') # 文件路径 print(command1) file_path = input('文件路径是:\n>>>').strip() file_name = os.path.split(file_path)[1] obj.sendall(file_name.encode('utf-8')) ret_code = obj.recv(1024) if ret_code ==b'1000': file_size = os.stat(file_path).st_size # int类型 obj.sendall(str(file_size).encode('utf-8')) obj.recv(1024) with open(file_path, 'rb') as f: for i in range(1,file_size+1): file_content = f.read(1) obj.sendall(file_content) sys.stdout.write('\r') sys.stdout.write('%.2f%% |%s' % (i / file_size * 100, int(i / file_size * 100) * '#')) sys.stdout.flush() elif ret_code==b'1001': pass def connect_server(): obj = socket.socket(socket.af_inet, socket.sock_stream) addr = ('192.168.131.1', 9999,) obj.connect(addr) ret_str = obj.recv(1024).decode('utf-8') print('来自%s的消息:\r\n>>>%s' % (addr[0], ret_str)) user = input('请输入用户名:>>>').strip() obj.sendall(user.encode('utf-8')) pwd = getpass.win_getpass('password:') obj.sendall(pwd.encode('utf-8')) result2 = str(obj.recv(1024), encoding='utf-8') # 1是登录;2是注册,请输入数字进行选择 print('来自%s的消息:\r\n>>>%s' % (addr[0], result2,)) inp = input('请输入发送给%s的消息:\n>>>' % addr[0]).strip() # 1 obj.sendall(inp.encode('utf-8')) result2 = str(obj.recv(1024), encoding='utf-8') print('来自%s的消息:\r\n>>>%s' % (addr[0], result2,)) # 登录成功 while true: result2 = str(obj.recv(1024), encoding='utf-8') print('来自%s的消息:\r\n>>>%s' % (addr[0], result2,)) # 3是执行命令;4是上传文件,请输入数字进行选择 inp = input('请输入发送给%s的消息:\n>>>' % addr[0]).strip() obj.sendall(inp.encode('utf-8')) # 3 if inp == '3': result2 = str(obj.recv(1024), encoding='utf-8') print('来自%s的消息:\r\n>>>%s' % (addr[0], result2,)) # 请输入命令 inp = input('请输入发送给%s的消息:\n>>>' % addr[0]).strip() obj.sendall(inp.encode('utf-8')) # ipconfig recv_com(obj) elif inp == '4': load_file(obj) elif inp == 'q': obj.close() break def main(): ''' 客户端主程序 :return: ''' connect_server() # ret = obj.recv(1024).decode('utf-8') # print('来自%s的消息:\n>>>%s' % (addr[0], ret)) # inp = input('请输入要传送的文件路径:\n>>>').strip() # size = str(os.stat(inp).st_size, encoding='utf-8') # file_name = os.path.split(inp)[1] # obj.sendall(size.encode('utf-8')) # obj.sendall(file_name.encode('utf-8')) # obj.recv(1024) # with open(inp, 'rb') as f: # for line in f: # if line: # obj.sendall(line) # else: # print('传送完毕') # break # obj.close() if __name__ == '__main__': main()
7. 后记
只实现了多用户md5登录,命令执行,文件传递,进度条显示,并没有实现文件续传功能。
还需要修改。不过也折腾了近5个小时,在编码的转换问题上折腾了好久。
下次一定要记住使用chardet模块的detect方法先检测下编码,然后按照对应的编码方式进行编码与解码。
上一篇: 有史以来最大的车祸
下一篇: 再这样处下去都和老公处出感情来了