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

一、要求

1. 支持多用户同时登录

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

3. 可以登录已注册用户

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

5. 支持上传、下载文件

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

二、代码

配置文件

 #!/usr/bin/env python
# -*- coding:utf-8 -*- import os BASE_DIR = os.path.dirname(os.path.dirname(__file__))
BASE_HOME = os.path.join(BASE_DIR, 'home')
NAME_PWD = os.path.join(BASE_DIR, 'db', 'name_pwd')
USER_FILE = os.path.join(BASE_DIR, 'db')

服务端:

 #!/usr/bin/env python
# -*- coding:utf-8 -*- import os
import hashlib
import pickle
import subprocess
import socketserver
from config import settings baseHome = settings.BASE_HOME
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(baseHome, file_name)
if file_name in baseHome: #检测文件是否已存在,涉及断点续传
has_recv = os.stat(baseHome).st_size #计算临时文件大小
conn.sendall(bytes(has_recv, encoding='utf-8'))
with open(new_file_name,'ab') as f: #追加模式
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 send_file(self, fileName):
'''
向客户端发送文件
:param fileName:
:return:
'''
filePath = os.path.join(self.currDir, fileName)
conn = self.request
if os.path.exists(filePath):
size = os.stat(filePath).st_size
conn.sendall(bytes(str(size)+','+fileName,encoding='utf-8'))
ret = conn.recv(1024)
r = str(ret,encoding='utf-8')
if r=='s':
has_send = 0
else:
has_send = int(r)
with open(filePath,'rb') as f:
f.seek(has_send)
while has_send<size:
data = f.read(1024)
conn.sendall(data)
has_send+=len(data)
conn.sendall(bytes('', encoding='utf-8'))
else:
conn.sendall(bytes('', encoding='utf-8')) def createDir(self, currDir, newName):
'''
创建文件夹
:param currDir:当前所在目录
:param newName: 新文件夹名称
:return: 是否创建成功
'''
mulu = os.path.join(baseHome, currDir)
newFilePath = os.path.join(mulu, newName)
if os.path.exists(newFilePath):
return ''
else:
ret = ''
try:
os.makedirs(newFilePath)
ret = ''
except OSError as e:
ret = ''
return ret 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, username, pwd):
'''
登录
:param username:用户名
:param pwd: 密码
:return: 是否登录成功
'''
if os.path.exists(settings.NAME_PWD):
s = pickle.load(open(settings.NAME_PWD,'rb'))
if username in s:
if s[username]==self.md5(pwd):
return True
else:
return False
else:
return False def regist(self, username, pwd):
'''
注册
:param username:用户名
:param pwd: 密码
:return: 是否注册成功
'''
conn = self.request
s = {}
if os.path.exists(settings.NAME_PWD):
s = pickle.load(open(settings.NAME_PWD, 'rb'))
if username in s:
return False
else:
s[username] = self.md5(pwd)
mulu = os.path.join(settings.USER_FILE, username)
os.makedirs(mulu)
pickle.dump(s, open(settings.NAME_PWD, 'wb'))
return True def before(self, username, pwd, ret):
'''
判断注册和登录,并展示用户的详细目录信息,支持cd和ls命令
:param username: 用户名
:param pwd: 密码
:param ret:
:return:
'''
conn = self.request
if ret == '':
r = self.login(username,pwd)
if r:
conn.sendall(bytes('y',encoding='utf-8'))
else:
conn.sendall(bytes('n',encoding='utf-8'))
elif ret == '':
r = self.regist(username, pwd)
if r:
conn.sendall(bytes('y',encoding='utf-8'))
else:
conn.sendall(bytes('n',encoding='utf-8')) def user_file(self, username):
'''
展示用户的详细目录信息,支持cd和ls命令
:param username: 用户名
:return:
'''
conn = self.request
mulu = baseHome
self.currDir = mulu
conn.sendall(bytes(mulu, encoding='utf-8'))
while True:
if conn:
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)
self.currDir = mulu
conn.sendall(bytes(mulu, encoding='utf-8'))
elif a=='ls':
ls = os.listdir(mulu)
print(ls)
a = ','.join(ls)
if a=='':
a = '.'
conn.sendall(bytes(a, encoding='utf-8'))
elif a=='mkdir':
m = self.createDir(self.currDir,b)
conn.sendall(bytes(m, 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')
c = conn.recv(1024)
r = str(c, encoding='utf-8')
username, pwd = r.split(',')
self.before(username, pwd, ret)
self.user_file(username)
while True:
a=conn.recv(1024)
ret = str(a, encoding='utf-8')
if ret == '':
self.recv_file()
elif ret=='':
self.command()
elif ret[0:4]=='get:':
self.send_file(ret[4:])
elif ret=='q':
break
else:
pass if __name__ == '__main__':
server = socketserver.ThreadingTCPServer(('',9999), MyServer)
server.serve_forever()

客户端:

 #!/usr/bin/env python
# -*-coding:utf-8 -*- import os, sys
import socket def send_file(file_path):
'''
发送文件
:param file_path:文件名
: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') #情况文件内容
sys.stdout.write('已发送%s%%|%s' % (int(has_send/size*100), (round(has_send/size*40)*'|')))
sys.stdout.flush() #强制刷出内存
print('上传成功!\n') def recv_file(toPath, getFile):
'''
接收要下载的文件
:param toPath: 本地要保存文件的存放路径
:param getFile: 要下载的文件名称
:return:
'''
obj.sendall(bytes('get:'+getFile,encoding='utf-8'))
a = str(obj.recv(1024), encoding='utf-8')
file_size, file_name = a.split(',')
file_size = int(file_size)
if file_size == 0:
print('没有找到此文件')
else:
new_file_name = os.path.join(toPath, file_name)
if file_name in toPath:
has_recv = os.stat(toPath).st_size
obj.sendall(bytes(has_recv, encoding='utf-8'))
with open(new_file_name,'ab') as f:
while has_recv<=file_size:
data = obj.recv(1024)
f.write(data)
has_recv+=len(data)
sys.stdout.write('\r') # 情况文件内容
sys.stdout.write('已接收%s%%|%s' % (int(has_recv / file_size * 100), (round(has_recv / file_size * 40) * '|')))
sys.stdout.flush() # 强制刷出内存
else:
has_recv = 0
obj.sendall(bytes('s', encoding='utf-8'))
with open(new_file_name, 'wb') as f:
while has_recv<= file_size:
data = obj.recv(1024)
f.write(data)
has_recv += len(data)
sys.stdout.write('\r') # 情况文件内容
sys.stdout.write('已接收%s%%|%s' % (int(has_recv / file_size * 100), (round(has_recv / file_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(username, pwd):
'''
登录
:param username: 用户名
:param pwd: 密码
:return: 是否登录成功
'''
obj.sendall(bytes(username+','+pwd, encoding='utf-8'))
ret = obj.recv(1024)
r = str(ret, encoding='utf-8')
if r=='y':
return True
else:
return False def regist(username, pwd):
'''
注册
:param username: 用户名
:param pwd: 密码
:return: 是否注册成功
'''
obj.sendall(bytes(username+','+pwd, encoding='utf-8'))
ret = obj.recv(1024)
r = str(ret, encoding='utf-8')
if r=='y':
return True
else:
return False def before(username, pwd):
'''
选择注册和登录,并展示用户的详细目录信息,支持cd和ls命令
:param username: 用户名
:param pwd: 密码
:return:
'''
a = input('请选择 1.登录 2.注册:')
obj.sendall(bytes(a, encoding='utf-8'))
# obj.recv()
if a=='':
ret = login(username, pwd)
if ret:
print('登录成功')
return 1
else:
print('用户名或密码错误')
return 0
elif a=='':
ret = regist(username, pwd)
if ret:
print('注册成功')
return 1
else:
print('用户名已存在')
return 0 def user_file(username):
# obj.sendall(bytes('打印用户文件路径', encoding='utf-8'))
ret = obj.recv(1024)
r = str(ret, encoding='utf-8')
print(r)
while True:
a = input('输入 cd切换目录,ls查看目录详细信息,mkdir创建文件夹,q退出:')
a = a.strip()
obj.sendall(bytes(a, encoding='utf-8'))
if a=='q':
break
elif a[0:5]=='mkdir':
ret = obj.recv(1024)
r = str(ret, encoding='utf-8')
if r=='':
print('文件夹创建成功')
elif r=='':
print('文件夹已存在!')
else:
print('创建失败!')
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(username, pwd):
ret = obj.recv(1024)
r = str(ret, encoding='utf-8')
print(r)
result = before(username, pwd) #判断登录/注册
if result:
user_file(username)
while True:
a = input('请选择 1.传文件 2.执行命令 3.收文件 q 退出:')
obj.sendall(bytes(str(a),encoding='utf-8'))
if a=='':
b = input('请输入文件路径:')
if os.path.exists(b):
send_file(b)
obj.sendall(bytes('hhe', encoding='utf-8'))
elif a=='':
b = input('请输入command:')
command(b)
elif a=='':
b = input('请输入存放路径:')
c = input('请输入要获取的文件:')
recv_file(b, c)
elif a=='q':
break
else:
print('输入错误!') obj.close() if __name__ == '__main__':
obj = socket.socket()
obj.connect(('192.168.1.100',9999))
username = input('请输入用户名:')
pwd = input('请输入密码:')
main(username, pwd)

Python实现支持并发、断点续传的FTP的更多相关文章

  1. python如何支持并发?

    由于GIL(Global Interpreter Lock)的存在使得在同一时刻Python进程只能使用CPU的一个核心,也就是对应操作系统的一个 内核线程,对于一个Python web程序,如果有个 ...

  2. python实现支持并发、断点续传的Ftp程序

    一.要求 1.用户md5认证 2.支持多用户同时登陆(并发) 3.进入用户的命令行模式,支持cd切换目录,ls查看目录子文件 4.执行命令(ipconfig) 5.传输文件: a.支持断点续传 b.传 ...

  3. 第五十六节,python实现支持并发、断点续传的Ftp程序

    一.要求 1.用户md5认证 2.支持多用户同时登陆(并发) 3.进入用户的命令行模式,支持cd切换目录,ls查看目录子文件 4.执行命令(ipconfig) 5.传输文件: a.支持断点续传 b.传 ...

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

    ### 作者介绍:* author:lzl### 博客地址:* http://www.cnblogs.com/lianzhilei/p/5813986.html### 功能实现 作业:开发一个支持多用 ...

  5. (转)Python开发程序:支持多用户在线的FTP程序

    原文链接:http://www.itnose.net/detail/6642756.html 作业:开发一个支持多用户在线的FTP程序 要求: 用户加密认证 允许同时多用户登录 每个用户有自己的家目录 ...

  6. 老男孩python作业7-开发一个支持多用户在线的FTP程序

    作业6:开发一个支持多用户在线的FTP程序 要求: 用户加密认证 允许同时多用户登录 每个用户有自己的家目录 ,且只能访问自己的家目录 对用户进行磁盘配额,每个用户的可用空间不同 允许用户在ftp s ...

  7. Python3学习之路~8.6 开发一个支持多用户在线的FTP程序-代码实现

    作业: 开发一个支持多用户在线的FTP程序 要求: 用户加密认证 允许同时多用户登录 每个用户有自己的家目录 ,且只能访问自己的家目录 对用户进行磁盘配额,每个用户的可用空间不同 允许用户在ftp s ...

  8. Python开发【项目】:FTP程序

    作业:开发一个支持多用户在线的FTP程序 要求: 用户加密认证 允许同时多用户登录 每个用户有自己的家目录 ,且只能访问自己的家目录 对用户进行磁盘配额,每个用户的可用空间不同 允许用户在ftp se ...

  9. Python中的并发编程

    简介 我们将一个正在运行的程序称为进程.每个进程都有它自己的系统状态,包含内存状态.打开文件列表.追踪指令执行情况的程序指针以及一个保存局部变量的调用栈.通常情况下,一个进程依照一个单序列控制流顺序执 ...

随机推荐

  1. Android 媒体存储服务(一)

    Android 媒体存储服务 本文介绍如何在 Android 中,开发者的 APP 如何使用媒体存储服务(包含MediaScanner.MediaProvider以及媒体信息解析等部分),包括如何把 ...

  2. 优化 UltraEdit 打开大文件时的性能

    UltraEdit 原本就是被设计成可以打开超大文件的工具,只不过在默认情况下需要进行以下优化设置: 禁止临时文件 禁止显示行号 禁止文件(回车 & 换行符)转换 禁止代码折叠 禁止显示函数列 ...

  3. 105 董婷婷 第二次Sprint总结

    总结: 第二次冲刺结束了,这次冲刺的主要任务是建立数据库.项目进行到现在也基本定型了,满满的成就感啊.经过一段时间的合作,团队成员间的默契大大提高,还有最后一次冲刺,队友们,加油哦!

  4. 安装系统时出现“windows无法安装到这个磁盘。选中的的磁盘采用GPT分区形式”

    安装系统到提示你不能安装在那个磁盘的一步,然后按住shift+F10呼出diskpart命令符,然后依次输入 diskpart list disk select disk 0 clean conver ...

  5. Apache2 部署 Django

    环境: debian8 apache2.4.10                    #请注意自己的apache版本,不同版本配置文件结构差异很大 django1.10 python3.4 默认ap ...

  6. Chromuim proxy Api 提取代里proxy调用Chrome隐身多窗口 多COOKIE 工具

    Chromuim proxy Api提取proxy调用Chrome隐身 多COOKIES 多窗口工具每一个代理拥有一个独立的窗口和USERDATA 独立COOKIES 伪装UA UA:<scri ...

  7. 关于url传参中文乱码问题

    之前都一直很不了解中文编码得问题,之前在做项目中没碰到那么头痛的问题.所以一直没有了解中文乱码的问题. 问题描述: 地址: http://localhost:8080/sun-government/c ...

  8. Python3 之 import 和 当前目录

    环境: Python-3.4.3 Web.py-0.37 安装 web.py 的时候,提示 ImportError: No module named 'utils' 看看源码,setup.py,有这么 ...

  9. Nginx-默认不压缩HTTP/1.0与长连接的关系

    在移动的 http 请求量和联通不相上下的前提下,移动的 http response 带来的网络流量是联通的 2.5 倍.移动大概有 3 成的请求都没有做压缩,而联通几乎都是经过压缩的.那些没有经过压 ...

  10. .net解决程序集版本冲突的方法

    以log4net为例,分为两种情况 1.不同version,相同publicKeyToken 在bin里放较新版本的dll 并在web|app.config的<configuration> ...