项目: 更新(二) python 实现大概FTP的功能

服务器利用 socketserver 模块 构造, 实现了 多进程.

客户端仍然利用的是底层的 socket模块. 只不过进行了更深度的 解耦, 新加或者删除 某些功能 更方便

在上一个版本的基础上,增加了 新建文件夹的功能, 并且将vip用户的名字加上了颜色, 变成了黄金 vip.

服务器端设置了两个文件, 1, info( 存储用户密码); 2, vipinfo (存储所有的vip用户的名字)

还需要再补充一个log文件夹,里面用来保存所有客户的访问记录. ps: 此功能还没添加.

下面是代码:

服务器端:

  1 import socketserver
  2 import struct
  3 import pickle
  4 import os
  5 
  6 
  7 class Myserver(socketserver.BaseRequestHandler):
  8     def __init__(self, request, client_address, server):
  9         self.dic_cho = {
 10             'login': self.login,        # 登录
 11             'register': self.register,  # 注册
 12             'new_file': self.new_file,  # 创建新的文件夹
 13             'down_dir': self.down_dir,  # 进入下一层
 14             'up_dir': self.up_dir,      # 进入上一层
 15             'upload': self.upload,      # 上传
 16             'download': self.download,  # 下载
 17             'vip': self.vip,            # 升级vip
 18             'end': self.end,            # 结束
 19             'size': 102400
 20         }
 21         self.flag = False
 22         self.flag_end = True
 23         super().__init__(request, client_address, server)
 24 
 25     def my_reve(self):   # 因为每次接收后的内容都会转成字典, 所以重写了接收的函数
 26         return pickle.loads(self.request.recv(struct.unpack('i', self.request.recv(4))[0]))
 27 
 28     def my_send(self, dic): # 重写了 发送方法.
 29         dic_pic = pickle.dumps(dic)
 30         return self.request.send(struct.pack('i', len(dic_pic)) + dic_pic)
 31 
 32     def isvip(self, server_dict, client_dic):  
 33         """此函数是 login函数的附属函数, 只是用来判断该用户是否为Vip
 34 
 35         :param server_dict: 服务器需要发送的字典
 36         :param client_dic: 服务器接收的客户端发来的字典
 37         :return: None
 38         """
 39         with open('vipinfo', encoding='utf-8') as f:
 40             for name in f:
 41                 if client_dic['username'] == name.strip():
 42                     self.flag = True
 43                     server_dict['return'] = '登录成功, 欢迎尊敬的VIP用户:\033[1;33;m%s\033[0m 访问ftp' % client_dic['username']
 44                     self.dic_cho['size'] = 10240000
 45                     server_dict['size'] = '容量:(单位:字节)%s/10240000' % os.path.getsize(self.dir_path)
 46                     return
 47 
 48     def login(self, client_dic, server_dict):
 49         self.dir_path = os.path.join(os.path.dirname(__file__), client_dic['username'])
 50         # 第一步 判断用户名+密码 是否正确
 51         with open('info', encoding='utf-8') as f:
 52             for line in f:
 53                 if client_dic['username'] + '\t' + client_dic['password'] == line.strip():
 54                     server_dict['return'] = '登录成功, 欢迎%s 用户访问ftp' % client_dic['username']
 55                     server_dict['size'] = f'容量:(单位:字节){os.path.getsize(self.dir_path)}/102400'
 56                     server_dict['dir_list'] = os.listdir(self.dir_path)
 57                     # 第二步 判断此人是不是会员, 有没有vip文件中
 58                     self.isvip(server_dict, client_dic)
 59                     # 第三步, 将字典发送给 客户端并且 结束函数
 60                     self.my_send(server_dict)
 61                     return
 62             server_dict['return'] = '错误:输入错误'
 63             self.my_send(server_dict)
 64 
 65     def register(self, client_dic, server_dict):
 66         self.dir_path = os.path.join(os.path.dirname(__file__), client_dic['username'])
 67         with open('info', encoding='utf-8') as f:
 68             for line in f:
 69                 username, password = line.strip().split('\t')
 70                 if client_dic['username'] == username:
 71                     server_dict['return'] = '错误:用户名已存在'
 72                     self.my_send(server_dict)
 73                     return
 74         with open('info', 'a+', encoding='utf-8') as f:
 75             f.write(client_dic['username'] + '\t' + client_dic['password'] + '\n')
 76             self.flag = True
 77             server_dict['return'] = '注册成功,自动登录中'
 78             os.mkdir(client_dic['username'])
 79             server_dict['dir_list'] = os.listdir(self.dir_path)
 80             server_dict['size'] = f'容量:(单位:字节){os.path.getsize(self.dir_path)}/102400'
 81             self.my_send(server_dict)
 82 
 83     def new_file(self, client_dic, server_dict):
 84         """
 85         此函数和下面的六个函数 被执行的前提是客户已经登录成功了,
 86         且已经在客户端显示出来了文件列表, 若没有登录, 该用户访问不到此方法
 87 
 88         此函数的功能是 在当前工作列表中新建文件夹
 89         :param client_dic:
 90         :param server_dict:
 91         :return:
 92         """
 93         new_name = client_dic['new_dir_name']
 94         os.mkdir(os.path.join(self.dir_path, new_name))
 95         server_dict['return'] = '%s 文件夹新建成功' % new_name
 96         self.my_send(server_dict)
 97 
 98     def down_dir(self, client_dic, server_dict):
 99         down_dir_name = client_dic['down_dir_name']
