Python实现支持并发、断点续传的FTP

参考网上一个FTP程序,重写了一遍,并稍加扩展

一、要求

1. 支持多用户同时登录

2. 可以注册用户,密码使用md5加密

3. 可以登录已注册用户

4.  支持cd切换目录,ls查看目录子文件

5. 支持上传、下载文件

6. 可以执行命令,如:ipconfig

二、代码

配置文件

1 #!/usr/bin/env python
2 # -*- coding:utf-8 -*-
3
4 import os
5
6 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 python
  2 # -*- coding:utf-8 -*-
  3
  4 import os
  5 import hashlib
  6 import pickle
  7 import subprocess
  8 import socketserver
  9 from config import settings
 10
 11 baseHome = settings.BASE_HOME
 12 class MyServer(socketserver.BaseRequestHandler):
 13     def recv_file(self):
 14         ‘‘‘
 15         文件传输
 16         :return:
 17         ‘‘‘
 18         conn = self.request
 19         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)
 22         if 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)
 29         else:
 30             has_recv = 0
 31             conn.sendall(bytes(‘s‘,encoding=‘utf-8‘))   #客户端收到字符串s,从0开始发送
 32             with open(new_file_name, ‘wb‘) as f:
 33                 while has_recv<= int(file_size):
 34                     data = conn.recv(1024)
 35                     f.write(data)
 36                     has_recv += len(data)
 37
 38     def send_file(self, fileName):
 39         ‘‘‘
 40         向客户端发送文件
 41         :param fileName:
 42         :return:
 43         ‘‘‘
 44         filePath = os.path.join(self.currDir, fileName)
 45         conn = self.request
 46         if os.path.exists(filePath):
 47             size = os.stat(filePath).st_size
 48             conn.sendall(bytes(str(size)+‘,‘+fileName,encoding=‘utf-8‘))
 49             ret = conn.recv(1024)
 50             r = str(ret,encoding=‘utf-8‘)
 51             if r==‘s‘:
 52                 has_send = 0
 53             else:
 54                 has_send = int(r)
 55             with open(filePath,‘rb‘) as f:
 56                 f.seek(has_send)
 57                 while 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‘))
 62         else:
 63             conn.sendall(bytes(‘0‘, encoding=‘utf-8‘))
 64
 65     def 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)
 74         if os.path.exists(newFilePath):
 75             return ‘2‘
 76         else:
 77             ret = ‘0‘
 78             try:
 79                 os.makedirs(newFilePath)
 80                 ret = ‘1‘
 81             except OSError as e:
 82                 ret = ‘0‘
 83             return ret
 84
 85     def command(self):
 86         ‘‘‘
 87         执行命令
 88         :return:
 89         ‘‘‘
 90         conn = self.request
 91         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]+1
 96         conn.sendall(bytes(str(s), encoding=‘utf-8‘))
 97         conn.recv(1024)
 98         conn.sendall(ret2)
 99
