python ftp的断点上传
- 格式:pdf
- 大小:50.05 KB
- 文档页数:2
Python使⽤sftp实现上传和下载功能在Python中可以使⽤paramiko模块中的sftp登陆远程主机,实现上传和下载功能。
1.功能实现1、根据输⼊参数判断是⽂件还是⽬录,进⾏上传和下载2、本地参数local需要与远程参数remote类型⼀致,⽂件以⽂件名结尾,⽬录以\结尾3、上传和下载的本地和远程⽬录需要存在4、异常捕获2.代码实现#!/usr/bin/python# coding=utf-8import paramikoimport osdef sftp_upload(host,port,username,password,local,remote):sf = paramiko.Transport((host,port))sf.connect(username = username,password = password)sftp = paramiko.SFTPClient.from_transport(sf)try:if os.path.isdir(local):#判断本地参数是⽬录还是⽂件for f in os.listdir(local):#遍历本地⽬录sftp.put(os.path.join(local+f),os.path.join(remote+f))#上传⽬录中的⽂件else:sftp.put(local,remote)#上传⽂件except Exception,e:print('upload exception:',e)sf.close()def sftp_download(host,port,username,password,local,remote):sf = paramiko.Transport((host,port))sf.connect(username = username,password = password)sftp = paramiko.SFTPClient.from_transport(sf)try:if os.path.isdir(local):#判断本地参数是⽬录还是⽂件for f in sftp.listdir(remote):#遍历远程⽬录sftp.get(os.path.join(remote+f),os.path.join(local+f))#下载⽬录中⽂件else:sftp.get(remote,local)#下载⽂件except Exception,e:print('download exception:',e)sf.close()if __name__ == '__main__':host = '192.168.1.2'#主机port = 22 #端⼝username = 'root' #⽤户名password = '123456' #密码local = 'F:\\sftptest\\'#本地⽂件或⽬录,与远程⼀致,当前为windows⽬录格式,window⽬录中间需要使⽤双斜线remote = '/opt/tianpy5/python/test/'#远程⽂件或⽬录,与本地⼀致,当前为linux⽬录格式sftp_upload(host,port,username,password,local,remote)#上传#sftp_download(host,port,username,password,local,remote)#下载3.总结以上代码实现了⽂件和⽬录的上传和下载,可以单独上传和下载⽂件,也可以批量上传和下载⽬录中的⽂件,基本实现了所要的功能,但是针对⽬录不存在的情况,以及上传和下载到多台主机上的情况,还有待完善。
python实现断点续传下载⽂件最近的任务⾥有⼀个功能是要我从⽇志服务器实时跟新⽇志到本地,⽇志在不断新增内容就需要我隔⼀段时间从上次下载的位置继续下载,并写⼊本地⽂件上次写完的位置后⾯。
[python]1. headers = {'Range': 'bytes=%d-' % local_file_dict.get(packet_path+k)}2. web_log = requests.get(packet_web_path+k, stream=True, headers=headers)3. with open(packet_path+k, 'ab') as local_file:4. for chunk in web_log.iter_content(chunk_size=1024):5. if chunk:6. local_file.write(chunk)7. local_file.flush()这⾥⽤的是requests.get()和他的⼀些参数[python]1. requests.get(url, stream=True, headers=headers)要实现断点续传,get()的stream参数要设为True在远程打开的是⼀个流,⽽headers⾥放的是续传的⼀些参数,这⾥的[python]1. headers = {'Range': 'bytes=%d-' % local_file_size}就是获得本地⽂件的⼤⼩作为续传的起点,还有就是按bytes然后以[python]1. iter_content(chunk_size=xxx)的⽅式逐chunk_size地遍历数据,并写⼊local_file[python]1. local_file.flush()刷新也很重要,实时保证⼀点点的写⼊。
python--简单的⽂件断点续传实例⼀、程序说明1、⽂件上传⽬标路径:home/file2、⽬标⽂件:putfile.png3、服务端代码:put_server.py4、客户端代码:put_client.py⼆、各部分代码1、服务端代码:put_server.py1#!/usr/bin/env python2# -*- coding:utf-8 -*-3"""4实现⽂件断点续传的服务器端5"""67import socket8import os910 BASE_DIR = os.path.dirname(os.path.dirname(__file__))1112 home = os.path.join(BASE_DIR, "home/file")13 sk = socket.socket()14 sk.bind(('127.0.0.1', 8001))15 sk.listen(5)1617while True:18print("Waiting....")19 conn, addr = sk.accept()20 conn.sendall(bytes('欢迎登录', encoding='utf-8'))21 flag = True22while flag:23 client_bytes = conn.recv(1024) #接收客户端发送过来的内容24 client_str = str(client_bytes, encoding='utf-8') #将内容转换成字符串2526# 将客户端发送过来的内容以"|"拆分为:命名⽅法,⽂件名,⽂件⼤⼩,⽬标路径27 func, file_name, file_byte_size, targe_path = client_str.split('|', 3)28 file_byte_size = int(file_byte_size)29 path = os.path.join(home, file_name)30 has_received = 03132#⾸先判断该路径下是否已存在⽂件33if os.path.exists(path):34 conn.sendall(bytes("2003", encoding='utf-8')) #发送通知客户端,该⽂件已存在35 is_continue = str(conn.recv(1024), encoding='utf-8') #等待客户端选择回复36if is_continue == "2004":37 has_file_size = os.stat(path).st_size38 conn.sendall(bytes(str(has_file_size), encoding='utf-8')) #将已接收的⽂件⼤⼩给客户端39 has_received += has_file_size40 f = open(path, 'ab')41else:42 f = open(path, 'wb')43else:44 conn.sendall(bytes("2002", encoding='utf-8'))45 f = open(path, 'wb')4647while has_received < file_byte_size:48try:49 data = conn.recv(1024)50if not data:51raise Exception52except Exception:53 flag = False54break55 f.write(data)56 has_received += len(data)57print("⽂件已接收完成!")58 f.close()2、客户端代码:put_client.py1#!/usr/bin/env python2# -*- coding:utf-8 -*-3"""4实现⽂件断点续传的客户端5"""67import socket8import sys9import re10import os11 FILE_DIR = os.path.dirname(__file__)1213 ck = socket.socket()14 ck.connect(('127.0.0.1', 8001))15print(str(ck.recv(1024), encoding='utf-8'))161718#定义⼀个函数,计算进度条19def bar(num = 1, sum = 100):20 rate = float(num) / float(sum)21 rate_num = int(rate * 100)22 temp = '\r%d %%' % (rate_num)23 sys.stdout.write(temp)2425while True:26 inp = input('请输⼊(内容格式:post|⽂件路径⽬标路径): \n >>> ').strip() #输⼊内容格式:命令|⽂件路径⽬标路径27 func, file_path =inp.split("|", 1) #将输⼊的内容拆分为两部分,⽅法名和路径28 local_path, target_path = re.split("\s*", file_path, 1) #再将路径部分,通过正则表达式。
python学习之路(三)使⽤socketserver进⾏ftp断点续传最近学习python到socketserver,本着想试⼀下⽔的深浅,采⽤Python3.6.⽬录结构如下:receive_file和file为下载或上传⽂件存放⽬录,ftp_client为ftp客户端,ftp_server为server端。
server端源码:#!/usr/bin/env python# -*- coding:utf-8 -*-import socketserverimport oserror_code = {'400':'FILE IS NOT EXISTS'}file_path = os.path.join(os.path.abspath('.'),'file') #获取⽂件⽬录路径'''服务端采⽤socketserver⽅式'''class MyTCPHandler(socketserver.BaseRequestHandler):def handle(self):while True:# print('new conn',self.client_address)data = self.request.recv(100) #接收客户端请求if not data.decode():breakelif data.decode().split()[0] == 'get': #server判断是下载还是上传⽂件,get是下载offset = data.decode().split('|')[1] #取出偏移量file = data.decode().split()[1].split('|')[0] #取出要下载的⽂件名filename = os.path.join(file_path,file)read_len = 0if os.path.exists(filename) : #判断是否有资源with open(filename,'rb') as fd:while True:send_data = fd.read(1024)read_len += len(send_data) #记录读取数据长度if send_data and read_len > int(offset): #达到偏移量发送数据ack_msg = "SEND SIZE|%s" % len(send_data)self.request.send(ack_msg.encode())client_ack = self.request.recv(50)if client_ack.decode() =="CLIENT_READY_TO_RECV":self.request.send(send_data)elif read_len <= int(offset):continueelse:send_data ='END'self.request.send(send_data.encode()) #数据传输完毕发送finally信号breakelse:msg = '400'self.request.send(msg.encode())elif data.decode().split()[0] == 'put': #判断客户端是不是上传⾏为file = data.decode().split()[1] #获取需要上传的⽂件名filename = os.path.join(file_path,file) #定义⽂件路径log = "%s.%s" % (file,'log') #指定记录偏移⽇志⽂件名logname = os.path.join(file_path,log) #定义⽇志路径if os.path.exists(filename) and os.path.exists(logname): #如果要上传的⽂件和⽇志⽂件同时存在,说明需要进⾏续传with open(logname) as f:offset = f.read().strip() #读取偏移量else:offset = 0 #表⽰不需要进⾏续传,直接从头开始传server_syn_msg = "offset %s" % offset #把偏移信息发送给客户端self.request.send(server_syn_msg.encode())total_len = int(offset) #获取已传输完的⽂件长度,即从这个位置开始接收新的数据while True:receive_ack = self.request.recv(100) #客户端接收到偏移信息后通知服务端要发送数据的长度信息,相当于⼀个ackres_msg = receive_ack.decode().split('|')if receive_ack.decode() == 'END': #判断⽂件是否上传完成,完成后删掉偏移⽇志os.remove(logname)breakelif res_msg[0].strip() =='SEND SIZE': #如果服务端收到了客户端发送过来的ack,给客户端返回⼀个syn信息,表⽰可以开始传数据了res_size = res_msg[1]self.request.send(b'CLIENT_READY_TO_RECV')recv_data = self.request.recv(1024) #接收数据total_len += len(recv_data) #记录接收数据长度with open(filename,'ab') as fd: #以追加的⽅式写⼊⽂件fd.write(recv_data)with open(logname,'w') as f: #把已接收到的数据长度写⼊⽇志f.write(str(total_len))if__name__ == '__main__':host,port = "localhost",5000server = socketserver.ThreadingTCPServer((host,port),MyTCPHandler)server.serve_forever() #开启服务端客户端源码:#!/usr/bin/env python# -*- coding:utf-8 -*-import socketimport os,sysreceive_file_path = os.path.abspath(os.path.join(os.path.abspath('.'),'receive_file')) #指定⽂件⽬录路径error_code = {'400':'FILE IS NOT EXISTS'}'''使⽤类的⽅式,⽅便反射'''class SOCKET(object):def__init__(self,ip,port):self.ip = ipself.port = portdef socket_obj(self):sk = socket.socket()sk.connect((self.ip,self.port))return skdef get(self): #get表⽰从服务端下载⽂件到本地conn = self.socket_obj() #⽣成对象user_input = input('get filename:') #指定输⼊命令格式 get filename# print(msg,type(msg))filename = user_input.split()[1] #获取⽂件名file = os.path.join(receive_file_path,filename) #下载⽂件的绝对路径logname = '%s.%s' % (filename,'log') #⽣成⽇志名log = os.path.join(receive_file_path,logname) #偏移量⽇志的绝对路径if os.path.exists(log) and os.path.exists(file): #判断是否需要续传,如果需要就读出偏移量with open(log) as f:offset = f.read().strip()else:offset = 0 # 否则偏移量置0msg = "%s|%s" %(user_input,offset)conn.send(msg.encode())total_length = int(offset) #记录传输完成了多少while True:server_ack_msg = conn.recv(100) #接收第⼀个ackif server_ack_msg.decode().strip() == '400': #如果ftp服务器没有这个资源,返回错误print('400', error_code['400'])conn.close()breakelif server_ack_msg.decode().strip() == 'END': #传输完成,ftp server返回字段,并删除偏移量⽇志conn.close()os.remove(log)breakres_msg = server_ack_msg.decode().split('|') #接收server的syn和传输数据⼤⼩的信息if res_msg[0].strip() == "SEND SIZE":res_size = int(res_msg[1])conn.send(b'CLIENT_READY_TO_RECV') #给server返回ackreceive_data = conn.recv(1024) #接收server的数据total_length += len(receive_data) #记录接收到了多少数据# print(receive_data.decode())# print(total_length)with open(file,'ab') as fd: #以追加的⽅式写⽂件fd.write(receive_data)with open(log,'w') as f: #把已接收数据长度写进⽇志f.write(str(total_length))def put(self): #put表⽰上传⽂件⾄服务端conn = self.socket_obj() #⽣成对象msg = input('put filename:') #指定命令输⼊格式,put filenamefilename = os.path.join(receive_file_path, msg.split()[1]) #⽣成上传⽂件路径if os.path.exists(filename): #判断⽂件存在与否,不存在返回错误conn.send(msg.encode()) #发送⽂件⾏为与⽂件名⾄服务端server_syn_msg = conn.recv(100) #接收服务端发送的偏移量信息offset = server_syn_msg.decode().split()[1]read_length = 0 #重置需要读取⽂件的长度with open(filename,'rb') as fd:while True:send_data = fd.read(1024) #开始读取⽂件,每次读取1024字节read_length += len(send_data) #记录读取数据长度if send_data and read_length> int(offset): #和服务端发送的偏移量进⾏⽐较,只有数据不为空和读到超过偏移量才会发送数据ack_msg = "SEND SIZE|%s" %len(send_data) #给服务端发送本次要发送数据的长度,相当于⼀个synconn.send(ack_msg.encode())client_ack = conn.recv(100) #接收到服务端发送的ack确认信息,收到之后开始传输数据if client_ack.decode() =='CLIENT_READY_TO_RECV':conn.send(send_data)elif read_length <= int(offset): #如果读取到的数据长度没到偏移量就继续循环读取⽂件continueelse:send_data = 'END'#⽂件已经读完,表⽰已经全部发送完成,给服务端发送信息说明客户端已经发送完成conn.send(send_data.encode())breakelse:print('400', error_code['400'])if__name__ == '__main__':c = SOCKET('127.0.0.1',5000)if hasattr(c,sys.argv[1]):func = getattr(c,sys.argv[1])func()由于时间原因,存在在传输的过程中有些⽂件⾥⾯涉及到中⽂的可能会报错的bug,只是功能基本实现,给⼤家分享⼀下我的思路,⽅便交流。
sftp断点续传原理
sftp(Secure File Transfer Protocol)是一种安全的文件传输协议,它通过加密和认证机制来保护文件的传输安全。
sftp断点续传是指在文件传输过程中,如果传输中断或失败,可以通过某种机制恢复传输,而不需要重新开始整个传输过程。
这种机制大大提高了文件传输的效率和可靠性。
sftp断点续传的原理主要涉及以下几个方面:
1. 文件分块传输,在sftp断点续传过程中,文件通常会被分成若干个块进行传输。
每个块都有一个唯一的标识符,以便在传输过程中进行管理和校验。
2. 断点记录和恢复,sftp客户端和服务器端会记录文件传输的断点信息,包括已经成功传输的块和未传输的块。
当传输中断或失败时,可以通过这些信息来恢复传输,而不需要重新传输整个文件。
3. 校验和验证,sftp断点续传还会对每个传输的块进行校验和验证,以确保传输的完整性和准确性。
如果某个块传输失败,
sftp会重新传输该块,而不会影响其他已经成功传输的块。
4. 客户端和服务器端协作,sftp客户端和服务器端会相互协作,通过交换断点信息和校验结果来实现断点续传功能。
客户端会
向服务器端请求恢复传输,而服务器端会根据客户端提供的断点信
息来继续传输文件。
总的来说,sftp断点续传通过文件分块传输、断点记录和恢复、校验和验证以及客户端和服务器端的协作来实现文件传输的高效性
和可靠性。
这种机制在大文件传输和不稳定网络环境下尤为重要,
可以显著提高文件传输的成功率和效率。
Python实现⽀持并发、断点续传的FTP 参考⽹上⼀个FTP程序,重写了⼀遍,并稍加扩展⼀、要求1. ⽀持多⽤户同时登录2. 可以注册⽤户,密码使⽤md5加密3. 可以登录已注册⽤户4. ⽀持cd切换⽬录,ls查看⽬录⼦⽂件5. ⽀持上传、下载⽂件6. 可以执⾏命令,如:ipconfig⼆、代码配置⽂件1#!/usr/bin/env python2# -*- coding:utf-8 -*-34import os56 BASE_DIR = os.path.dirname(os.path.dirname(__file__))7 BASE_HOME = os.path.join(BASE_DIR, 'home')8 NAME_PWD = os.path.join(BASE_DIR, 'db', 'name_pwd')9 USER_FILE = os.path.join(BASE_DIR, 'db')服务端:1#!/usr/bin/env python2# -*- coding:utf-8 -*-34import os5import hashlib6import pickle7import subprocess8import socketserver9from config import settings1011 baseHome = settings.BASE_HOME12class MyServer(socketserver.BaseRequestHandler):13def recv_file(self):14'''15⽂件传输16 :return:17'''18 conn = self.request19 a = str(conn.recv(1024),encoding='utf-8')20 file_size, file_name = a.split(',')21 new_file_name = os.path.join(baseHome, file_name)22if file_name in baseHome: #检测⽂件是否已存在,涉及断点续传23 has_recv = os.stat(baseHome).st_size #计算临时⽂件⼤⼩24 conn.sendall(bytes(has_recv, encoding='utf-8'))25 with open(new_file_name,'ab') as f: #追加模式26 data = conn.recv(1024)27 f.write(data)28 has_recv += len(data)29else:30 has_recv = 031 conn.sendall(bytes('s',encoding='utf-8')) #客户端收到字符串s,从0开始发送32 with open(new_file_name, 'wb') as f:33while has_recv<= int(file_size):34 data = conn.recv(1024)35 f.write(data)36 has_recv += len(data)3738def send_file(self, fileName):39'''40向客户端发送⽂件41 :param fileName:42 :return:43'''44 filePath = os.path.join(self.currDir, fileName)45 conn = self.request46if os.path.exists(filePath):47 size = os.stat(filePath).st_size48 conn.sendall(bytes(str(size)+','+fileName,encoding='utf-8'))49 ret = conn.recv(1024)50 r = str(ret,encoding='utf-8')51if r=='s':52 has_send = 053else:54 has_send = int(r)55 with open(filePath,'rb') as f:56 f.seek(has_send)57while has_send<size:58 data = f.read(1024)59 conn.sendall(data)60 has_send+=len(data)61 conn.sendall(bytes('0', encoding='utf-8'))62else:63 conn.sendall(bytes('0', encoding='utf-8'))6465def createDir(self, currDir, newName):66'''67创建⽂件夹68 :param currDir:当前所在⽬录69 :param newName: 新⽂件夹名称70 :return: 是否创建成功71'''72 mulu = os.path.join(baseHome, currDir)73 newFilePath = os.path.join(mulu, newName)74if os.path.exists(newFilePath):75return'2'76else:77 ret = '0'78try:79 os.makedirs(newFilePath)80 ret = '1'81except OSError as e:82 ret = '0'83return ret8485def command(self):86'''87执⾏命令88 :return:89'''90 conn = self.request91 a = conn.recv(1024)92 ret = str(a, encoding='utf-8')93 ret2 = subprocess.check_output(ret, shell=True)94 r = divmod(len(ret2), 1024)95 s = r[0]+196 conn.sendall(bytes(str(s), encoding='utf-8'))97 conn.recv(1024)98 conn.sendall(ret2)99100def md5(self, pwd):101'''102判断密码进⾏加密103 :param pwd:104 :return:105'''106 hash = hashlib.md5(bytes('xx7',encoding='utf-8'))107 hash.update(bytes(pwd, encoding='utf-8'))108return hash.hexdigest()109110def login(self, username, pwd):111'''112登录113 :param username:⽤户名114 :param pwd: 密码115 :return: 是否登录成功116'''117if os.path.exists(_PWD):118 s = pickle.load(open(_PWD,'rb'))119if username in s:120if s[username]==self.md5(pwd):121return True122else:123return False124else:125return False126127def regist(self, username, pwd):128'''129注册130 :param username:⽤户名131 :param pwd: 密码132 :return: 是否注册成功133'''134 conn = self.request135 s = {}136if os.path.exists(_PWD):137 s = pickle.load(open(_PWD, 'rb'))138if username in s:139return False140else:141 s[username] = self.md5(pwd)142 mulu = os.path.join(ER_FILE, username)143 os.makedirs(mulu)144 pickle.dump(s, open(_PWD, 'wb'))145return True146147def before(self, username, pwd, ret):148'''149判断注册和登录,并展⽰⽤户的详细⽬录信息,⽀持cd和ls命令150 :param username: ⽤户名151 :param pwd: 密码152 :param ret:153 :return:154'''155 conn = self.request156if ret == '1':157 r = self.login(username,pwd)158if r:159 conn.sendall(bytes('y',encoding='utf-8'))160else:161 conn.sendall(bytes('n',encoding='utf-8'))162elif ret == '2':163 r = self.regist(username, pwd)164if r:165 conn.sendall(bytes('y',encoding='utf-8'))166else:167 conn.sendall(bytes('n',encoding='utf-8'))168169def user_file(self, username):170'''171展⽰⽤户的详细⽬录信息,⽀持cd和ls命令172 :param username: ⽤户名173 :return:174'''175 conn = self.request176 mulu = baseHome177 self.currDir = mulu178 conn.sendall(bytes(mulu, encoding='utf-8'))179while True:180if conn:181 b = conn.recv(1024)182 ret = str(b, encoding='utf-8')183try:184 a, b = ret.split('',1)185except Exception as e:186 a = ret187if a == 'cd':188if b=='..':189 mulu = os.path.dirname(mulu)190else:191 mulu = os.path.join(mulu, b)192 self.currDir = mulu193 conn.sendall(bytes(mulu, encoding='utf-8'))194elif a=='ls':195 ls = os.listdir(mulu)196print(ls)197 a = ','.join(ls)198if a=='':199 a = '.'200 conn.sendall(bytes(a, encoding='utf-8'))201elif a=='mkdir':202 m = self.createDir(self.currDir,b)203 conn.sendall(bytes(m, encoding='utf-8'))204elif a=='q':205break206207def handle(self):208 conn = self.request209 conn.sendall(bytes('welcome',encoding='utf-8'))210 b = conn.recv(1024)211 ret = str(b, encoding='utf-8')212 c = conn.recv(1024)213 r = str(c, encoding='utf-8')214 username, pwd = r.split(',')215 self.before(username, pwd, ret)216 er_file(username)217while True:218 a=conn.recv(1024)219 ret = str(a, encoding='utf-8')220if ret == '1':221 self.recv_file()222elif ret=='2':223 mand()224elif ret[0:4]=='get:':225 self.send_file(ret[4:])226elif ret=='q':227break228else:229pass230231if__name__ == '__main__':232 server = socketserver.ThreadingTCPServer(('',9999), MyServer)233 server.serve_forever()客户端:1#!/usr/bin/env python2# -*-coding:utf-8 -*-34import os, sys5import socket67def send_file(file_path):8'''9发送⽂件10 :param file_path:⽂件名11 :return:12'''13 size = os.stat(file_path).st_size14 file_name = os.path.basename(file_path)15 obj.sendall(bytes(str(size)+','+file_name,encoding='utf-8'))16 ret = obj.recv(1024)17 r = str(ret, encoding='utf-8')18if r=='s': #⽂件不存在,从头开始传19 has_send = 020else: #⽂件存在21 has_send = int(r)22 with open(file_path, 'rb') as f:23 f.seek(has_send) #定位到已经传到的位置24while has_send<size:25 data = f.read(1024)26 obj.sendall(data)27 has_send+=len(data)28 sys.stdout.write('\r') #情况⽂件内容29 sys.stdout.write('已发送%s%%|%s' % (int(has_send/size*100), (round(has_send/size*40)*'|')))30 sys.stdout.flush() #强制刷出内存31print('上传成功!\n')3233def recv_file(toPath, getFile):34'''35接收要下载的⽂件36 :param toPath: 本地要保存⽂件的存放路径37 :param getFile: 要下载的⽂件名称38 :return:39'''40 obj.sendall(bytes('get:'+getFile,encoding='utf-8'))41 a = str(obj.recv(1024), encoding='utf-8')42 file_size, file_name = a.split(',')43 file_size = int(file_size)44if file_size == 0:45print('没有找到此⽂件')46else:47 new_file_name = os.path.join(toPath, file_name)48if file_name in toPath:49 has_recv = os.stat(toPath).st_size50 obj.sendall(bytes(has_recv, encoding='utf-8'))51 with open(new_file_name,'ab') as f:52while has_recv<=file_size:53 data = obj.recv(1024)54 f.write(data)55 has_recv+=len(data)56 sys.stdout.write('\r') # 情况⽂件内容57 sys.stdout.write('已接收%s%%|%s' % (int(has_recv / file_size * 100), (round(has_recv / file_size * 40) * '|')))58 sys.stdout.flush() # 强制刷出内存59else:60 has_recv = 061 obj.sendall(bytes('s', encoding='utf-8'))62 with open(new_file_name, 'wb') as f:63while has_recv<= file_size:64 data = obj.recv(1024)65 f.write(data)66 has_recv += len(data)67 sys.stdout.write('\r') # 情况⽂件内容68 sys.stdout.write('已接收%s%%|%s' % (int(has_recv / file_size * 100), (round(has_recv / file_size * 40) * '|')))69 sys.stdout.flush() # 强制刷出内存70print('接收成功!\n')717273def command(command_name):74'''75执⾏命令76 :param command_name:77 :return:78'''79 obj.sendall(bytes(command_name, encoding='utf-8'))80 ret = obj.recv(1024) #接受命令需要接受的次数81 obj.sendall(bytes('收到次数',encoding='utf-8'))82 r = str(ret, encoding='utf-8')83for i in range(int(r)): #共需接收int(r)次84 ret = obj.recv(1024) #等待客户端发送85 r = str(ret, encoding='GBK')86print(r)8788def login(username, pwd):89'''90登录91 :param username: ⽤户名92 :param pwd: 密码93 :return: 是否登录成功94'''95 obj.sendall(bytes(username+','+pwd, encoding='utf-8'))96 ret = obj.recv(1024)97 r = str(ret, encoding='utf-8')98if r=='y':99return True100else:101return False102103def regist(username, pwd):104'''105注册106 :param username: ⽤户名107 :param pwd: 密码108 :return: 是否注册成功109'''110 obj.sendall(bytes(username+','+pwd, encoding='utf-8'))111 ret = obj.recv(1024)112 r = str(ret, encoding='utf-8')113if r=='y':114return True115else:116return False117118def before(username, pwd):119'''120选择注册和登录,并展⽰⽤户的详细⽬录信息,⽀持cd和ls命令121 :param username: ⽤户名122 :param pwd: 密码123 :return:124'''125 a = input('请选择 1.登录 2.注册:')126 obj.sendall(bytes(a, encoding='utf-8'))127# obj.recv()128if a=='1':129 ret = login(username, pwd)130if ret:131print('登录成功')132return 1133else:134print('⽤户名或密码错误')135return 0136elif a=='2':137 ret = regist(username, pwd)138if ret:139print('注册成功')140return 1141else:142print('⽤户名已存在')143return 0144145def user_file(username):146# obj.sendall(bytes('打印⽤户⽂件路径', encoding='utf-8'))147 ret = obj.recv(1024)148 r = str(ret, encoding='utf-8')149print(r)150while True:151 a = input('输⼊ cd切换⽬录,ls查看⽬录详细信息,mkdir创建⽂件夹,q退出:') 152 a = a.strip()153 obj.sendall(bytes(a, encoding='utf-8'))154if a=='q':155break156elif a[0:5]=='mkdir':157 ret = obj.recv(1024)158 r = str(ret, encoding='utf-8')159if r=='1':160print('⽂件夹创建成功')161elif r=='2':162print('⽂件夹已存在!')163else:164print('创建失败!')165else:166 ret = obj.recv(1024)167 r=str(ret, encoding='utf-8')168if len(r)==1: #判断是cd结果,还是ls的结果(ls只有⼀个⼦⽬录,直接打印)169print(r)170else:171 li = r.split(',')172for i in li:173print(i)174175def main(username, pwd):176 ret = obj.recv(1024)177 r = str(ret, encoding='utf-8')178print(r)179 result = before(username, pwd) #判断登录/注册180if result:181 user_file(username)182while True:183 a = input('请选择 1.传⽂件 2.执⾏命令 3.收⽂件 q 退出:')184 obj.sendall(bytes(str(a),encoding='utf-8'))185if a=='1':186 b = input('请输⼊⽂件路径:')187if os.path.exists(b):188 send_file(b)189 obj.sendall(bytes('hhe', encoding='utf-8'))190elif a=='2':191 b = input('请输⼊command:')192 command(b)193elif a=='3':194 b = input('请输⼊存放路径:')195 c = input('请输⼊要获取的⽂件:')196 recv_file(b, c)197elif a=='q':198break199else:200print('输⼊错误!')201202 obj.close()203204if__name__ == '__main__':205 obj = socket.socket()206 obj.connect(('192.168.1.100',9999))207 username = input('请输⼊⽤户名:')208 pwd = input('请输⼊密码:')209 main(username, pwd)。
断点续传方案简介断点续传是指在网络传输过程中,当连接中断或者文件传输中止时,能够从中断处重新开始传输,而不是从头开始。
这样可以提高文件传输的可靠性和传输效率。
在实际应用中,断点续传方案常常用于大文件的上传或下载过程中,以确保用户在网络不稳定的情况下能够顺利完成文件传输,而无需重新开始。
本文将介绍几种常见的断点续传方案,并分析各种方案的优缺点,帮助读者选择适合自己应用场景的方案。
方案一:基于HTTP的断点续传HTTP协议是应用层协议中最常用的协议之一,支持断点续传的HTTP服务器通常会在响应头中添加Range字段,用于指定服务器传输的起始位置。
客户端在进行文件下载时,通过设置请求头中的Range字段来请求指定范围的数据。
服务器接收到请求后,根据Range字段返回相应的数据片段。
如果客户端在下载过程中中断,可以通过设置Range字段重新发送请求,从中断处继续下载。
HTTP的断点续传方案具有以下优点:-:基于HTTP的断点续传方案使用标准的HTTP协议,不需要额外的协议和框架支持,方便快捷。
-:基于HTTP的断点续传方案通常兼容多种操作系统和终端设备,使用广泛。
-:通过设置不同的Range字段,可以实现下载指定范围的数据,具有较高的灵活性。
-:HTTP协议本身就具有较高的可靠性,断点续传方案在一定程度上增强了文件传输的可靠性。
然而,基于HTTP的断点续传方案也存在一些局限性:-:由于每次续传都需要从中断处开始,可能会导致重复传输已经传输过的数据,降低传输效率。
-:对于非常大的文件,服务器需要保存大量的中断点信息,占用较多的磁盘空间和内存资源。
-:如果服务器不支持断点续传,那么即使客户端实现了断点续传方案,也无法成功续传。
方案二:基于FTP的断点续传FTP(File Transfer Protocol)是一种文件传输协议,也常用于文件上传和下载。
FTP支持断点续传的机制,能够在网络中断或传输中止后从中断处继续传输。
Python数据传输Python是一种高级编程语言,具有简单易学、灵活多变的特点,广泛应用于各个领域。
数据传输是Python中一个重要的概念,它指的是将数据从一个地方传输到另一个地方的过程。
在本文中,我将介绍Python中常用的数据传输方法和技术。
一、文件传输在许多情况下,我们需要将文件从一台计算机传输到另一台计算机。
Python提供了多种文件传输的方法,下面是其中几种常用的方式:1. 使用shutil模块进行文件传输:import shutilshutil.copy(source, destination)上述代码将源文件复制到目标文件夹中。
2. 使用ftplib模块进行FTP传输:from ftplib import FTPftp = FTP(host)ftp.login(user, passwd)ftp.retrbinary('RETR ' + filename, open(local_filename, 'wb').write)上述代码建立了与FTP服务器的连接,并从服务器下载文件到本地。
二、网络传输网络传输是指通过网络将数据从一个节点传输到另一个节点。
Python提供了多个库和模块来处理网络传输,下面是两个常用的库的示例:1. 使用socket模块进行网络传输:import socketsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)sock.sendall(data)上述代码创建了一个TCP套接字,并将数据发送到已连接的节点。
2. 使用requests库进行HTTP传输:import requestsr = requests.get(url)上述代码发送一个HTTP GET请求,并返回服务器响应的数据。
三、数据库传输在数据处理过程中,我们通常需要与数据库进行交互。
Python提供了多种方式与数据库进行数据传输,下面是两个常用的库的示例:1. 使用MySQLdb库进行MySQL数据库传输:import MySQLdbdb = MySQLdb.connect(host, user, passwd, db)cursor = db.cursor()cursor.execute(sql)上述代码连接到MySQL数据库,并执行给定的SQL语句。
本文建立在你对socket知识有一点点的基础之上(有一点点就足够了:))FTP客户端实现要建立两个通道,一个控制命令通道,让FTP服务器知道客户端要干什么,一个数据传输通道。
所谓的两个通道只不过是两个调用了connect函数的连接,只是控制命令通道专门用来传输一些字符串命令信息,而数据通道则是用来传输文件。
控制命令通道一定是由客户端向服务器的连接(默认的端口是21,也可以指定端口,这要看服务器的设置)。
连接的过程完成了FTP的登录。
数据通道则不一定啦,具体哪个连哪个,请看下面对PASV命令的解释。
其实FTP断点续传的原理很简单,可分为断点下载和断点上传。
客户端的实现步骤如下:一、下载:1、向服务器发送“REST + 本地文件长度”命令,告诉服务器,客户端要断点下载了。
这时服务器还不知道客户端要下载哪个文件;2、向服务器发送“RETR + 文件名”命令,通知服务器要下载的文件名,这时服务器开始定位文件指针读文件并发送数据。
3、客户端定位本地文件指针(文件末尾);4、两端的准备工作都做完了以后,客户端创建socket,以被动或非被动方式建立数据通道,循环调用recv接收数据并追加入本地文件;二、上传:1、获取服务器上和本地要上传文件的同名文件大小;2、向服务器发送“APPE +文件名”,通知服务器,接下来从数据通道发送给你的数据要附加到这个文件末尾。
3、定位本地文件指针(和FTP上文件大小相同的位置)4、从文件指针处读数据并发送。
好了,FTP断点续传的原理就这么简单。
代码里将断点上传和断点下载放到同一个函数(MoveFile)里,通过get参数说明是上传还是下载。
当然,整个 FTP类的实现有800多行,包括登录、退出、获取FTP文件大小、删除FTP服务器上文件、响应服务器,解析响应信息等函数。
相应的注释代码里都有,这里就不一一熬述了。
这里重点说说PASV模式,即被动模式,这是FTP命令里比较不容易理解的一个,这条命令请求服务器在某个端口(非FTP默认端口或控制命令端口)创建一个监听socket,服务器创建的端口号会在客户端的控制命令通道上得到响应。
寻找自我的博客
p ython ftp的断点上传
分类: Python 2012-10-15 22:34 51人阅读 评论(0) 收藏举报
主要作用:支持ftp上传,断点上传。
要支持目录的话,改改就行.原理是一样的.
断点下载也类似.
#!/usr/bin/env python2.5.4
#coding:utf-8
from ftplib import FTP
import os
import sys
import traceback
class MyFTP(FTP):
'''
#继承父类中的方法,在子类中可以直接调用
#重载父类中storbinary的方法
'''
def storbinary(self, cmd , fd,fsize=0,rest=0):
blocksize=1024
cmpsize=rest
conn = self.transfercmd(cmd, rest)
while 1:
if rest==0:
buf=fd.read(blocksize)
else:
fd.seek(cmpsize)
buf=fd.read(blocksize)
if buf:
conn.send(buf)
else:
print 'Ending.'
break
cmpsize+=blocksize
conn.close()
fd.close()
def ConnectFTP(remoteip,remoteport,loginname,loginpassword):
ftp=MyFTP()
try:
ftp.connect(remoteip,remoteport)
except:
return (0,'connect failed!')
else:
try:
ftp.login(loginname,loginpassword)
except:
return (0,'login failed!')
else:
return (1,ftp)
def mywork(remoteip,remoteport,loginname,loginpassword,path,localfile,filesize): res=ConnectFTP(remoteip,remoteport,loginname,loginpassword)
bufsize=1024
if res[0]!=1:
print res[1]
sys.exit()
ftp=res[1]
fd=open(localfile,'rb')
ftp.set_pasv(0) #到这一部出现连接超时请偿试设置非0值
if path:
ftp.cwd(path)
file_list=ftp.nlst()
if localfile in file_list:
rest=ftp.size(localfile)
print 'Conntinue uploading:'
ftp.storbinary('STOR %s' % localfile ,fd,filesize,rest)
else:
print 'Starting upload:...'
ftp.storbinary('STOR %s' % localfile ,fd,filesize,0)
ftp.set_debuglevel(0)
if __name__== '__main__':
remoteip=sys.argv[1]
remoteport=sys.arg[2]
loginname=sys.arg[3]
loginpassword=sys.arg[4]
filename=sys.argv[5]
path=sys.argv[6]
port=21
statinfo=os.stat(filename)
size=int(statinfo.st_size)
mywork(remoteip,port,loginname,loginpassword,path,filename,size)。