Python之路day9-FTP作业_待完善

day09 网络编程 Eva-J 博客地址: https://www.cnblogs.com/Eva-J/articles/11437710.html

day09 FTP作业需求地址: https://www.cnblogs.com/Eva-J/articles/7642557.html

 

Python之路day9-FTP作业_待完善
  1 #!/usr/bin/python
  2 # -*- coding:utf-8 -*-
  3 # Author :王刘俊
  4 
  5 import socketserver
  6 import json
  7 import hashlib
  8 import os, sys
  9 import struct
 10 
 11 remote_file = os.path.join(os.path.dirname(__file__), 'remote')  # 存储服务端存放文件的绝对路径
 12 
 13 
 14 class Auth:
 15 
 16     @classmethod
 17     def register(cls, usr_dic):  # 服务端注册校验结果
 18         pwd = cls.get_md5(usr_dic)
 19         with open('userinfo', 'a', encoding='utf-8') as f:
 20             f.write('%s|%s\n' % (usr_dic['username'], pwd))
 21         result_dic = {'operate': 'register', 'flag': True}
 22         return result_dic
 23 
 24     @classmethod
 25     def login(cls, usr_dic):  # 服务端登录校验结果
 26         pwd = cls.get_md5(usr_dic)
 27         with open('userinfo', encoding='utf-8') as f:
 28             for line in f:
 29                 if line:
 30                     userinfo = line.strip().split('|')
 31                     if userinfo[0] == usr_dic['username'] and userinfo[1] == pwd:
 32                         result_dic = {'operate': 'login', 'flag': True}
 33                         break
 34             else:
 35                 result_dic = {'operate': 'login', 'flag': False}
 36         return result_dic
 37 
 38     @staticmethod
 39     def get_md5(usr_dic):  # 根据用户名加盐对密码进行md5加密
 40         md5 = hashlib.md5(usr_dic['username'].encode('utf-8'))
 41         md5.update(usr_dic['password'].encode('utf-8'))
 42         pwd = md5.hexdigest()
 43         return pwd
 44 
 45     @staticmethod
 46     def myquit(opt_dic):  # 退出
 47         opt_dic['flag'] = False
 48         return opt_dic
 49 
 50 
 51 class Myserver(socketserver.BaseRequestHandler):
 52     def mysend(self, dic, protocol=False):  # 发送信息
 53         str_d = json.dumps(dic).encode('utf-8')
 54         if protocol:
 55             len_b = len(str_d)  # 计算json格式的字典长度
 56             len_dic = struct.pack('i', len_b)  # 将长度利用struct转化为4个字节
 57             self.request.send(len_dic)  # 发送长度
 58         self.request.send(str_d)
 59 
 60     def myrecv(self, msg_len=1024, protocol=False):  # 自定义协议接收数据
 61         if protocol:
 62             bytes_len = self.request.recv(4)  # 接收4字节,即将接受字符串的长度
 63             msg_len = struct.unpack('i', bytes_len)[0]  # 解析字符串长度
 64         msg = self.request.recv(msg_len)  # 根据指定长度接收信息
 65         str_msg = msg.decode('utf-8')  # 解码
 66         opt_dic = json.loads(str_msg)
 67         return opt_dic
 68 
 69     @staticmethod
 70     def processBar(num, total):  # 实现进度条
 71         rate = num / total
 72         rate_num = int(rate * 100)
 73         if rate_num == 100:
 74             r = '\r%s>%d%%\n' % ('=' * rate_num, rate_num,)
 75         else:
 76             r = '\r%s>%d%%' % ('=' * rate_num, rate_num,)
 77         sys.stdout.write(r)
 78         sys.stdout.flush
 79 
 80     def upload(self, opt_dic):  # 上传文件
 81         filename = opt_dic['filename']
 82         file_path = os.path.join(remote_file, filename)
 83         # 按指定大小依次接收文件内容,并写入新文件
 84         with open(file_path, 'wb') as f:
 85             filesize = opt_dic['filesize']
 86             while filesize > 0:
 87                 content = self.request.recv(10240)
 88                 f.write(content)
 89                 filesize -= len(content)
 90                 self.processBar(opt_dic['filesize'] - filesize, opt_dic['filesize'])
 91         print('已成功发送\033[34m%s\033[0m,共计\033[34m%s\033[0m字节' % (filename, opt_dic['filesize']))
 92         opt_dic['flag'] = True
 93         return opt_dic
 94 
 95     def download(self, opt_dic):  # 下载文件
 96         # 将remote 文件夹下的文件名和大小写入字典,准备发送到客户端
 97         file_dic = {}
 98         for file in os.listdir(remote_file):
 99             file_path = os.path.join(remote_file, file)
