使用IO多路复用实现FTP上传下载

 

服务端

import  time,os,selectors
from socket import  *
BASE_DIR = os.path.dirname(os.path.abspath(__file__))

class Server:
    def __init__(self):
        self.ip_port = ("127.0.0.1",8001)
        self.sel = selectors.DefaultSelector()#根据平台选择最佳的IO多路机制,比如linux就会选择epoll

        self.dic = {}
        self.create_sock()
        self.handle()

    def create_sock(self):
        sk = socket(AF_INET,SOCK_STREAM)
        sk.bind((self.ip_port))
        sk.setblocking(False)
        sk.listen(5)
        self.sel.register(sk,selectors.EVENT_READ,self.accept)#注册监听对象
    def handle(self):
        while True:
            events = self.sel.select() ##监听谁发生变化了

            for key,mask in events:
                func = key.data  #获取对象调用的函数
                func(key.fileobj,mask)
    def accept(self,sock,mask):
        print("登录服务端")
        conn ,addr = sock.accept()
        #data = conn.recv(1024)
        self.sel.register(conn,selectors.EVENT_READ,self.read)
        self.dic[conn] = {}

    def read(self,conn,mask):
        try:
            if  not self.dic[conn]:

                data = conn.recv(1024)
                try:
                    cmd ,filename ,filesize =str(data.decode("utf-8")).split("|")
                    self.dic[conn] = {"cmd": cmd, "filename": filename, "filesize": filesize, "hasReceived": 0}
                except Exception as e:
                    cmd, filename= str(data.decode("utf-8")).split("|")
                    self.dic[conn] = {"cmd": cmd, "filename": filename,"filesize":os.path.getsize(os.path.join(BASE_DIR,"load",filename)),
                                      "hasSended": 0}


                if cmd == "put": #上传
                    conn.send("ok".encode("utf-8"))
                if cmd =="get":#下载
                    conn.send(str(self.dic[conn]["filesize"]).encode("utf-8"))


            else:


                if self.dic[conn].get("cmd",None):

                    cmd = self.dic[conn].get("cmd")
                    if hasattr(self,cmd):
                        func = getattr(self,cmd)
                        func(conn,mask)
                    else:
                        print("error")
        except Exception as e:
            print(e)
            print(conn,"断开连接")
            conn.close()
            self.sel.unregister(conn)

    def put(self,conn,mask):

        filename = self.dic[conn]['filename']
        filesize = self.dic[conn]['filesize']

        path = os.path.join(BASE_DIR, "upload", filename)
        data = conn.recv(1024)
        conn.send("success".encode("utf-8"))
        self.dic[conn]['hasReceived']+=len(data)
        with open(path,"ab") as f:
            f.write(data)
        if self.dic[conn]['hasReceived'] == self.dic[conn]['filesize']:
            self.dic[conn] = {}
            print("上传结束")
    def get(self,conn,mask):

        filename = self.dic[conn]['filename']
        path = os.path.join(BASE_DIR,"load",filename)

        with open(path, "rb") as f:

            f.seek(self.dic[conn]["hasSended"],0)
            data = f.read(10)
            conn.send(data)
            self.dic[conn]['hasSended']+=len(data)
            if self.dic[conn]['hasSended'] ==self.dic[conn]["filesize"]:

                self.dic[conn]={}
                print("下载结束")
        time.sleep(0.5)

if __name__ == "__main__":
    Server()

 

 

 

客户端

import  os,time,sys
BASE_DIR =os.path.dirname(os.path.abspath(__file__))

import socket
import selectors
class selectFtpClient:
    def __init__(self):

        self.port = ("127.0.0.1",8001)
        self.create_socket()
        self.command_fanout()

    def create_socket(self):
        try:
            self.sock = socket.socket()
            self.sock.connect(self.port)
            print("连接FTP成功!")
        except Exception :
            print("连接失败!")
    def command_fanout(self):
        while True:
            cmd = input(">>>").strip()
            if cmd == "exit()":
                break
            cmd,file=cmd.split()
            if hasattr(self,cmd):
                func = getattr(self,cmd)
                func(cmd,file)
            else:
                print('调用错误!')
    #上传
    def put(self,cmd,file):
        if os.path.isfile(file):
            fileName = os.path.basename(file)
            fileSize = os.path.getsize(file)
            fileInfo = "%s|%s|%s"%(cmd,fileName,fileSize)
            self.sock.send(bytes(fileInfo,encoding="utf-8"))
            recvStatus = self.sock.recv(1024)
            hasSend = 0
            if str(recvStatus,encoding="utf-8") =='ok':
                with open(file,"rb") as f:
                    while fileSize >hasSend:
                        contant = f.read(10)
                        recv_size = len(contant)
                        self.sock.send(contant)
                        hasSend+=recv_size
                        s = str(int(hasSend/fileSize*100))+"%"
                        print("正在上传文件:"+fileName+"   已经上传:  "+s)
                        time.sleep(0.5)
                print("%s文件上传完毕"%(fileName,))
            else:
                print("文件不存在")


#下载
    def get(self,cmd,file):

        fileInfo = "%s|%s"%(cmd,file)
        self.sock.send(bytes(fileInfo,encoding="utf-8"))
        filesize = int(self.sock.recv(10).decode("utf-8"))

        f = open(file,"ab")
        i=0
        while i<filesize:
            self.sock.send("ok".encode("utf-8"))
            data = self.sock.recv(10)
            f.write(data)
            i+=len(data)
            s = str(int(i / filesize * 100)) + "%"
            print("正在上传文件:" + file + "   已经下载:  " + s)

        print("下载完成")
        f.close()



if __name__ == "__main__":
    selectFtpClient()

 

使用IO多路复用实现FTP上传下载
标题