100         self.dir_path = os.path.join(self.dir_path, down_dir_name)
101         server_dict['dir_list'] = os.listdir(self.dir_path)
102         self.my_send(server_dict)
103 
104     def up_dir(self, client_dic, server_dict):
105         dir_path_if = os.path.dirname(self.dir_path)
106         if dir_path_if == os.path.dirname(__file__):
107             server_dict['return'] = '已经是最上层目录了'
108         else:
109             self.dir_path = dir_path_if
110         server_dict['dir_list'] = os.listdir(self.dir_path)
111         self.my_send(server_dict)
112 
113     def upload(self, client_dic, server_dict):
114         filesize = client_dic['upload_file_size']
115         size = os.path.getsize(self.dir_path)
116         if filesize+size >= self.dic_cho['size']:
117             server_dict['return'] = '内存不足'
118             self.my_send(server_dict)
119             return
120         filename = os.path.join(self.dir_path, client_dic['upload_file_name'])
121         with open(filename, 'wb') as f:
122             while filesize:
123                 if filesize < 1024:
124                     content = self.request.recv(filesize)
125                 else:
126                     content = self.request.recv(1024)
127                 f.write(content)
128                 filesize -= len(content)
129         server_dict['return'] = '上传成功'
130         server_dict['dir_list'] = os.listdir(self.dir_path)
131         self.my_send(server_dict)
132 
133     def download(self, client_dic, server_dict):
134         filename = os.path.join(self.dir_path, client_dic['download_file_name'])
135         filesize = os.path.getsize(filename)
136         server_dict['file_size'] = filesize
137         self.my_send(server_dict)
138         with open(filename, 'rb') as f:
139             while filesize:
140                 if filesize > 1024:
141                     content = f.read(filesize)
142                 else:
143                     content = f.read(1024)
144                 self.request.send(content)
145                 filesize -= len(content)
146         ok = self.request.recv(2)
147         print(ok)
148         self.request.send(b'download ok') if ok == b'ok' else self.request.send(b'download no')
149 
150     def vip(self, client_dic, server_dict):
151         with open('vipinfo', 'r+', encoding='utf-8') as f:
152             for line in f:
153                 if client_dic['username'] == line.strip():
154                     server_dict['return'] = '您已经是尊敬的Vip用户了'
155                     self.my_send(server_dict)
156                     return
157             f.seek(0, 2)
158             f.write(client_dic['username'] + '\n')
159         self.isvip(server_dict, client_dic)
160         self.my_send(server_dict)
161 
162     def end(self, client_dic, server_dict):
163         self.flag_end = False
164         server_dict['return'] = '程序结束'
165         self.my_send(server_dict)
166 
167     def handle(self):
168         server_dict = {}
169         flag = self.flag_end
170         while flag:
171             try:
172                 client_dic = self.my_reve()
173                 self.dic_cho[client_dic['opt']](client_dic, server_dict)
174             except Exception:pass
175 
176 
177 server = socketserver.TCPServer(('127.0.0.1', 9090), Myserver)
178 server.serve_forever()