100             file_dic[file] = os.path.getsize(file_path)
101         self.mysend(file_dic, True)
102         dic = self.myrecv(protocol=True)
103         file_path = os.path.join(remote_file, dic['filename'])
104         with open(file_path, 'rb') as  f:
105             filesize = dic['filesize']
106             while filesize > 0:
107                 content = f.read(10240)
108                 self.request.send(content)
109                 filesize -= len(content)
110                 self.processBar(dic['filesize'] - filesize, dic['filesize'])
111         print('已发送文件\033[34m%s\033[0m 共计\033[34m%s\033[0m字节' % (dic['filename'], dic['filesize']))
112         opt_dic['flag'] = True
113         return opt_dic
114 
115     def myquit(self, opt_dic):  # 退出
116         opt_dic['flag'] = False
117         return opt_dic
118 
119     def handle(self):  # 重写handle方法
120         while True:
121             try:
122                 usr_dic = self.myrecv(protocol=True)  # 接收指令
123                 if hasattr(Auth, usr_dic['operate']):  # 反射注册、登录验证
124                     result_dic = getattr(Auth, usr_dic['operate'])(usr_dic)
125                 if result_dic['flag'] and usr_dic['operate'] != 'myquit':
126                     self.mysend(result_dic, protocol=True)
127                 while result_dic['flag']:
128                     opt_dic = self.myrecv(protocol=True)
129                     if hasattr(Myserver, opt_dic['operate']):  # 反射上传、下载
130                         result_dic = getattr(Myserver, opt_dic['operate'])(self, opt_dic)
131                         if not result_dic['flag']: break
132                 print('客户端%s已断开连接' % self.client_address[0])
133                 break
134             except ConnectionResetError:
135                 print('客户端%s已断开连接:' % self.client_address[0])
136                 break
137 
138 
139 sk = socketserver.ThreadingTCPServer(('127.0.0.1', 9000), Myserver)
140 sk.serve_forever()
FTP-server Python之路day9-FTP作业_待完善
  1 #!/usr/bin/python
  2 # -*- coding:utf-8 -*-
  3 # Author :王刘俊
  4 
  5 import socket
  6 import json
  7 import os, sys
  8 import struct
  9 
 10 local_file = os.path.join(os.path.dirname(__file__), 'local')  # 存储客户端存放文件的绝对路径
 11 
 12 
 13 def send_dic(sk, dic, protocol=False):  # 自定义发送信息函数
 14     bytes_d = json.dumps(dic).encode('utf-8')  # 字典转为json格式并编码
 15     if protocol:
 16         len_b = len(bytes_d)  # 计算json格式的字典长度
 17         len_dic = struct.pack('i', len_b)  # 将长度利用struct转化为4个字节
 18         sk.send(len_dic)  # 发送长度
 19     sk.send(bytes_d)
 20 
 21 
 22 def recv_dic(sk, msg_len=1024, protocol=False):
 23     if protocol:
 24         bytes_len = sk.recv(4)  # 接收4字节,即将接受字符串的长度
 25         msg_len = struct.unpack('i', bytes_len)[0]  # 解析字符串长度
 26     msg = sk.recv(msg_len)  # 根据指定长度接收信息
 27     str_msg = msg.decode('utf-8')  # 解码
 28     opt_dic = json.loads(str_msg)
 29     return opt_dic
 30 
 31 
 32 def get_usr(opt='login'):  # 接收输入的用户名密码
 33     usr_dic = {}
 34     inp_usr = input('请输入用户名:').strip()
 35     inp_pwd = input('请输入密码:').strip()
 36     if inp_usr and inp_pwd and opt == 'register':
 37         cfm_pwd = input('再次确认密码:').strip()
 38         if inp_pwd == cfm_pwd:  # 发送明文密码
 39             usr_dic = {'username': inp_usr, 'password': inp_pwd, 'operate': opt}
 40     elif inp_usr and inp_pwd:
 41         usr_dic = {'username': inp_usr, 'password': inp_pwd, 'operate': opt}
 42     return usr_dic
 43 
 44 
 45 def login(sk):  # 登录
 46     print('in login')
 47     ret = get_usr()
 48     if ret: send_dic(sk, ret, protocol=True)
 49     res_dic = recv_dic(sk, protocol=True)
 50     if res_dic['operate'] == 'login' and res_dic['flag']:
 51         print('登录成功')
 52     else:
 53         print('登录失败')
 54     return res_dic['flag']
 55 
 56 
 57 def register(sk):  # 注册
 58     print('in register')
 59     ret = get_usr('register')
 60     if ret: send_dic(sk, ret, protocol=True)
 61     res_dic = recv_dic(sk, protocol=True)
 62     if res_dic['operate'] == 'register' and res_dic['flag']:
 63         print('注册成功')
 64     else:
 65         print('注册失败')
 66     return res_dic['flag']
 67 
 68 
 69 def upload(sk):  # 文件上传
 70     path = input('请输入要上传的文件路径:').strip()
 71     if os.path.isfile(path):  # 确保文件是真实存在的
 72         # 拿到文件名字和大小
 73         filename = os.path.basename(path)
 74         filesize = os.path.getsize(path)
 75         dic = {'filename': filename, 'filesize': filesize, 'operate': 'upload'}
 76         send_dic(sk, dic, protocol=True)
 77         # 按指定字节大小发送文件
 78         with open(path, 'rb') as  f:
 79             al_size = filesize  # 记录下载进度
 80             while al_size > 0:
 81                 content = f.read(10240)
 82                 sk.send(content)
 83                 al_size -= len(content)
 84                 processBar(filesize - al_size, filesize)
 85             print('文件\033[34m%s\033[0m已成功上传' % filename)
 86     return True
 87 
 88 
 89 def download(sk):  # 文件下载
 90     dic = {'operate': 'download'}
 91     send_dic(sk, dic, protocol=True)  # 发送download 指令
 92     file_dic = recv_dic(sk, protocol=True)  # 接收文件列表
 93     print('-' * 30)
 94     print('序号\t文件名\t文件大小')
 95     for index, file in enumerate(file_dic, 1):
 96         print('%s %s\t%s' % (index, file, file_dic[file]))
 97     print('-' * 30)
 98     choice = input('请输入要下载的文件名:').strip()
 99     if choice in file_dic and file_dic[choice]:  # 所选文件存在且大小不为0
