python:基于select的sokct ftp 服务端

#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()

 

posted @ 2019-08-22 20:52  Forever_eif  阅读(196)  评论(0编辑  收藏  举报