100     def 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‘))
108         return hash.hexdigest()
109
110     def login(self, username, pwd):
111         ‘‘‘
112         登录
113         :param username:用户名
114         :param pwd: 密码
115         :return: 是否登录成功
116         ‘‘‘
117         if os.path.exists(settings.NAME_PWD):
118             s = pickle.load(open(settings.NAME_PWD,‘rb‘))
119         if username in s:
120             if s[username]==self.md5(pwd):
121                 return True
122             else:
123                 return False
124         else:
125             return False
126
127     def regist(self, username, pwd):
128         ‘‘‘
129         注册
130         :param username:用户名
131         :param pwd: 密码
132         :return: 是否注册成功
133         ‘‘‘
134         conn = self.request
135         s = {}
136         if os.path.exists(settings.NAME_PWD):
137             s = pickle.load(open(settings.NAME_PWD, ‘rb‘))
138         if username in s:
139             return False
140         else:
141             s[username] = self.md5(pwd)
142             mulu = os.path.join(settings.USER_FILE, username)
143             os.makedirs(mulu)
144             pickle.dump(s, open(settings.NAME_PWD, ‘wb‘))
145             return True
146
147     def before(self, username, pwd, ret):
148         ‘‘‘
149         判断注册和登录,并展示用户的详细目录信息,支持cd和ls命令
150         :param username: 用户名
151         :param pwd: 密码
152         :param ret:
153         :return:
154         ‘‘‘
155         conn = self.request
156         if ret == ‘1‘:
157             r = self.login(username,pwd)
158             if r:
159                 conn.sendall(bytes(‘y‘,encoding=‘utf-8‘))
160             else:
161                 conn.sendall(bytes(‘n‘,encoding=‘utf-8‘))
162         elif ret == ‘2‘:
163             r = self.regist(username, pwd)
164             if r:
165                 conn.sendall(bytes(‘y‘,encoding=‘utf-8‘))
166             else:
167                 conn.sendall(bytes(‘n‘,encoding=‘utf-8‘))
168
169     def user_file(self, username):
170         ‘‘‘
171         展示用户的详细目录信息,支持cd和ls命令
172         :param username: 用户名
173         :return:
174         ‘‘‘
175         conn = self.request
176         mulu = baseHome
177         self.currDir = mulu
178         conn.sendall(bytes(mulu, encoding=‘utf-8‘))
179         while True:
180             if conn:
181                 b = conn.recv(1024)
182                 ret = str(b, encoding=‘utf-8‘)
183                 try:
184                     a, b = ret.split(‘ ‘,1)
185                 except Exception as e:
186                     a = ret
187                 if a == ‘cd‘:
188                     if b==‘..‘:
189                         mulu = os.path.dirname(mulu)
190                     else:
191                         mulu = os.path.join(mulu, b)
192                     self.currDir = mulu
193                     conn.sendall(bytes(mulu, encoding=‘utf-8‘))
194                 elif a==‘ls‘:
195                     ls = os.listdir(mulu)
196                     print(ls)
197                     a = ‘,‘.join(ls)
198                     if a==‘‘:
199                         a = ‘.‘
200                     conn.sendall(bytes(a, encoding=‘utf-8‘))
201                 elif a==‘mkdir‘:
202                     m = self.createDir(self.currDir,b)
203                     conn.sendall(bytes(m, encoding=‘utf-8‘))
204                 elif a==‘q‘:
205                     break
206
207     def handle(self):
208         conn = self.request
209         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         self.user_file(username)
217         while True:
218             a=conn.recv(1024)
219             ret = str(a, encoding=‘utf-8‘)
220             if ret == ‘1‘:
221                 self.recv_file()
222             elif ret==‘2‘:
223                 self.command()
224             elif ret[0:4]==‘get:‘:
225                 self.send_file(ret[4:])
226             elif ret==‘q‘:
227                 break
228             else:
229                 pass
230
231 if __name__ == ‘__main__‘:
232     server = socketserver.ThreadingTCPServer((‘‘,9999), MyServer)
233     server.serve_forever()

客户端:

  1 #!/usr/bin/env python
  2 # -*-coding:utf-8 -*-
  3
  4 import os, sys
  5 import socket
  6
  7 def send_file(file_path):
  8     ‘‘‘
  9     发送文件
 10     :param file_path:文件名
 11     :return:
 12     ‘‘‘
 13     size = os.stat(file_path).st_size
 14     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‘)
 18     if r==‘s‘:  #文件不存在,从头开始传
 19         has_send = 0
 20     else:   #文件存在
 21         has_send = int(r)
 22     with open(file_path, ‘rb‘) as f:
 23         f.seek(has_send)    #定位到已经传到的位置
 24         while 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()  #强制刷出内存
 31     print(‘上传成功!\n‘)
 32
 33 def 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)
 44     if file_size == 0:
 45         print(‘没有找到此文件‘)
 46     else:
 47         new_file_name = os.path.join(toPath, file_name)
 48         if file_name in toPath:
 49             has_recv = os.stat(toPath).st_size
 50             obj.sendall(bytes(has_recv, encoding=‘utf-8‘))
 51             with open(new_file_name,‘ab‘) as f:
 52                 while 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()  # 强制刷出内存
 59         else:
 60             has_recv = 0
 61             obj.sendall(bytes(‘s‘, encoding=‘utf-8‘))
 62             with open(new_file_name, ‘wb‘) as f:
 63                 while 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()  # 强制刷出内存
 70         print(‘接收成功!\n‘)
 71
 72
 73 def 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‘)
 83     for i in range(int(r)):     #共需接收int(r)次
 84         ret = obj.recv(1024)    #等待客户端发送
 85         r = str(ret, encoding=‘GBK‘)
 86         print(r)
 87
 88 def 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‘)
 98     if r==‘y‘:
 99         return True
