python 基于selectors库实现文件上传与下载
server.py
importselectors importsocket importos importtime BASE_DIR=os.path.abspath(os.path.dirname(__file__)) classselectFtpserver: def__init__(self): self.dic={}#创建空字典 self.hasReceived=0 self.hasSend=0 self.sel=selectors.DefaultSelector()#生成一个select对象 self.create_socket()#create_socket()是创建socket对象函数完成绑定功能 self.hanle()#handle()函数完成循环监听 defcreate_socket(self): sock=socket.socket() sock.bind(('127.0.0.1',8899)) sock.listen() sock.setblocking(False) self.sel.register(sock,selectors.EVENT_READ,self.accept)#把刚生成的sock连接对象注册到select连接列表中,并交给accept函数处理 print("服务端已打开,请连接客户端") defhanle(self): whileTrue: events=self.sel.select()#默认是阻塞,有活动连接就返回活动的连接列表 #这里看起来是select,其实有可能会使用epoll,如果你的系统支持epoll,那么默认就是epoll #print("event==",events) forkey,maskinevents: callback=key.data#去调accept函数 callback(key.fileobj,mask)#key.fileobj就是readable中的一个socket连接对象 defaccept(self,sock,mask): conn,addr=sock.accept()#Shouldbeready print('accepted',conn,'from',addr) conn.setblocking(False)#设定非阻塞 self.sel.register(conn,selectors.EVENT_READ,self.read)#新连接注册read回调函数 self.dic[conn]={}#在空字典里进行了conn赋值,self.dic={conn:{},} defread(self,conn,mask):#接收了conn和mask try:#加异常防止客户端突然断开 ifnotself.dic[conn]:#判断self.dic[conn]里面是否是空字典,如果是空字典,代表第一次进来 print('====第一次进来') data=conn.recv(1024)#conn接收了客户端发来的数据 print("data==",str(data,encoding='utf-8')) cmd,filename,filesize=str(data,encoding='utf-8').split('|')#把接收到客户端发来的包解开拿到cmd,filename,filesize个信息 self.dic={conn:{"cmd":cmd,"filename":filename,"filesize":int(filesize)}}#把拿到的cmd,filename,filesize信息放到self.dic字典里去后程序返回到handle()函数里的events继续监听 print(self.dic) ifcmd=='put':#如果接收的信息是put conn.send(bytes("OK",encoding='utf8'))#给客户端返回一条数据 ifself.dic[conn]['cmd']=='get': file=os.path.join(BASE_DIR,"upload",filename) ifos.path.exists(file): print("文件存在的情况,返回YES给客户端") filesize=os.path.getsize(file) self.dic[conn]['filesize']=filesize print("self.dic",self.dic) send_info='%s|%s'%('YES',filesize) conn.send(bytes(send_info,encoding='utf8')) else: print("文件不存在情况下") send_info='%s|%s'%('NO',0) conn.send(bytes(send_info,encoding='utf8')) self.dic[conn]={}#文件不存在的情况下,要将清空字典 else:#如果不是空字典代表不是第一次进来 print('不是第一次来的') print(self.dic) ifself.dic[conn].get('cmd',None):#对接收的命令进行分发判断是put还是get cmd=self.dic[conn].get('cmd') ifhasattr(self,cmd):#如果cmd=put调用put函数,如果是cmd=get函数调用get函数 func=getattr(self,cmd) func(conn) else: print("errorcmd!") conn.close() else: print("errorcmd!") conn.close() exceptExceptionase: print('断开的客户端信息是:',conn) self.sel.unregister(conn)#如果没有接收到数据做一个关闭解除 conn.close() #put上传函数 defput(self,conn): fileName=self.dic[conn]['filename'] fileSize=self.dic[conn]['filesize'] #print("BASE_DIR",BASE_DIR) path=os.path.join(BASE_DIR,"upload",fileName)#拿到要接收的信息 #print(fileName,fileSize,path) recv_data=conn.recv(1024)#接收客户端上传的数据1024字节 self.hasReceived+=len(recv_data)#把接收的数据累加到变量self.hasReceived withopen(path,'ab')asf:#打开文件 f.write(recv_data)#把接收的数据写到文件里去 iffileSize==self.hasReceived:#判断文件大小跟接收大小是否一样 ifconninself.dic.keys():#如果文件大小跟接收大小一样清空字典 self.dic[conn]={} self.hasReceived=0#S上传结束之后,需要将self.hasReceived重置成功 print("%s上传完毕!"%fileName) defget(self,conn): fileName=self.dic[conn]['filename'] file=os.path.join(BASE_DIR,"upload",fileName) #fileSize=os.path.getsize(file) fileSize=self.dic[conn]['filesize'] data=conn.recv(1024)#conn接收了客户端发来的数据 dataOK=str(data,encoding='utf-8') ifdataOK=='OK': withopen(file,'rb')asf:#打开文件 whilefileSize>self.hasSend:#循环的发送文件给客户端 contant=f.read(1024) recv_size=len(contant) conn.send(contant) self.hasSend+=recv_size s=str(int(self.hasSend/fileSize*100))+"%" print("正在下载文件:"+fileName+"已经下载:"+s) iffileSize==self.hasSend:#判断文件大小跟接收大小是否一样 ifconninself.dic.keys():#如果文件大小跟接收大小一样清空字典 self.dic[conn]={} print("%s下载完毕!"%fileName) self.hasSend=0 if__name__=='__main__': selectFtpserver()
client.py
importsocket importos,sys BASE_DIR=os.path.dirname(os.path.abspath(__file__)) classselectFtpClient: def__init__(self): self.args=sys.argv#sys.argv在命令行输入的参数,第一个参数默认文件名,第二个参数跟IP地址和端口 iflen(self.args)>1:#如果大于1把第二个参数俩个值赋值给port self.port=(self.args[1],int(self.args[2])) else: self.port=("127.0.0.1",8899)#如果没有第二个参数默认取这个 self.create_socket()# self.command_fanout()#进行命令分发 self.mainPath=os.path.join(BASE_DIR,'filename')#获取该客户端下的filename路径 #create_socket函数创建socket对象连接服务端 defcreate_socket(self): try: self.sk=socket.socket() self.sk.connect(self.port) print('连接FTP服务器成功!') exceptExceptionase: print("eroor:",e) #command_fanout()函数进行命令分发 defcommand_fanout(self): whileTrue: try: print("----------------welcometoftpclient-------------------") self.help_info() cmd_info=input('>>>请输入操作命令:').strip()#put12.pngimages ifnotcmd_info: continue cmd,file=cmd_info.split()##按照空格分隔 #print("命令是什么",cmds) ifcmd=="quit": break ifhasattr(self,cmd): func=getattr(self,cmd) func(cmd,file) Tag=input("是否继续进入ftpclinet,请选择Y/N:").strip() ifTag.upper()=='Y': continue else: break else: print('Nosuchcommand,pleasetryagain') exceptExceptionase:#server关闭了 print('%s'%e) break defhelp_info(self): print(''' get+(文件名)表示下载文件 put+(文件名)表示上传文件 quit表示退出登录 ''') #put()上传函数 defput(self,cmd,file): ifos.path.isfile(file):#判断本地文件是否存在 fileName=os.path.basename(file)#取出文件的名字 fileSize=os.path.getsize(file)#取出文件的大小 fileInfo='%s|%s|%s'%(cmd,fileName,fileSize)#给文件名字大小打包成fileInf self.sk.send(bytes(fileInfo,encoding='utf8'))#调用send方法把fileInf发给服务端 recvStatus=self.sk.recv(1024)#接收服务端返回的OK内容 print('recvStatus',recvStatus) hasSend=0 ifstr(recvStatus,encoding='utf8')=="OK":#如果接收到服务端返回的OK withopen(file,'rb')asf:#打开文件 whilefileSize>hasSend:#循环的去上传文件 contant=f.read(1024) recv_size=len(contant) self.sk.send(contant) hasSend+=recv_size s=str(int(hasSend/fileSize*100))+"%" print("正在上传文件:"+fileName+"已经上传:"+s) print('%s文件上传完毕'%(fileName,)) else: print('要上传的文件不存在') #get()下载函数 defget(self,cmd,fileName): path=os.path.join(BASE_DIR,"download",fileName)#拿到要接收的信息 fileSize=0 fileInfo='%s|%s|%s'%(cmd,fileName,fileSize)#给文件名字大小打包成fileInf print(fileInfo) self.sk.send(bytes(fileInfo,encoding='utf8'))#调用send方法把fileInfo发给服务端 recvdata=self.sk.recv(1024)#接收服务端返回的是否存在文件内容 recvStatus,fileSize=str(recvdata,encoding='utf-8').split('|') print("recvStatus==",recvStatus,fileSize) fileSize=int(fileSize) hasReceived=0 ifrecvStatus=="YES":#如果接收到服务端返回的YES self.sk.send(bytes('OK',encoding='utf8'))#通知服务端可以正常下载了 whilefileSize>hasReceived:#循环的发送文件给客户端 recv_data=self.sk.recv(1024)#接收客户端上传的数据1024字节 hasReceived+=len(recv_data)#把接收的数据累加到变量self.hasReceived print("hasReceived",hasReceived) withopen(path,'ab')asf:#打开文件 f.write(recv_data)#把接收的数据写到文件里去 iffileSize==hasReceived:#判断文件大小跟接收大小是否一样 print("%s下载完毕!"%fileName) recvStatus='YESS' else: print('要下载的文件不存在') if__name__=='__main__': selectFtpClient()
以上就是python基于selectors库实现文件上传与下载的详细内容,更多关于python上传下载的资料请关注毛票票其它相关文章!