参考网上一个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. CoInitialize浅析一

    大家都知道程序中若要使用COM组件则必须要先调用CoInitialize,该函数主要是用来初始化COM运行环境.但这个函数的作用域是以线程为单位还是以进程为单位呢?也许大家已经通过测试程序摸索出答案, ...

  2. JSTL String时间转成 date

    两个标签配合使用 <fmt:parseDate value="${integralRecord.startDate}" var="date1"/> ...

  3. js倒计时跳转链接

    (function(){ var loadUrl = 'http://www.cnblogs.com/naokr/',//跳转链接 loadTime = 3000,//跳转时间 reTime = 10 ...

  4. C# 二维数组相关知识记录

    //初始化一个数组 , ] { { , }, { , }, { , }, { , }, { , } }; //查某个字段的长度 print(name.GetLength()); //获得第一个字段的长 ...

  5. Codeforces Round #170 (Div. 2)

    A. Circle Line 考虑环上的最短距离. B. New Problem \(n\) 个串建后缀自动机. 找的时候bfs一下即可. C. Learning Languages 并查集维护可以沟 ...

  6. IDEA IntelliJ常用设置以及快捷键(转)

    转载自:http://macrochen.iteye.com/blog/1035680 关于字体的设置 IDEA下使用雅黑Consolas混合字体      快捷贱, 快捷贱 , 快捷键贱    In ...

  7. System.DateUtils 1. DateOf、TimeOf 简单修饰功能

    编译版本:Delphi XE7 { Simple trimming functions } // 简单修饰功能 function DateOf(const AValue: TDateTime): TD ...

  8. ASP.NET Razor - C# 逻辑条件

    编程逻辑:根据条件执行代码. If 条件 C# 允许根据条件执行代码. 使用 if 语句来判断条件.根据判断结果,if 语句返回 true 或者 false: if 语句开始一个代码块 条件写在括号里 ...

  9. LeetCode-Sort Colors

    Given an array with n objects colored red, white or blue, sort them so that objects of the same colo ...

  10. [转]iOS代码块Block

    代码块Block是苹果在iOS4开始引入的对C语言的扩展,用来实现匿名函数的特性,Block是一种特殊的数据类型,其可以正常定义变量.作为参数.作为返回值,特殊地,Block还可以保存一段代码,在需要 ...