#7512 import select import os,sys import socket,queue import time,hashlib import json import random BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(BASE_DIR) from conf import setting class SelectFTPServer(object): ''' FTP服务端 ''' SOCK_FAMALY = socket.AF_INET #IP v4 SOCK_TYPE = socket.SOCK_STREAM SOCK_ALLOW_CONN = 1024 MSG_DICT = {} INPUTS = [] OUTPUTS = [] READ ,WRITE ,EXCEPTION = None,None,None TASK_STEP =0 def __init__(self, ip = 'localhost' ,port = 9999): self.server = socket.socket(self.SOCK_FAMALY,self.SOCK_TYPE) self.server.bind((ip,port)) self.server.listen(self.SOCK_ALLOW_CONN) self.server.setblocking(False) self.INPUTS.append(self.server) print('服务器创建时间 : ', time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())) self.interaction() def com_get(self,get_con,recv_data): os.chdir(setting.SERVER_DOWNLOAD) #切换工作目录 # self.MSG_DICT[get_con]['comunicate_data']['error'] = 222 print('com_get',self.MSG_DICT[get_con]['comunicate_data']) if os.path.exists(recv_data['filename']): if os.path.isfile(recv_data['filename']): filename = setting.SERVER_DOWNLOAD +'\\%s'%recv_data['filename'] self.MSG_DICT[get_con]['comunicate_data']['error'] = 777 self.MSG_DICT[get_con]['comunicate_data']['size'] = os.stat(filename).st_size self.MSG_DICT[get_con]['comunicate_data']['filename'] = filename self.MSG_DICT[get_con]['user_stat']['task_step'] = 1 if get_con not in self.OUTPUTS: self.OUTPUTS.append(get_con) else: pass def com_put(self,put_con,recv_data): os.chdir(setting.SERVER_UPLOAD) self.MSG_DICT[put_con]['user_stat']['task_step'] = 1 if put_con not in self.OUTPUTS: self.OUTPUTS.append(put_con) else: pass def com_handle(self,recv_data): recv_data = self.datahead(recv_data,'recv') def data_format(self,rconn,recv_data): # self.MSG_DICT[rconn]['comunicate_data'] = self.datahead(recv_data,'recv') try: if type(self.datahead(recv_data, 'recv')) is dict: recv_data = self.datahead(recv_data,'recv') action = recv_data['action'] if action is not None and hasattr(self,'com_%s'%action): self.MSG_DICT[rconn]['comunicate_data'] = recv_data func = getattr(self,'com_%s'%action) func(rconn ,recv_data) else: if action == 'rspond_ok' and self.MSG_DICT[rconn]['user_stat']['task_step'] == 2: self.MSG_DICT[rconn]['user_stat']['task_step'] = 3 #如果收到回复,任务状态进入第二步 self.file_obj = open(self.MSG_DICT[rconn]['comunicate_data']['filename'], 'rb') except (json.decoder.JSONDecodeError,UnicodeDecodeError) : self.MSG_DICT[rconn]['queue'].put(recv_data) if rconn not in self.OUTPUTS: self.OUTPUTS.append(rconn) def connetion(self,rconn): if rconn is self.server : new_conn ,new_addr = self.server.accept() new_conn.setblocking(False) self.INPUTS.append(new_conn) self.MSG_DICT[new_conn] = {} self.MSG_DICT[new_conn]['queue'] = queue.Queue() self.MSG_DICT[new_conn]['user_stat'] = {} #存储文件断点标记 self.MSG_DICT[new_conn]['user_stat']['task_step'] = 0 #任务状态 self.MSG_DICT[new_conn]['md5'] = hashlib.md5() #校验码 self.MSG_DICT[new_conn]['comunicate_data'] = {} #声明通信协议 print('新连接:[%s],' %repr(new_addr), '创建时间:', time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())) else: try: recv_data = rconn.recv(1024) if recv_data: self.data_format(rconn,recv_data) else: print("空指令") self.INPUTS.remove(rconn) except ConnectionResetError as e: self.INPUTS.remove(rconn) if rconn in self.OUTPUTS: self.OUTPUTS.remove(rconn) del self.MSG_DICT[rconn] print('2 \033[31;1m [%s] 连接中断,中断原因 [%s] ,中断时间:[%s] \033[0m' %(repr(rconn.getpeername()),e,time.strftime('[%Y-%m-%d %H:%M:%S]',time.localtime()))) def sendable(self,wconn): try: if self.MSG_DICT[wconn]['comunicate_data']['action'] == 'get': if self.MSG_DICT[wconn]['user_stat']['task_step'] == 1 : #第一步将文件信息发送 wconn.send(self.datahead(self.MSG_DICT[wconn]['comunicate_data'],'send')) if self.MSG_DICT[wconn]['comunicate_data']['error'] == 777: self.MSG_DICT[wconn]['user_stat']['file_flag'] = 0 self.MSG_DICT[wconn]['user_stat']['task_step'] = 2 else: self.MSG_DICT[wconn]['user_stat']['task_step'] = 0 elif self.MSG_DICT[wconn]['user_stat']['task_step'] == 2: pass elif self.MSG_DICT[wconn]['user_stat']['task_step'] == 3: #第二步开始发送文件 self.file_obj.seek(self.MSG_DICT[wconn]['user_stat']['file_flag']) size = self.MSG_DICT[wconn]['comunicate_data']['size'] data = self.file_obj.readline() wconn.send(data) self.MSG_DICT[wconn]['user_stat']['file_flag'] += len(data) self.MSG_DICT[wconn]['md5'].update(data) #传输完成 if self.MSG_DICT[wconn]['user_stat']['file_flag'] >= size: self.MSG_DICT[wconn]['user_stat']['task_step'] = 0 self.MSG_DICT[wconn]['user_stat']['file_flag'] = 0 self.OUTPUTS.remove(wconn) wconn.send(self.MSG_DICT[wconn]['md5'].hexdigest().encode()) self.file_obj.close() else: print('\033[31;1m 文件不存在! \033[0m') self.OUTPUTS.remove(wconn) elif self.MSG_DICT[wconn]['comunicate_data']['action'] == 'put': if self.MSG_DICT[wconn]['user_stat']['task_step'] == 1: wconn.send(b'rspond_ok') self.OUTPUTS.remove(wconn) self.MSG_DICT[wconn]['user_stat']['task_step'] = 2 self.MSG_DICT[wconn]['user_stat']['file_flag'] = 0 self.file_put = open(self.MSG_DICT[wconn]['comunicate_data']['filename']+'%d.dat'%random.randint(1,10000), 'wb') elif self.MSG_DICT[wconn]['user_stat']['task_step'] == 2: try: data = self.MSG_DICT[wconn]['queue'].get_nowait() except queue.Empty as e: pass # self.OUTPUTS.remove(wconn) else: self.file_put.seek(self.MSG_DICT[wconn]['user_stat']['file_flag']) self.file_put.write(data) self.MSG_DICT[wconn]['user_stat']['file_flag'] += len(data) percentage = float( self.MSG_DICT[wconn]['user_stat']['file_flag'] / self.MSG_DICT[wconn]['comunicate_data']['size']) * 100 print('%.2f'%percentage) if self.MSG_DICT[wconn]['user_stat']['file_flag'] >= self.MSG_DICT[wconn]['comunicate_data']['size']: self.OUTPUTS.remove(wconn) self.MSG_DICT[wconn]['user_stat']['task_step'] = 0 print("上传成功") except KeyError as e: print('1 \033[31;1m [%s] 连接中断,中断原因 [%s] ,中断时间:[%s] \033[0m' % (repr(wconn.getpeername()), e, time.strftime('[%Y-%m-%d %H:%M:%S]', time.localtime()))) self.INPUTS.remove(wconn) if wconn in self.OUTPUTS: self.OUTPUTS.remove(wconn) del self.MSG_DICT[wconn] def excepthandle(self,econn): pass def interaction(self): while True: self.READ , self.WRITE ,self.EXCEPTION = select.select(self.INPUTS,self.OUTPUTS,self.INPUTS) for rconn in self.READ: self.connetion(rconn) for wconn in self.WRITE: self.sendable(wconn) for econn in self.EXCEPTION: self.excepthandle(econn) def initiate(self): pass def datahead(self,data,flag): if flag == 'send': return json.dumps(data).encode() elif flag == 'recv': return json.loads(data.decode()) else: print("调用出错") if __name__ == '__main__': server = SelectFTPServer()