100     else:
101         return False
102
103 def 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‘)
113     if r==‘y‘:
114         return True
115     else:
116         return False
117
118 def 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()
128     if a==‘1‘:
129         ret = login(username, pwd)
130         if ret:
131             print(‘登录成功‘)
132             return 1
133         else:
134             print(‘用户名或密码错误‘)
135             return 0
136     elif a==‘2‘:
137         ret = regist(username, pwd)
138         if ret:
139             print(‘注册成功‘)
140             return 1
141         else:
142             print(‘用户名已存在‘)
143             return 0
144
145 def user_file(username):
146     # obj.sendall(bytes(‘打印用户文件路径‘, encoding=‘utf-8‘))
147     ret = obj.recv(1024)
148     r = str(ret, encoding=‘utf-8‘)
149     print(r)
150     while True:
151         a = input(‘输入 cd切换目录,ls查看目录详细信息,mkdir创建文件夹,q退出:‘)
152         a = a.strip()
153         obj.sendall(bytes(a, encoding=‘utf-8‘))
154         if a==‘q‘:
155             break
156         elif a[0:5]==‘mkdir‘:
157             ret = obj.recv(1024)
158             r = str(ret, encoding=‘utf-8‘)
159             if r==‘1‘:
160                 print(‘文件夹创建成功‘)
161             elif r==‘2‘:
162                 print(‘文件夹已存在!‘)
163             else:
164                 print(‘创建失败!‘)
165         else:
166             ret = obj.recv(1024)
167             r=str(ret, encoding=‘utf-8‘)
168             if len(r)==1:   #判断是cd结果,还是ls的结果(ls只有一个子目录,直接打印)
169                 print(r)
170             else:
171                 li = r.split(‘,‘)
172                 for i in li:
173                     print(i)
174
175 def main(username, pwd):
176     ret = obj.recv(1024)
177     r = str(ret, encoding=‘utf-8‘)
178     print(r)
179     result = before(username, pwd)  #判断登录/注册
180     if result:
181         user_file(username)
182         while True:
183             a = input(‘请选择 1.传文件 2.执行命令 3.收文件 q 退出:‘)
184             obj.sendall(bytes(str(a),encoding=‘utf-8‘))
185             if a==‘1‘:
186                 b = input(‘请输入文件路径:‘)
187                 if os.path.exists(b):
188                     send_file(b)
189                     obj.sendall(bytes(‘hhe‘, encoding=‘utf-8‘))
190             elif a==‘2‘:
191                 b = input(‘请输入command:‘)
192                 command(b)
193             elif a==‘3‘:
194                 b = input(‘请输入存放路径:‘)
195                 c = input(‘请输入要获取的文件:‘)
196                 recv_file(b, c)
197             elif a==‘q‘:
198                 break
199             else:
200                 print(‘输入错误!‘)
201
202     obj.close()
203
204 if __name__ == ‘__main__‘:
205     obj = socket.socket()
206     obj.connect((‘192.168.1.100‘,9999))
207     username = input(‘请输入用户名:‘)
208     pwd = input(‘请输入密码:‘)
209     main(username, pwd)
时间: 2024-10-10 16:47:35

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.服

python 开发一个支持多用户在线的FTP

### 作者介绍:* author:lzl### 博客地址:* http://www.cnblogs.com/lianzhilei/p/5813986.html### 功能实现 作业:开发一个支持多用户在线的FTP程序 要求: 用户加密认证 允许同时多用户登录 每个用户有自己的家目录 ,且只能访问自己的家目录 对用户进行磁盘配额,每个用户的可用空间不同 允许用户在ftp server上随意切换目录 允许用户查看当前目录下文件 允许上传和下载文件,保证文件一致性 文件传输过程中显示进度条 附加功能

