基于Selectors的简单FTP

服务端

import os
import selectors
import socket
class Select_server():
    Base_dir=os.path.dirname(os.path.abspath(__file__))
    def __init__(self):
        self.dic={}
        self.hasreceived=0
        self.sel=selectors.DefaultSelector()
        self.creat_socket()
        self.handle()

    def creat_socket(self):
        server=socket.socket()
        server.bind(('localhost',8080))
        server.listen(5)
        server.setblocking(0)
        self.sel.register(server,selectors.EVENT_READ,self.accept)
        print('开始连接...')

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

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

    def read(self,conn,mask):
        try:
            if not self.dic[conn]:
                fileInfo=conn.recv(1024)
                cmd,filename,filesize=str(fileInfo,encoding='utf8').split('|')
                if hasattr(self,cmd):
                    if cmd=='put':
                        conn.send(bytes('OK,服务端准备好上传文件%s'%filename,encoding='utf8'))
                        self.dic[conn]={'cmd':cmd,'filename':filename,'filesize':int(filesize)}
                    elif cmd=='get':
                        file=os.path.join(self.Base_dir,'download',filename)
                        if os.path.exists(file):
                            filesize=os.path.getsize(file)
                            conn.send(bytes('OK|%s'%filesize,encoding='utf8'))
                            self.dic[conn]={'cmd':cmd,'filename':filename}
                        else:
                            conn.send('NO'.encode('utf8'))
                    else:
                        conn.send('WRONG,错误的指令,请重新输入指令'.encode('utf8'))
                else:
                    conn.send('WRONG,错误的指令,请重新输入指令'.encode('utf8'))
            else:
                func=getattr(self,self.dic[conn].get('cmd'))
                func(conn)
        except Exception as e:
            print(e)
            self.sel.unregister(conn)
            conn.close()

    def put(self,conn):
        filename=self.dic[conn].get('filename')
        filesize=self.dic[conn].get('filesize')
        path=os.path.join(self.Base_dir,'upload',filename)
        try:
            data=conn.recv(1024)
            self.hasreceived+=len(data)
            with open(path,'ab') as f:
                f.write(data)
            if self.hasreceived==filesize:
                if conn in self.dic.keys():
                    self.dic[conn]={}
                    self.hasreceived=0
                    print('%s上传完毕'%filename)
            return
        except Exception as e:
            print(e)
            self.sel.unregister(conn)
            conn.close()

    def get(self,conn):
        filename=self.dic[conn].get('filename')
        filesize=self.dic[conn].get('filesize')
        path=os.path.join(self.Base_dir,'download',filename)
        data=conn.recv(1024)
        with open(path,'rb') as f:
            for line in f:
                conn.send(line)
            self.dic[conn]={}
            print('文件下载完毕!')


if __name__ == '__main__':
    Select_server()



客户端
import socket
import sys
import os
class Select_Client():
    Base_dir=os.path.dirname(os.path.abspath(__file__))
    def __init__(self):
        arg=sys.argv
        if len(arg)>2:
            self.ip=(arg[1],int(arg[2]))
        else:
            self.ip=(('218.197.223.92',8080))
        if self.creat_socket():
            self.handle()

    def creat_socket(self):
        self.sk=socket.socket()
        try:
            self.sk.connect(self.ip)
            print('成功连接到服务端',self.ip)
            return True
        except Exception as e:
            print('Error',e)
            print('请重启客户端')
            return False

    def handle(self):
        while True:
            print('请输入指令')
            data=input('>>:').strip()
            if data=='exit()':exit()
            cmd,path=data.split(' ',1)
            if hasattr(self,cmd):
                func=getattr(self,cmd)
                func(cmd,path)
            else:
                print('无效的指令,请重新输入')

    def put(self,cmd,path):
        try:
            filename=os.path.basename(path)
            filesize=os.path.getsize(path)
        except Exception as e:
            print(e)
            return
        fileInfo='%s|%s|%s'%(cmd,filename,filesize)
        self.sk.send(fileInfo.encode('utf8'))
        message=self.sk.recv(1024).decode('utf8')
        print(message)
        if 'OK' in message:
            hassend=0
            with open(path,'rb') as f:
                while hassend<filesize:
                    data=f.read(1024)
                    self.sk.send(data)
                    hassend+=len(data)
                    rate=hassend/filesize*100
                    sys.stdout.write('\r %.2f%% %s'%(rate,'*'*int(rate)))#\r将指针指向开头,所以每次都会覆盖输出
            print('\n%s上传成功'%filename)
        else:
            return

    def get(self,cmd,filename):
        self.sk.send(bytes('%s|%s|0'%(cmd,filename),encoding='utf8'))
        message=self.sk.recv(1024).decode('utf8')
        if 'OK' in message:
            self.sk.send(b'Ready')
            print('OK,服务端准备好下载文件%s'%filename)
            filesize=int(message.split('|')[1])
            path=os.path.join(self.Base_dir,'download',filename)
            hasreceived=0
            with open(path,'wb') as f:
                while hasreceived<filesize:
                    data=self.sk.recv(1024)
                    f.write(data)
                    hasreceived+=len(data)
                    rate=hasreceived/filesize*100
                    sys.stdout.write('\r%.2f%% %s'%(rate,'*'*int(rate)))
            print('\n%s下载成功'%filename)
        else:
            print('文件%s不存在,请重新输入指令'%filename)
            return


if __name__ == '__main__':
    Select_Client()





猜你喜欢

转载自blog.csdn.net/henry_lv/article/details/80149481