客户端:

  1 import os
  2 import socket
  3 import struct
  4 import pickle
  5 import hashlib
  6 
  7 
  8 class Myclient(socket.socket):
  9     def __init__(self):
 10         super().__init__()
 11         self.dic_cho = {
 12             'login': self.login,  # 登录
 13             'regis': self.register,  # 注册
 14             'new_file': self.new_file,  # 创建新的文件夹
 15             'down_dir': self.down_dir,  # 进入下一层
 16             'up_dir': self.up_dir,  # 进入上一层
 17             'upload': self.upload,  # 上传
 18             'download': self.download,  # 下载
 19             'vip': self.vip,  # 升级vip
 20             'end': self.end,  # 结束
 21         }
 22         self.flag = True
 23 
 24     def my_reve(self):
 25         return pickle.loads(self.sk.recv(struct.unpack('i', self.sk.recv(4))[0]))
 26 
 27     def my_send(self, dic):
 28         dic_pic = pickle.dumps(dic)
 29         return self.sk.send(struct.pack('i', len(dic_pic)) + dic_pic)
 30 
 31     def login(self):pass
 32 
 33     def register(self):pass
 34 
 35     def my_md5(self, user, pwd):
 36         md5_obj = hashlib.md5(user.encode('utf-8'))
 37         md5_obj.update(pwd.encode('utf-8'))
 38         return md5_obj.hexdigest()
 39 
 40     def new_file(self):
 41         new_file_name = input('>>>请输入新建文件夹的名字:').strip()
 42         self.client_dict['new_dir_name'] = new_file_name
 43         self.my_send(self.client_dict)
 44         server_dict = self.my_reve()
 45         print(server_dict['dir_list'])
 46 
 47     def down_dir(self):
 48         down_dir_name = input('>>>请输入下一级文件夹的名字:').strip()
 49         self.client_dict['down_dir_name'] = down_dir_name
 50         self.my_send(self.client_dict)
 51         server_dict = self.my_reve()
 52         print(server_dict['dir_list'])
 53 
 54     def up_dir(self):
 55         self.my_send(self.client_dict)
 56         server_dict = self.my_reve()
 57         print(server_dict['dir_list'])
 58 
 59     def upload(self):
 60         upload_file_path = input('>>>请输入上传文件绝对路径:').strip()
 61         self.client_dict['upload_file_name'] = os.path.basename(upload_file_path)
 62         self.client_dict['upload_file_size'] = os.path.getsize(upload_file_path)
 63         filesize = self.client_dict['upload_file_size']
 64         self.my_send(self.client_dict)
 65         with open(upload_file_path, 'rb') as f:
 66             while filesize:
 67                 if filesize > 1024:
 68                     content = f.read(filesize)
 69                 else:
 70                     content = f.read(1024)
 71                 self.sk.send(content)
 72                 filesize -= len(content)
 73         server_dict = self.my_reve()
 74         print(server_dict['return'])
 75         print(server_dict['dir_list'])
 76 
 77     def download(self):
 78         download_file_name = input('>>>请输入您要下载的文件的名字:').strip()
 79         download_file_path = input('>>>请输入要下载到本地的绝对路径以及对该文件命名:').strip()
 80         self.client_dict['download_file_name'] = download_file_name
 81         self.my_send(self.client_dict)
 82         server_dict = self.my_reve()
 83         filesize = server_dict['file_size']
 84         with open(download_file_path, 'wb') as f:
 85             while filesize:
 86                 if filesize < 1024:
 87                     content = self.sk.recv(filesize)
 88                 else:
 89                     content = self.sk.recv(1024)
 90                 f.write(content)
 91                 filesize -= len(content)
 92             self.sk.send(b'ok')
 93             ok = self.sk.recv(11)
 94             if ok == b'download ok':
 95                 print('下载成功')
 96             else:
 97                 print('下载失败')
 98             print(server_dict['dir_list'])
 99 