Python开发程序:支持多用户在线的FTP程序

作业:开发一个支持多用户在线的FTP程序 要求: 用户加密认证 允许同时多用户登录 每个用户有自己的家目录 ,且只能访问自己的家目录 对用户进行磁盘配额,每个用户的可用空间不同 允许用户在ftp server上随意切换目录 允许用户查看当前目录下文件 允许上传和下载文件,保证文件一致性 文件传输过程中显示进度条 附加功能:支持文件的断点续传(仅下载) 程序 1.最最重要的readme: ### 作者介绍: * author:lzl ### 博客地址: * http://www.cnblogs.c

linux下wget命令,支持断点续传,ftp、http、https等协议

转载的地址:http://blog.163.com/[email protected]/blog/static/32097310201171833420905/ 今天操作远端机器的时候发现少一个安装包, 需要传到对方的机器上,还能使用通过的老办法,直接SSH连上去了,发现传的很慢, 只有40K的样子, 看时间还需要二个多小时就有点受不了了.想想有一台FTP服务器上有这个文件,可以直接从FTP服务器上下载不就得了.本想电话指导着操作,但想到对面的操作能力,不禁心里又打起鼓来. 使用google搜了

改进的一行Python实现文件共享--支持并发

SimpleHTTPServer是python自带的一个简单的静态HTTP服务器, python2.x下只要切换到想要共享的目录简单地输入下面的命令,就可以打开该HTTP服务器: python -m SimpleHTTPServer [port] 其中,port是可选参数,用于指定使用的端口,默认使用的是8000端口. 在python3.x中,SimpleHTTPServer模块被合并进了http.server模块中,所以,python3.x中命令略有不同: python3 -m http.se

开发一个支持多用户在线的FTP程序

一,项目题目:开发一个支持多用户在线的FTP程序 二,项目要求: 1.用户加密认证 2.允许同时多用户登录 3.每个用户有自己的家目录 ,且只能访问自己的家目录 4.对用户进行磁盘配额,每个用户的可用空间不同 5.允许用户在ftp server上随意切换目录 6.允许用户查看当前目录下文件 7.允许上传和下载文件,保证文件一致性(md5) 8.文件传输过程中显示进度条 9.附加功能:支持文件的断点续传 三,注意事项: 基本要求. 完成1,2,3,5,6,7,8 实力选手. 完成 上条 及需求4

Python 开源异步并发框架的未来(转)

Python 开源异步并发框架的未来 fantix 1.1k 2014年04月16日 发布 推荐 4 推荐 收藏 31 收藏,8.9k 浏览 呵呵,这个标题有点大,其实只是想从零开始介绍一下异步的基础,以及 Python 开源异步并发框架的发展和互操作性. 另外,这是我在 OSTC 2014 做的一个 20140330-OSTC-分论坛1王川 http://v.youku.com/v_show/id_XNjk2ODI0ODQ4.html ,幻灯片在这里,欢迎拍砖. 开源 Python 是开源的,

Python开源异步并发框架

Python开源异步并发框架的未来 2014年3月30日,由全球最大的中文IT社区CSDN主办的“开源技术大会·2014” (Open Source Technology Conference 2014,简称OSTC 2014)在北京丽亭华苑酒店召开. 本次大会以“启蒙·开源”(Open Mind, Open Source)为主题,邀请到了来自全国各地的30多位开源业界资深人士发表主题演讲,数十个开源社区现场参与,到场的开源软件开发者.贡献者和开源爱好 者总人数超过500人.作为一场“接地气”的

Python中的并发编程

简介 我们将一个正在运行的程序称为进程.每个进程都有它自己的系统状态,包含内存状态.打开文件列表.追踪指令执行情况的程序指针以及一个保存局部变量的调用栈.通常情况下,一个进程依照一个单序列控制流顺序执行,这个控制流被称为该进程的主线程.在任何给定的时刻,一个程序只做一件事情. 一个程序可以通过Python库函数中的os或subprocess模块创建新进程(例如os.fork()或是subprocess.Popen()).然而,这些被称为子进程的进程却是独立运行的,它们有各自独立的系统状态以及主线