Python案例-网络编程-FTP&断点续传&进度条&上传下载
来源:互联网 发布:js设置fontsize 编辑:程序博客网 时间:2024/06/03 18:46
本次ftpV2,完善了上次未完成的代码,实现上传下载,断点续传,客户端任务进度条等功能
废话不多说,上代码,详细解释,请查看代码注释
Server端
#!/usr/bin/env python# --coding = utf-8# Author Allen Leeimport socketserver,json,osimport subprocess#创建ftpserver类,并继承socktserver,借用其io多路复用的select方法,以实现多响应用户的并发class Myftp(socketserver.BaseRequestHandler): #再次重写handle方法,由于类的继承中,self遵循自下而上,从左到右的寻址规则,因此被重写的方法将优先被调用 def handle(self): #权限控制 while True: if not self.checkuser(): break else: self.request.sendall(bytes('welcome to myftp',encoding='utf-8')) while True: res_data = self.request.recv(1024).strip() if not res_data: break #再次统一处理client端发出的json包, res_msg = json.loads(str(res_data,encoding='utf-8')) #通过反射来引导用户到对应的方法中 res_tag = res_msg.get('action') if hasattr(self,res_tag): getattr(self,res_tag)(res_msg) else:break self.request.close() #用户验证 def checkuser(self): server_tag = False res = self.request.recv(1024) if len(res) == 0: return error userinfo = json.loads(str(res,encoding='utf-8')) if userinfo[0].get('username') == 'username' and userinfo[0].get('password') == 'password': server_tag = True return True else: return False def put(self,res_msg): file_name = res_msg.get('file_name') file_size = res_msg.get('file_size') ret = os.path.isfile(file_name) if not ret: #此为正常传输 with open(file_name,'wb+')as f: self.request.sendall(bytes('ok',encoding='utf-8')) recv_data = self.request.recv(1024) f.write(recv_data) else: #此为断点续传处理 with open(file_name,'ab+')as f: file_newsize = len(file_name) self.request.sendall(bytes('continue|%s'%(file_newsize), encoding='utf-8')) recv_data = self.request.recv(1024) f.write(recv_data) def get(self,res_msg): file_name = res_mas.get('file_name') ret = os.path.isfile(file_name) if not ret: print('this file is not exists') return False else: total_size =os.stat(file_name).st_size with open(file_name,'rb')as f: self.request.sendall(bytes('ready|%d'%(total_size),encoding='utf-8')) reg = str(self.request.recv(1024),encoding='utf-8') if reg.startswith('ok'): new_size = 0 for line in f: client.sendall(bytes(line,encoding='utf-8')) new_size += len(line) if new_size >= total_size:break if reg.startswith('continue'): new_size = reg.split('|')[1] #使用seek方法来实现将文件指针放在上次断点处,并继续传输,进而完成断点续传的功能,第一个参数表示指针偏移位数,第二个参数表示,从文件开头开偏移 f.seek(new_size,0) for line in f: client.sendall(bytes(line,encoding='utf-8')) new_size +=len(line) if new_size >= total_size:break #次方法为处理寻常请求,用户可以在这里实现切换目录、删除文件、创建目录、等等 def cmd(self,res_msg): cmd = res_msg.get("cmd") result = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE) ret = result.stdout.read() if not ret: send_data = 'there is no such commons' print(send_data) else: send_data = bytes(ret,encoding='utf-8') self.request.sendall('ready|%s'%(len(send_data))) ret = str(self.request.recv(1024),encoding=utf-8) if ret == 'start': self.request.sendall(send_data)if __name__ == '__main__': #创建对象时使用ThreadindTCP,来实现多线程的处理 ftpserver = socketserver.ThreadingTCPServer(('127.0.0.1', 9909), Myftp) ftpserver.serve_forever()
Client端
#!/usr/bin/env python# --coding = utf-8# Author Allen Leeimport socket, os, json,sysclass Myclient(): #在构造方法中启动client的socket对象以及连接server端 def __init__(self): self.client = socket.socket() self.client.connect(('127.0.0.1', 9909)) #run为client的主方法,其中通过对用户输入的命令来判断具体操作,并通过反射将其引导到对应的方法 def run(self): while True: #权限控制 check = self.login() #通过while循环实现用户输入代码的复用 while True: res_data = self.client.recv(1024).strip() if not res_data:break print(str(res_data, encoding='utf-8')) send_data = input('>> : ').strip() if not send_data: continue if hasattr(self,send_data): getattr(self,send_data)(send_data) #当用户输入的不是指定的put get方法时,将被引致平常的cmd命令行,在此可以完成切换目录、创建文件、删除文件 else: getattr(self,'cmd')(send_data) self.client.close() #用户登录验证 def login(self): self.tag = False for i in range(3): username = input('please input your username:') passwd = input('please input your passwd:') password = commons.md5(passwd) userinfo = {"username":username,"password":password } self.client.send(bytes(json.dumps(userinfo),encoding='utf-8')) ret = self.client.recv(1024) res_check = str(ret,encoding='utf-8') if res_check == 'ok': self.tag = True return True else: return False print("your username or passwd is wrong") self.client.close() def put(self,send_data): pathh = input('input the file `s path ;') #首先判断文件是否存在,通过os.path.isfile来实现 ret = os.path.isfile(pathh) if not ret: print('the file is not exists') return False #如果存在,则将操作类型、文件名、文件大小以字典形势格式化,再以json的方法进行格式化 else: #通过os.stat方法来取文件的大小 file_size = os.stat(pathh).st_size file_name = pathh.split('\\')[-1] send_msg = {"action":send_data, "filename":file_name, "filesize":file_size, } self.client.sendall(bytes(json.dumps(send_msg),encoding='utf-8')) res_tag = self.client.recv(1024) if not res_tag: return False if str(res_tag,encoding='utf-8').startswith('ok'): #上传文件只用r就够了 with open(pathh,'rb') as f: new_size = 0 for line in f: self.client.sendall(bytes(line,encoding='utf-8')) new_size += len(line) #以下为实现传输文件时,显示当前进度条 ret = new_size/file_size num = int(ret*100) view = '\r [%-100s]%d%%'%("="*num,100,) sys.stdout.write(view) sys.stdout.flush() if new_size >= file_size: break if str(res_tag,encoding='utf-8').startswith('continue'): with open(pathh, 'rb') as f: #此处使用seek来进行文件指针的偏移,进而完成断点续传的功能 file_newsize=str(res_tag,encoding='utf-8').split('|')[1] f.seek(file_name,0) for line in f: self.client.sendall(bytes(line,encoding='utf-8')) new_size += len(line) #以下为实现传输文件时,显示当前进度条 ret = new_size/file_size num = int(ret*100) #以下使用了sys模块的标准输出 view = '\r [%-100s]%d%%'%("="*num,100,) sys.stdout.write(view) sys.stdout.flush() if new_size >= file_size: break def get(self,send_data): get_name = input('input what your want:').strip() if not get_name: return False send_msg = {"action":send_data, "filename":get_name } self.client.sendall(bytes(json.dumps(send_msg),encoding='utf-8')) res_data = self.client.recv(1024) res_tag = str(res_data,encoding='utf-8') #客户端接收到服务端的确认信息ready之后开始传输,相当于tcp的三次握手中的ack包 if res_tag.startswith('ready'): #通过判断本地是否有此文件,来确认是否启用断点续传 if not os.path.isfile(get_name): with open(file_name,'wb')as f: self.client.sendall(bytes('start', encoding='utf-8')) total_size = res_data.split('|')[1] new_size = 0 while new_size <total_size: res_data = self.client.recv(1024) new_size += len(res_data) f.write(res_data) #以下为下载文件的进度条实现 ret = new_size/total_size num = int(ret*100) view = '\r [%-100s]%d%%'%('='*num,100) sys.stdout.write(view) sys.stdout.flush() else: #如果本地不存在此文件将给服务端发送,断点续传的请求标签 with open(file_name,'ab')as f: new_size = os.stat(file_name).st_size self.client.sendall(bytes('continue|%d'%(new_size), encoding='utf-8')) total_size = res_data.split('|')[1] while new_size <total_size: res_data = self.client.recv(1024) new_size += len(res_data) f.write(res_data) #以下为下载文件的进度条实现 ret = new_size/total_size num = int(ret*100) view = '\r [%-100s]%d%%'%('='*num,100) sys.stdout.write(view) sys.stdout.flush() def cmd(self,send_data): send_msg = {"action":'cmd', "cmd":send_data, } self.client.sendall(bytes(json.dumps(send_msg), encoding='utf-8')) res_data = self.client.recv(1024) res_tag = str(res_data, encoding='utf-8') if res_tag.startswith('ready'): self.client.sendall(bytes('start', encoding='utf-8')) #以下为解决发送命令过程中出现的粘报现象,思路为提前告诉对方总大小 total_size = res_data.split('|')[1] new_size = 0 while new_size < total_size: res_data = self.client.recv(1024) new_size += len(res_data) print(str(res_data, encoding='utf-8')) def client_exit(self): self.client.close()if __name__ == '__main__': Myclient.run()
具体一些bug还未调试,主题代码思路已经实现
0 0
- Python案例-网络编程-FTP&断点续传&进度条&上传下载
- python ftp上传下载文件,支持断点续传
- Python案例-网络编程-socket-Ftp&多用户登录
- FTP上传下载的断点续传实现
- c#上传下载ftp(支持断点续传)
- c#上传下载ftp(支持断点续传)
- c#上传下载ftp(支持断点续传)
- FTP上传下载的断点续传实现
- c#上传下载ftp(支持断点续传)
- FTP上传下载的断点续传实现
- c#上传下载ftp(支持断点续传)
- C# 上传下载ftp(支持断点续传)
- ftp图片上传下载带进度条
- java实现FTP多线程断点续传,上传下载!
- java实现FTP多线程断点续传,上传下载
- java实现FTP多线程断点续传,上传下载!
- C# FTP上传下载(支持断点续传)
- C# 上传下载ftp(支持断点续传) 一
- php数据类型以及判断isset或者empty使用
- C++动态类型转换、强制类型转换、静态类型转换举例分析
- 2016/07/16 《jquery仿新浪微博新版搜索下拉特效》学习笔记一
- int 负数最小值
- 随机数发生器
- Python案例-网络编程-FTP&断点续传&进度条&上传下载
- 4.1.3求值器数据结构
- 爬虫实战:提取人和老鼠中RNA表达性较好的RNA序列
- PHP中使用substr()截取字符串出现中文乱码
- c语言 ascii 和 压缩bcd 码之间的相互转换
- 在scanf里面使用换行符\n是一种什么体验?scanf("%d\n",&a);
- J2EE进阶(六)SSH框架工作流程项目整合实例讲解
- 12. Integer to Roman
- 图像特征提取(类似于综述)