python 网络编程 练习(二)---selectors实现FTP

需求:
使用SELECT或SELECTORS模块实现并发简单版FTP
允许多用户并发上传下载文件

流程图:
在这里插入图片描述
目录结构:
在这里插入图片描述

#server:
import os,time,socket,selectors
BASE_DIR=os.path.dirname(os.path.abspath(__file__))

class SelectFTPServer():
    def __init__(self):
        self.dic={}
        self.HasReceived=0
        self.sel=selectors.DefaultSelector()
        self.create_socket()
        self.handle()
    def create_socket(self):
        server=socket.socket()
        server.bind(('127.0.0.1',8080))
        server.listen(5)
        server.setblocking(False)
        self.sel.register(server,selectors.EVENT_READ,self.accept)
        print('server已开启,等待client连接')
    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('从%s来的连接:%s'%(addr,conn))
        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)
                cmd,filename,filesize=str(data,encoding='utf-8').split('|')
                self.dic={conn:{'cmd':cmd,'filename':filename,'filesize':int(filesize)}}
                if cmd=='put':
                    conn.send(bytes('ok',encoding='utf-8'))
                if cmd=='get':
                    file=os.path.join(BASE_DIR,'download',filename)
                    if os.path.exist(file):
                        FileSize=os.path.getsize(file)
                        SendInfo='%s|%s'%('yes',FileSize)
                        conn.send(bytes(SendInfo,encoding='utf-8'))
                    else:
                        SendInfo='%s|%s'%('no',0)
                        conn.send(bytes(SendInfo,encoding='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)
                    else:
                        print('error cmd')
                        conn.close()
        except Exception as e:
            print('error:%s'%e)
            self.sel.unregister(conn)
            conn.close()
    def put(self,conn):
        FileName=self.dic[conn]['filename']
        FileSize=self.dic[conn]['filesize']
        path=os.path.join(BASE_DIR,'upload',FileName)
        recv_data=conn.recv(1024)
        self.HasReceived+=len(recv_data)
        with open(path,'ab') as f:
            f.write(recv_data)
        if FileSize==HasReceived:
            if conn in self.dic.key:
                self.dic[conn]={}
            print('%s上传完毕'%FileName)
    def get(self,conn):
        FileName=self.dic[conn]['filename']
        path=os.path.join(BASE_DIR,'upload',FileName)
        with open(file,'rb') as f:
            seek(HasReceived)
            content=f.read(1024)
            recv_size=len(content)
            self.HasReceived+=recv_size
            self.sk.send(content)
            if FileSize==HasReceived:
                if conn in self.dic.key:
                    self.dic[conn]={}
                print('%s下载完毕'%FileName)
        
if __name__=='__main__':
    SelectFTPServer()
#client:
import socket,os,sys
BASE_DIR=os.path.dirname(os.path.abspath(__file__))

class SelectFTPClient():
    def __init__(self):
        self.args=sys.argv#命令行上输入的参数(文件路径,IP,端口)
        if len(self.args)>1:
            self.port=(self.args[1],int(self.args[2]))
        else:
            self.port=('127.0.0.1',8080)
        create_socket()
        command_fanout()
    def create_socket(self):
        try:
            self.sk=socket.socket()
            self.sk.connect(self.port)
            print('成功连接FTP Server')
        except Exception as e:
            print('error:%s'%e)
    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.sk.send(bytes(FileInfo,encoding='utf-8'))
            RecvStatus=self.sk.recv(1024)
            print('RecvStatus:%s'%RecvStatus)
            HasSend=0
            if str(RecvStatus,encoding='utf-8')=='ok':
                with open(file,'rb') as f:
                    while HasSend<FileSize:
                        conten=f.read(1024)
                        recv_size=len(content)
                        self.sk.cend(content)
                        HasSend+=recv_size
                        s=str(int(HasSend/FileSize*100))+'%'
                        print('正在上传文件%s,已上传%s'%(FileName,s))
                print('文件%s已上传完毕'%FileName)
        else:
            print('文件不存在')
    def get(self,cmd,file):
        FileName=file
        FileSize=0
        FileInfo='%s|%s|%s'%(cmd,FileName,FileSize)
        self.sk.send(bytes(FileInfo,encoding='utf-8'))
        Recv=self.sk.recv(1024)
        print('Recv:%s'%Recv)
        RecvStatus,FileSize=str(Recv,encoding='utf-8').split('|')
        HasReceived=0
        path=os.path.join(BASE_DIR,'download1',FileName)
        if str(RecvStatus)=='yes':
            with open(path,'ab') as f:
                while HasRecieved<FileSize:
                    recv_data=conn.recv(1024)
                    f.write(recv_data)
                    HasReceived+=len(recv_data)
                    s=str(int(HasRecieved/FileSize*100))+'%'
                    print('正在下载文件%s,已下载%s'%(FileName,s))
                print('文件%s已下载完毕'%FileName)

if __name__=='__main__':
    SelectFTPClient()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值