使用IO多路复用selectors模块写上传下载功能

import selectors
import socket
import struct
import json
import os,sys
BASEDIR = os.path.dirname(__file__)

class Server:
    def __init__(self):
        self.dic = {}
        self.sel = selectors.DefaultSelector()
        self.makesock()
        self.handle()

    def makesock(self):
        sock = socket.socket()
        sock.bind(('127.0.0.1',8099))
        sock.listen(5)
        sock.setblocking(False)
        self.sel.register(sock,selectors.EVENT_READ,self.accept)

    def handle(self):
        while True:
            event = self.sel.select()
            for key,mask in event:
                func = key.data
                func(key.fileobj,mask)

    def accept(self,sock,mask):
        conn,addr = sock.accept()
        self.sel.register(conn,selectors.EVENT_READ,self.read)
        self.dic[conn] = {}

    def read(self,conn,mask):
        if not self.dic[conn]:
            try:
                length = struct.unpack('i',conn.recv(4))[0]
                cmd = json.loads(conn.recv(length).decode('utf8'))
            except Exception as e:
                print(e)
                conn.close()
                self.sel.unregister(conn)
                return
            if cmd['action'] == 'put':

                conn.send(b'0')
                f = open(os.path.basename(cmd['filename']),'wb')
                if not cmd['filesize']:
                    f.close()
                    return
                self.dic[conn] = cmd
                self.dic[conn]['data_len'] = 0
                self.dic[conn]['file'] = f
            elif cmd['action'] == 'get':
                path = os.path.join(BASEDIR,cmd['filename'])
                if os.path.exists(path) and os.path.isfile(path):
                    filesize = os.path.getsize(path)
                    # print(filesize)
                    if filesize:
                        f = open(path,'rb')
                        self.dic[conn] = cmd
                        self.dic[conn]['file'] = f
                        conn.send(b'2')
                        conn.send(str(filesize).encode('utf8'))
                    else:
                        conn.send(b'1')
                else:
                    conn.send(b'0')
        else:
            if hasattr(self,self.dic[conn]['action']):
                func = getattr(self,self.dic[conn]['action'])
                func(conn)

    def get(self,conn):

        data = self.dic[conn]['file'].read(1024)
        if not data:
            self.dic[conn]['file'].close()
            self.dic[conn] = {}
            return
        status = conn.recv(1)
        conn.send(data)

    def put(self,conn):
        if self.dic[conn]['data_len'] == self.dic[conn]['filesize']:
            self.dic[conn]['file'].close()
            self.dic[conn] = {}
            return
        data = conn.recv(1024)
        self.dic[conn]['file'].write(data)
        self.dic[conn]['data_len'] += len(data)

if __name__ == '__main__':
    Server()
import socket
import struct
import json
import os,sys

class Client:
    def __init__(self,ip_port):
        self.ip_port = ip_port
        self.makeconn()
        self.handle()

    def makeconn(self):
        self.conn = socket.socket()
        self.conn.connect(self.ip_port)

    def handle(self):
        while True:
            cmd = input(">>>")
            cmd = cmd.split()
            if hasattr(self,cmd[0]):
                func = getattr(self,cmd[0])
                func(*cmd)

    def jindu(self,size,filesize):
        baifen_len = size / filesize
        baifen = int(baifen_len * 100)
        isok = 0
        if baifen == 100:
            r = '
%s>%d%%
' % ('=' * baifen, baifen,)
            isok =  1
        else:
            r = "
%s>%d%%"%('='*baifen,baifen,)
        sys.stdout.write(r)
        sys.stdout.flush
        return isok

    def get(self,*cmd):
        data = {
            "action" : "get",
            "filename" : cmd[1]
        }
        data = json.dumps(data).encode('utf8')
        length = struct.pack('i',len(data))
        self.conn.send(length)
        self.conn.send(data)
        status = self.conn.recv(1).decode('utf-8')
        if status == '0':
            print("文件不存在")
            return
        f = open(os.path.basename(cmd[1]),'wb')
        if status == '1':
            f.close()
            return
        filesize = self.conn.recv(1024).decode('utf8')
        filesize = int(filesize)
        file_len = 0
        while True:
            self.conn.send(b'0')
            file_data = self.conn.recv(1024)
            file_len += len(file_data)
            f.write(file_data)
            if self.jindu(file_len,filesize):
                f.close()
                break

    def put(self,*cmd):
        data = {
            "action": "put",
            "filename": cmd[1],
        }
        if os.path.exists(cmd[1]) and os.path.isfile(cmd[1]):
            filesize = os.path.getsize(cmd[1])
            data['filesize'] = filesize
            data = json.dumps(data).encode('utf8')
            length = struct.pack('i', len(data))
            self.conn.send(length)
            self.conn.send(data)
            status = self.conn.recv(1)
            data_len = 0
            with open(cmd[1],'rb') as f:
                while True:
                    data = f.read(1024)
                    if not data: return
                    self.conn.send(data)
                    data_len += len(data)
                    if self.jindu(data_len, filesize):
                        break
        else:
            print("文件不存在")
            return



if __name__ == '__main__':
    c = Client(('127.0.0.1',8099))
    c.handle()
原文地址:https://www.cnblogs.com/xieys-1993/p/11724170.html