各位用户为了找寻关于python实现可以断点续传和并发的ftp程序的资料费劲了很多周折。这里教程网为您整理了关于python实现可以断点续传和并发的ftp程序的相关资料,仅供查阅,以下为您介绍关于python实现可以断点续传和并发的ftp程序的详细内容
前言
下载文件时,最怕中途断线,无法成功下载完整的文件。断点续传就是从文件中断的地方接下去下载,而不必重新下载。这项功能对于下载较大文件时非常有用。那么这篇文章就来给大家分享如何利用python实现可以断点续传和并发的ftp程序。
一、要求
1、用户md5认证
2、支持多用户同时登陆(并发)
3、进入用户的命令行模式,支持cd切换目录,ls查看目录子文件
4、执行命令(ipconfig)
5、传输文件:
a、支持断点续传
b、传输中显示进度条
二、思路
1.客户端用户登录和注册:
a、客户端仅提供用户名和密码,选择登录或注册,
b、服务器端进行注册并将加密后的密码写入文件,最后返回给客户端是否登录或注册成功
2.ls和cd命令
a、客户端输入命令,服务器端处理并返回给客户端
3.执行命令:
a、客户端发送需要执行的命令
b、服务器端执行命令,并返回客户端需要接收该命令的次数s=r[0]+1,其中r=divmod(结果总长度,1024)
c、客户端收到次数,告诉服务端已经收到
d、服务端发送执行结果,客户端进行for循环接收该结果
4.发送文件:
a、客户端输入文件路径(测试版路径为:f.png),发送文件名和文件大小
b、服务器端检测指定目录是否含有该文件,如果没有,返回给客户端字符串s,即从头开始发送start,has_recv=0 如果有,即需要断点续传,返回给客户端已经上传了多少has_recv
c、客户端接收返回值,并seek到has_recv的位置,进行循环收发,打印当前进度,直到传输完毕。
注:本程序可循环接收用户选择传输文件和执行命令
三、代码
配置文件:
? 1 2 3 4 5 6 7 8#!/usr/bin/env python
# -*- coding: utf-8 -*-
import
os
BASE_DIR
=
os.path.dirname(os.path.dirname(__file__))
#配置文件的上层目录
NEW_FILENAME
=
os.path.join(BASE_DIR,
'view'
)
#新文件目录
NAME_PWD
=
os.path.join(BASE_DIR,
'db'
,
'name_pwd'
)
#用户名和密码目录
USER_FILE
=
os.path.join(BASE_DIR,
'db'
)
服务器端:
? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187#!/usr/bin/env python
# -*- coding: utf-8 -*-
import
sys,os
import
time
import
socket
import
hashlib
import
pickle
import
subprocess
import
socketserver
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
from
config
import
settings
new
=
settings.NEW_FILENAME
class
Myserver(socketserver.BaseRequestHandler):
def
recv_file(
self
):
'''
文件传输
:return:
'''
conn
=
self
.request
a
=
str
(conn.recv(
1024
),encoding
=
'utf-8'
)
file_size,file_name
=
a.split(
','
)
new_file_name
=
os.path.join(new,file_name)
if
file_name
in
new:
#检测文件是否已存在,涉及断点续传
has_recv
=
os.stat(new).st_size
#计算临时文件大小
conn.sendall(bytes(has_recv,encoding
=
'utf-8'
))
with
open
(new_file_name,
'ab'
) as f:
#追加模式
while
has_recv<
=
int
(file_size):
data
=
conn.recv(
1024
)
f.write(data)
has_recv
+
=
len
(data)
else
:
has_recv
=
0
conn.sendall(bytes(
's'
,encoding
=
'utf-8'
))
# 客户端收到字符串s,从0开始发送
with
open
(new_file_name,
'wb'
) as f:
while
has_recv<
=
int
(file_size):
data
=
conn.recv(
1024
)
f.write(data)
has_recv
+
=
len
(data)
def
command(
self
):
'''
执行命令
:return:
'''
conn
=
self
.request
a
=
conn.recv(
1024
)
ret
=
str
(a,encoding
=
'utf-8'
)
ret2
=
subprocess.check_output(ret, shell
=
True
)
r
=
divmod
(
len
(ret2),
1024
)
s
=
r[
0
]
+
1
#客户端需要接收的次数
conn.sendall(bytes(
str
(s),encoding
=
'utf-8'
))
conn.recv(
1024
)
#确认客户端收到需要接收的次数
conn.sendall(ret2)
def
md5(
self
,pwd):
'''
对密码进行加密
:param pwd: 密码
:return:
'''
hash
=
hashlib.md5(bytes(
'xx7'
,encoding
=
'utf-8'
))
hash
.update(bytes(pwd,encoding
=
'utf-8'
))
return
hash
.hexdigest()
def
login(
self
,usrname,pwd):
'''
登陆
:param usrname: 用户名
:param pwd: 密码
:return:是否登陆成功
'''
conn
=
self
.request
s
=
pickle.load(
open
(settings.NAME_PWD,
'rb'
))
if
usrname
in
s:
if
s[usrname]
=
=
self
.md5(pwd):
#和加密后的密码进行比较
return
True
else
:
return
False
else
:
return
False
def
regist(
self
,usrname,pwd):
'''
注册
:param usrname: 用户名
:param pwd: 密码
:return:是否注册成功
'''
conn
=
self
.request
s
=
pickle.load(
open
(settings.NAME_PWD,
'rb'
))
if
usrname
in
s:
return
False
else
:
s[usrname]
=
self
.md5(pwd)
mulu
=
os.path.join(settings.USER_FILE,usrname)
os.makedirs(mulu,
'a'
)
pickle.dump(s,
open
(settings.NAME_PWD,
'wb'
))
return
True
def
before(
self
,usrname,pwd,ret):
'''
判断注册和登陆,并展示用户的详细目录信息,支持cd和ls命令
:return:
'''
conn
=
self
.request
if
ret
=
=
'1'
:
r
=
self
.login(usrname,pwd)
if
r:
conn.sendall(bytes(
'y'
,encoding
=
'utf-8'
))
else
:
conn.sendall(bytes(
'n'
,encoding
=
'utf-8'
))
elif
ret
=
=
'2'
:
# print(usrname,pwd)
r
=
self
.regist(usrname,pwd)
if
r:
conn.sendall(bytes(
'y'
,encoding
=
'utf-8'
))
else
:
conn.sendall(bytes(
'n'
,encoding
=
'utf-8'
))
def
usr_file(
self
,usrname):
'''
展示用户的详细目录信息,支持cd和ls命令
:param usrname: 用户名
:return:
'''
conn
=
self
.request
conn.recv(
1024
)
mulu
=
os.path.join(settings.USER_FILE,usrname)
conn.sendall(bytes(mulu,encoding
=
'utf-8'
))
while
True
:
b
=
conn.recv(
1024
)
ret
=
str
(b,encoding
=
'utf-8'
)
try
:
a,b
=
ret.split(
' '
,
1
)
except
Exception as e:
a
=
ret
if
a
=
=
'cd'
:
if
b
=
=
'..'
:
mulu
=
os.path.dirname(mulu)
else
:
mulu
=
os.path.join(mulu,b)
conn.sendall(bytes(mulu,encoding
=
'utf-8'
))
elif
a
=
=
'ls'
:
ls
=
os.listdir(mulu)
print
(ls)
a
=
','
.join(ls)
conn.sendall(bytes(a,encoding
=
'utf-8'
))
elif
a
=
=
'q'
:
break
def
handle(
self
):
conn
=
self
.request
conn.sendall(bytes(
'welcome'
,encoding
=
'utf-8'
))
b
=
conn.recv(
1024
)
ret
=
str
(b,encoding
=
'utf-8'
)
print
(ret)
conn.sendall(bytes(
'b ok'
,encoding
=
'utf-8'
))
c
=
conn.recv(
1024
)
r
=
str
(c,encoding
=
'utf-8'
)
usrname,pwd
=
r.split(
','
)
self
.before(usrname,pwd,ret)
#登陆或注册验证
self
.usr_file(usrname)
#展示用户的详细目录信息,支持cd和ls命令
while
True
:
a
=
conn.recv(
1024
)
conn.sendall(bytes(
'收到a'
,encoding
=
'utf-8'
))
ret
=
str
(a,encoding
=
'utf-8'
)
if
ret
=
=
'1'
:
self
.recv_file()
# conn.sendall(bytes('file ok',encoding='utf-8'))
elif
ret
=
=
'2'
:
self
.command()
elif
ret
=
=
'q'
:
break
else
:
pass
if
__name__
=
=
'__main__'
:
sever
=
socketserver.ThreadingTCPServer((
'127.0.0.1'
,
9999
),Myserver)
sever.serve_forever()
客户端:
? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165#!/usr/bin/env python
# -*- coding: utf-8 -*-
import
sys
import
time
import
os
import
socket
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
from
config
import
settings
def
send_file(file_path):
'''
发送文件
:param file_name:文件名
:return:
'''
size
=
os.stat(file_path).st_size
file_name
=
os.path.basename(file_path)
obj.sendall(bytes(
str
(size)
+
','
+
file_name,encoding
=
'utf-8'
))
#发送文件大小和文件名
ret
=
obj.recv(
1024
)
#接收已经传了多少
r
=
str
(ret,encoding
=
'utf-8'
)
if
r
=
=
's'
:
#文件不存在,从头开始传
has_send
=
0
else
:
#文件存在
has_send
=
int
(r)
with
open
(file_path,
'rb'
) as f:
f.seek(has_send)
#定位到已经传到的位置
while
has_send<size:
data
=
f.read(
1024
)
obj.sendall(data)
has_send
+
=
len
(data)
sys.stdout.write(
'r'
)
#清空文件内容
time.sleep(
0.2
)
sys.stdout.write(
'已发送%s%%|%s'
%
(
int
(has_send
/
size
*
100
),(
round
(has_send
/
size
*
40
)
*
'★'
)))
sys.stdout.flush()
#强制刷出内存
print
(
"上传成功n"
)
def
command(command_name):
'''
执行命令
:param command_name:
:return:
'''
obj.sendall(bytes(command_name,encoding
=
'utf-8'
))
ret
=
obj.recv(
1024
)
#接收命令需要接收的次数
obj.sendall(bytes(
'收到次数'
,encoding
=
'utf-8'
))
r
=
str
(ret,encoding
=
'utf-8'
)
for
i
in
range
(
int
(r)):
#共需要接收int(r)次
ret
=
obj.recv(
1024
)
#等待客户端发送
r
=
str
(ret,encoding
=
'GBK'
)
print
(r)
def
login(usrname,pwd):
'''
登陆
:param usrname:用户名
:param pwd:密码
:return:是否登陆成功
'''
obj.sendall(bytes(usrname
+
','
+
pwd,encoding
=
'utf-8'
))
ret
=
obj.recv(
1024
)
r
=
str
(ret,encoding
=
'utf-8'
)
if
r
=
=
'y'
:
return
1
else
:
return
0
def
regist(usrname,pwd):
'''
注册
:param usrname:用户名
:param pwd:密码
:return:是否注册成功
'''
obj.sendall(bytes(usrname
+
','
+
pwd,encoding
=
'utf-8'
))
ret
=
obj.recv(
1024
)
r
=
str
(ret,encoding
=
'utf-8'
)
if
r
=
=
'y'
:
return
1
else
:
return
0
def
before(usrname,pwd):
'''
选择登陆或注册,展示用户的详细目录信息,支持cd和ls命令
:return:
'''
a
=
input
(
'请选择1.登陆 2.注册'
)
obj.sendall(bytes(a,encoding
=
'utf-8'
))
obj.recv(
1024
)
if
a
=
=
'1'
:
ret
=
login(usrname,pwd)
if
ret:
print
(
'登陆成功'
)
return
1
else
:
print
(
'用户名或密码错误'
)
return
0
elif
a
=
=
'2'
:
ret
=
regist(usrname,pwd)
if
ret:
print
(
'注册成功'
)
return
1
else
:
print
(
'用户名已存在'
)
return
0
def
usr_file(usrname):
obj.sendall(bytes(
'打印用户文件路径'
,encoding
=
'utf-8'
))
ret
=
obj.recv(
1024
)
#等待客户端发送
r
=
str
(ret,encoding
=
'utf-8'
)
print
(r)
while
True
:
a
=
input
(
'输入cd切换目录,ls查看目录详细信息,q退出>:'
)
obj.sendall(bytes(a,encoding
=
'utf-8'
))
if
a
=
=
'q'
:
break
else
:
ret
=
obj.recv(
1024
)
#等待客户端发送
r
=
str
(ret,encoding
=
'utf-8'
)
if
len
(r)
=
=
1
:
#判断是cd结果还是ls的结果(ls只有一个子目录也可以直接打印)
print
(r)
else
:
li
=
r.split(
','
)
for
i
in
li:
print
(i)
#打印每一个子目录
def
main(usrname,pwd):
ret
=
obj.recv(
1024
)
#等待客户端发送
r
=
str
(ret,encoding
=
'utf-8'
)
print
(r)
result
=
before(usrname,pwd)
#登陆或注册
if
result:
usr_file(usrname)
while
True
:
a
=
input
(
'请选择1.传文件 2.执行命令 q退出:'
)
obj.sendall(bytes(
str
(a),encoding
=
'utf-8'
))
ret
=
obj.recv(
1024
)
#确认是否收到a
r
=
str
(ret,encoding
=
'utf-8'
)
print
(r)
if
a
=
=
'1'
:
b
=
input
(
'请输入文件路径(测试版路径为:f.png):'
)
# b='f.png'
if
os.path.exists(b):
send_file(b)
obj.sendall(bytes(
'hhe'
,encoding
=
'utf-8'
))
# obj.recv(1024)
elif
a
=
=
'2'
:
b
=
input
(
'请输入command:'
)
command(b)
elif
a
=
=
'q'
:
break
else
:
print
(
'输入错误'
)
obj.close()
if
__name__
=
=
'__main__'
:
obj
=
socket.socket()
#创建客户端socket对象
obj.connect((
'127.0.0.1'
,
9999
))
usrname
=
input
(
'请输入用户名'
)
pwd
=
input
(
'请输入密码'
)
main(usrname,pwd)
总结
以上就是python实现可以断点续传和并发的ftp程序的全部内容,文章介绍的很详细,希望对大家学习或者使用python带来一定的帮助。