ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

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

2019-09-21 12:01:53  阅读:264  来源: 互联网

标签:opt FTP day9 Python dic sk filesize file usr


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

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

 

  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
  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.待补充

标签:opt,FTP,day9,Python,dic,sk,filesize,file,usr
来源: https://www.cnblogs.com/wanglj/p/11562228.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有