100     def vip(self):
101         self.my_send(self.client_dict)
102         server_dict = self.my_reve()
103         print(server_dict['return'])
104         print(server_dict['size'])
105         print(server_dict['dir_list'])
106 
107     def end(self):
108         self.my_send(self.client_dict)
109         self.flag = False
110         server_dict = self.my_reve()
111         print(server_dict['return'])
112 
113     def main(self):
114         main_dict = {
115             '1': self.new_file,
116             '2': self.down_dir,
117             '3': self.up_dir,
118             '4': self.upload,
119             '5': self.download,
120             '6': self.vip,
121             '7': self.end,
122         }
123         while 1:
124             print('1, 在当前目录新建文件夹\n'
125                   '2, 进入下级目录\n'
126                   '3, 返回上级目录\n'
127                   '4, 上传文件\n'
128                   '5, 下载文件\n'
129                   '6, 升级Vip\n'
130                   '7, 退出')
131             cho_main = input('>>>请输入功能选项ID:').strip()
132             try:
133                 self.client_dict['opt'] = main_dict[cho_main].__name__
134                 main_dict[cho_main]()
135                 if cho_main == '7':
136                     break
137             except Exception:
138                 print('选项输入不规范')
139 
140     def my_input(self, call_dict):
141         print('欢迎来到FTP\n1, 登录\n2, 注册')
142         cho = input('>>>请输入选项ID:').strip()
143         if cho != '1' and cho != '2':
144             return 3
145         username = input('>>>Username:').strip()
146         password = input('>>>Password:').strip()
147         self.client_dict['opt'] = call_dict[cho].__name__
148         self.client_dict['username'] = username
149         self.client_dict['password'] = self.my_md5(username, password)
150         self.my_send(self.client_dict)
151 
152     def main_main(self):
153         call_dict = {'1': self.login, '2': self.register}
154         self.client_dict = {}
155         flag = self.flag
156         while flag:
157             ret = self.my_input(call_dict)
158             if ret == 3:
159                 print('输入错误')
160                 continue
161             server_dict = self.my_reve()
162             print(server_dict['return'])
163             if server_dict['return'][0] != '':
164                 print(server_dict['size'])
165                 print(server_dict['dir_list'])
166                 self.main()
167                 flag = self.flag
168 
169     def __call__(self, *args, **kwargs):
170         self.sk = socket.socket()
171         self.sk.connect(('127.0.0.1', 9090))
172         self.main_main()
173         self.sk.close()
174 
175 
176 if __name__ == '__main__':
177     client = Myclient()
178     client()
179 
180 # 这个是 发送的字典的内容, 每次操作, 所对应的键值对 中的值都会发生改变.
181 # client_dict = {'opt': None,                   # 选项
182 #                'username': None,              # 用户名
183 #                'password': None,              # 密码
184 #                'new_dir_name': None,          # 新建文件夹的名字
185 #                'down_dir_name': None,         # 打开下一层文件夹的名字
186 #                'upload_file_name': None,      # 上传到ftp里面的文件的名字
187 #                'upload_file_size': None,      # 上传的文件的大小
188 #                'download_file_name': None,    # 下载的文件名字
189 #                }

猜你喜欢

转载自www.cnblogs.com/Fushengliangnian/p/9374388.html