欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

python selectors模块实现 IO多路复用机制的上传下载

程序员文章站 2022-05-26 22:15:40
import selectorsimport socketimport os,timeBASE_DIR = os.path.dirname(os.path.abspath(__file__))class Server: # sel = selectors.DefaultSelector() def ... ......

python selectors模块实现 IO多路复用机制的上传下载


import selectors
import socket
import os,time

base_dir = os.path.dirname(os.path.abspath(__file__))

class server:
    # sel = selectors.defaultselector()
    def __init__(self):
        self.ip_port=('127.0.0.1',8080)
        self.sel=selectors.defaultselector()
        #根据平台选择最佳的io多路机制,比如linux就会选择epoll

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

    def create_sock(self):
        sock = socket.socket()
        sock.bind(('localhost', 1234))
        sock.listen(100)
        # sock.setblocking(false)
        #注册监听对象,绑定accept
        self.sel.register(sock, selectors.event_read, self.accept
    def handle(self):
        while true:
            #sel监听sock变化,当sock实例化时,赋值给events,通过回调函数触发
            #key.data(key.fileobj,mask)  accept(sock,mask),
            #当有客户端连接时通过accept注册到read……
            events = self.sel.select()  # [sock,conn1,conn2]
            for key, mask in events:
                callback = key.data  # sel  accept  sel read
                callback(key.fileobj, mask)  #accept(sock,mask),read(conn1,mask)……
    def accept(self,sock, mask):
        print('登录服务端---')
        conn, addr = sock.accept()  # should be ready
        print('accepted', conn, 'from', addr)
        # conn.setblocking(false)
        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('utf8'))
                if cmd=='get':#下载
                    conn.send(str(self.dic[conn]['filesize']).encode('utf8'))
            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,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(1024)
            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()