100         dic = {'filename': choice, 'filesize': file_dic[choice], 'operate': 'download'}
101         send_dic(sk, dic, protocol=True)
102         # 按指定字节大小接收文件到local目录
103         file_path = os.path.join(local_file, choice)
104         with open(file_path, 'wb') as f:
105             filesize = dic['filesize']
106             while filesize > 0:
107                 content = sk.recv(10240)
108                 f.write(content)
109                 filesize -= len(content)  # 发送大小
110                 processBar(dic['filesize'] - filesize, dic['filesize'])
111             print('文件\033[34m%s\033[0m已下载至\033[34m%s\033[0m' % (dic['filename'], local_file))
112     else:
113         print('文件不存在')
114     return True
115 
116 
117 def processBar(num, total):  # 实现进度条
118     rate = num / total
119     rate_num = int(rate * 100)
120     if rate_num == 100:
121         r = '\r%s>%d%%\n' % ('=' * rate_num, rate_num,)
122     else:
123         r = '\r%s>%d%%' % ('=' * rate_num, rate_num,)
124     sys.stdout.write(r)
125     sys.stdout.flush
126 
127 
128 def myquit(sk):
129     dic = {'operate': 'myquit'}
130     send_dic(sk, dic, protocol=True)
131     print('已断开连接')
132     return False
133 
134 
135 def choose_opt(opt_lst):  # 选择菜单
136     print('-' * 30)
137     for index, opt in enumerate(opt_lst, 1):
138         print(index, opt[0])
139     print('-' * 30)
140     while True:
141         try:
142             num = int(input('请输入要选择的操作序号:'))
143             return opt_lst[num - 1][1]
144         except (ValueError, IndexError):
145             print('输入不合法')
146 
147 
148 sk = socket.socket()
149 sk.connect(('127.0.0.1', 9000))
150 
151 opt_lst = [('登录', login), ('注册', register), ('退出', myquit)]
152 func = choose_opt(opt_lst)
153 res = func(sk)  # 登录注册
154 while res:
155     opt_lst2 = [('上传', upload), ('下载', download), ('退出', myquit)]
156     func = choose_opt(opt_lst2)
157     res = func(sk)  # 登录注册
158     if not res: break
159 sk.close()
FTP-client

 

remote 为服务端存放文件目录, local 为客户端存放文件目录

 

已完成:

  1. 多用户同时登陆

  2. 用户登陆,加密认证

  3.传输过程中现实进度条

  4.客户端意外输出、退出服务端异常处理

待完善:

  1. 完整度md5校验

  2. 磁盘分配: 每个用户拥有自己独立的目录

  3. 删除文件和文件夹,新建、上传文件夹

  4.待补充

上一篇:实验一


下一篇:SK-Learn随机梯度下降法