def login(self, sock, wdata): while True: try: login_info = set_struct.recv_message(sock) if login_info == None: break except BlockingIOError: continue #z在客户端登录时如果失去连接,那么会导致服务端也会被终止,在此捕获异常 except ConnectionResetError: queue.get() break #验证帐号是否正确,将返回的结果True和False返回给客户端,客户端以此凭据来展示登录成功或失败 is_success, username = login_obj.verify_account(login_info) wdata[sock] = [ username, ] is_success_dict = {'is_success': is_success, 'username': username} set_struct.send_message(sock, is_success_dict) if is_success_dict['is_success'] == True: print(self.put_response_code['204']) return else: print(self.put_response_code['205']) continue
def check_put_pause(self, put_file_dict, puted_file, pause_init, sock): #检查文件的MD5码 #1、如果文件MD5码一致,则会调用put_file_existed方法告知客户端 #2、如果MD5码不一致,且断点续传配置文件中也存在上传文件的断点记录的话,会让用户选择是否继续断点续传 puted_file_md5 = set_md5.set_file_md5(puted_file) if puted_file_md5 == put_file_dict['file_md5']: f, recv_size = self.put_file_existed(sock) return f, recv_size else: if os.path.exists(pause_init): recv_size = conf_obj.set_conf({'file_name': puted_file}, 'read_recv_size', pause_init) put_status_dict = { 'put_status': False, 'put_message': self.put_response_code['202'], 'put_again': 'yes', 'is_choice': 'yes' } set_struct.send_message(sock, put_status_dict) diff_dict = set_struct.recv_message(sock) if diff_dict['is_pause_go'] == 'y': f = set_file.write_file(puted_file, 'ab') if diff_dict['is_pause_go'] == 'n': f = set_file.write_file(puted_file, 'wb') recv_size = 0 return f, int(recv_size)
def put_diff(self, put_file, file_size, put_file_dict): '''接收服务端针对下载文件的状态反馈 1、如果反馈信息为True则可以开始执行puting方法,开始上传文件 2、如果反馈信息为False,是因为由服务端检查了,准备上传文件在断点续传配置文件中的记录 3、由用户选择是否进行断点续传,提供了y和n选项 ''' while True: put_status_dict = set_struct.recv_message(self.client) while True: print(put_status_dict['put_message']) if put_status_dict['is_choice'] == 'yes': is_pause_go = input('>>>').lower() if put_status_dict['put_status'] == False: if put_status_dict['put_again'] == 'yes': if is_pause_go in ['n' 'y']: diff_dict = {'is_pause_go': is_pause_go} set_struct.send_message(self.client, diff_dict) break else: print(self.put_request_code['205']) continue else: return else: self.puting(put_file, put_status_dict, file_size, put_file_dict) return
def get(self, cmd, filename): '''初始下载文件函数方法,在函数中验证准备下载的文件是否存在 1、如果文件存在,且MD5码一致,则告知用户无需重复下载 2、如果文件存在,但MD5码不一致,则调用check_get_pause方法,检查断点续传配置文件 3、如果文件不存在,则会调用downloading方法执行下载方法 ''' pause_init = os.path.join(self.base_dir, 'db', 'pause.init') get_file = os.path.join(self.base_dir, 'download', self.username, filename) if not os.path.exists(get_file): set_struct.send_message(self.client, {'cmd': cmd}) # self.client.send(cmd.encode(self.encoding)) get_dict = set_struct.recv_message(self.client) if get_dict['get_status'] == False: print(self.put_request_code['201']) return confirm_dict = {'confirm_get': True} set_struct.send_message(self.client, confirm_dict) print(self.put_request_code['200']) set_bar.set_bar() f = set_file.write_file(get_file, 'wb') recv_size = 0 self.downloading(f, recv_size, get_file, get_dict) else: set_struct.send_message(self.client, {'cmd': cmd}) # self.client.send(cmd.encode(self.encoding)) get_dict = set_struct.recv_message(self.client) if get_dict['get_status'] == False: print(self.put_request_code['201']) return get_file_md5 = set_md5.set_file_md5(get_file) if get_file_md5 == get_dict['file_md5']: self.get_file_existed() return else: f, file_name, recv_size = self.check_get_pause( get_file, pause_init) confirm_dict = { 'confirm_get': True, 'is_pause_go': self.is_pause_go } set_struct.send_message(self.client, confirm_dict) self.downloading(f, int(recv_size), file_name, get_dict)
def ll(self, cmd): #通过ll函数方法,可以查看用户通过cd命令到达指定目录后的文件 set_struct.send_message(self.client, {'cmd': cmd}) file_list = set_struct.recv_message(self.client) #如果返回的文件列表为空,则告知用户,否则打印文件 if len(file_list) == 0: print(self.put_request_code['210']) return else: print('文件列表如下:') for file in file_list: print(file)
def cd(self, cmd, directory): print(directory) '''通过cd命令,用户可以切换目录''' root_directory = os.path.join(self.base_dir, 'share') root_directory_list = os.listdir(root_directory) #如果用户指定切换的目录,在云盘列表,或使用cd / | cd ..命令时会将请求发送至客户端 if directory in root_directory_list or directory in ['/', '..']: set_struct.send_message(self.client, {'cmd': cmd}) self.current_directory = os.path.split( set_struct.recv_message(self.client))[1] if self.current_directory == 'share': self.current_directory = '/' else: print('没有找到%s' % directory)
def view(self, cmd, username): #用户可通过view命令浏览个人云盘空间文件的方法 if username != self.username: print(self.put_request_code['208']) return set_struct.send_message(self.client, {'cmd': cmd}) view_info = set_struct.recv_message(self.client) #如果返回的结果是列表,则告知用户云盘是空的 #如果返回的结果是字典,则会调用show_view_file犯法打印文件 if isinstance(view_info, list): print(self.put_request_code['209']) if isinstance(view_info, dict): self.show_view_file(view_info)
def put(self, filename, sock, wdata, rlist): print('jin') #服务端接收到put命令,处理上传文件的函数犯法 #1、如果文件存在,则会调用check_put_pause方法,检查断点续传配置文件爱你 #2、如果文件不存在,且磁盘空间满足上传文件的大小,则会调用puting方法执行上传 put_file_dict = set_struct.recv_message(sock) print('put_file_dict', put_file_dict) puted_file = os.path.join(self.base_dir, 'share', wdata[sock][0], filename) pause_init = os.path.join(self.base_dir, 'db', 'pause.init') free_size = self.free_size(sock, wdata) if os.path.exists(puted_file): f, recv_size = self.check_put_pause(put_file_dict, puted_file, pause_init, sock) if f == None: return else: f = None recv_size = 0 if put_file_dict['file_size'] < free_size: put_status_dict = { 'put_status': True, 'put_message': self.put_response_code['200'], 'put_again': 'no', 'is_choice': 'no', 'recv_size': recv_size } set_struct.send_message(sock, put_status_dict) t = Thread(target=self.puting, args=(f, recv_size, put_file_dict, puted_file, sock, rlist)) t.start() t.join() else: self.size_not_enough(put_file_dict, sock, wdata)
def login(self, client): while True: login_choice = input('还没有账号?按r注册账号,已有账号请按g>>>:') if login_choice in ['r', 'R', 'g', 'G']: if login_choice in ['r', 'R']: self.register() continue if login_choice in ['g', 'G']: if not os.path.exists( '%s/%s/%s' % (self.base_dir, 'db', 'account.init')): print('当前系统内还没有任何账号,请先注册') continue while True: username = input('请输入用户名:') password = input('请输入密码:') login_info = { 'username': username, 'password': password } set_struct.send_message(client, login_info) is_success_dict = set_struct.recv_message(client) if is_success_dict['is_success'] == True: self.username = is_success_dict['username'] print('连接成功') return username else: print('用户名或密码错误,请重新输入') continue else: print('您的输入有误,请重新输入') continue
def run(self): link_status_file = os.path.join(self.base_dir, 'db', 'link_status.txt') self.server_bind() conn_is_login = [] conn_not_login = [] rlist = [ self.server, ] wlist = [] wdata = {} while True: rl, wl, xl = select.select(rlist, wlist, [], 0.5) for sock in rl: if sock == self.server: conn, caddr = self.server.accept() #如果有客户端连接,如果队列没有满,则放入caddr,放入后如果队列满,则会创建文件,该文件的存在与否表示队列是否满载 if conn: if not queue.full(): queue.put(caddr) if queue.full(): set_file.write_file(link_status_file, 'w') if queue.empty(): os.remove(link_status_file) rlist.append(conn) conn_not_login.append(conn) else: if sock in conn_not_login: t = Thread(target=self.login, args=(sock, wdata)) t.start() t.join() conn_is_login.append(sock) conn_not_login.remove(sock) break while True: try: cmd_dict = set_struct.recv_message(sock) cmd = cmd_dict['cmd'] if not cmd: queue.get() os.remove(link_status_file) print(self.put_response_code['203']) sock.close() rlist.remove(sock) wdata.pop(sock) break wlist.append(sock) wdata[sock].append(cmd) break except BlockingIOError: break except Exception: queue.get() #通过文件是否存在控制并发量,如果客户端断开则删除该文件,表示允许客户端连接 if os.path.exists(link_status_file): os.remove(link_status_file) print(self.put_response_code['203']) sock.close() #在客户端登录时,还没有获取到rlist和wdata的值,所以当客户端重新连接时,服务端会报错 try: rlist.remove(sock) wdata.pop(sock) except KeyError: break break for sock in wl: request_method = wdata[sock][1].split()[0] if hasattr(self, request_method): #不同长度的命令分别处理,需要该判断,因为调用函数时传递的参数不同 if len(wdata[sock][1].split()) == 2: request_content = wdata[sock][1].split()[1] func = getattr(self, request_method) #从之前的通过反射判断如果方法存在,那么就执行func()变为发起一个线程去执行这个方法 t = Thread(target=func, args=(request_content, sock, wdata, rlist)) t.start() rlist.remove(sock) wlist.remove(sock) #之前没加这一句,下载的都是同一个文件 del wdata[sock][1] else: func = getattr(self, request_method) t = Thread(target=func, args=(sock, wdata, rlist)) t.start() rlist.remove(sock) wlist.remove(sock) del wdata[sock][1]
def pwd(self, cmd): #查看当前所在目录的命令 set_struct.send_message(self.client, {'cmd': cmd}) current_directory = set_struct.recv_message(self.client) print(current_directory)