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上传下载的资料请关注毛票票其它相关文章!