[ python ] 项目一:FTP程序
声明:
该项目参考学习地址:
http://www.cnblogs.com/lianzhilei/p/5869205.html , 感谢博主分享,如有侵权,立即删除。
作业:开发一个支持多用户在线的FTP程序
要求:
- 用户加密认证
- 允许同时多用户登录
- 每个用户有自己的家目录 ,且只能访问自己的家目录
- 对用户进行磁盘配额,每个用户的可用空间不同
- 允许用户在ftp server上随意切换目录
- 允许用户查看当前目录下文件
- 允许上传和下载文件,保证文件一致性
- 文件传输过程中显示进度条
- 附加功能:支持文件的断点续传
程序:
1、README
- # 作者介绍:
- author: hkey
- # 博客地址:
- # 功能实现:
- 作业:开发一个支持多用户在线的FTP程序
- 要求:
- 用户加密认证
- 允许同时多用户登录
- 每个用户有自己的家目录 ,且只能访问自己的家目录
- 对用户进行磁盘配额,每个用户的可用空间不同
- 允许用户在ftp server上随意切换目录
- 允许用户查看当前目录下文件
- 允许上传和下载文件,保证文件一致性
- 文件传输过程中显示进度条
- 附加功能:支持文件的断点续传
- # 目录结构:
- FTP/
- ├── ftp_client/ # ftp客户端程序
- │ ├── ftp_client.py # 客户端主程序
- │ ├── __init__.py
- └── ftp_server/ # ftp服务端程序
- ├── conf/ # 配置文件目录
- │ ├── __init__.py
- │ └── settings.py
- ├── database/ # 用户数据库
- │ ├── hkey.db
- │ └── xiaofei.db
- ├── ftp_server.py
- ├── home/ # 用户家目录
- │ ├── hkey/
- │ └── xiaofei/
- ├── __init__.py
- ├── log/
- └── modules/ # 程序核心功能目录
- ├── auth_user.py
- ├── __init__.py
- └── socket_server.py
- # 功能实现:
- 1. 初始化配置在conf下的settings.py 文件里声明,第一次运行创建用户家目录(home/)和数据文件(database/)
- 2. 每个用户的磁盘配额为10M, 在conf/settings.py 中声明, 可以修改
- 3. 本程序适用于windows,命令:cd / mkdir / pwd / dir / put / get
- 4. 实现了get下载续传的功能:
- 服务器存在文件, 客户端不存在,直接下载;
- 服务器存在文件, 客户端也存在文件,比较大小, 一致则不传,不一致则追加续传;
- # 状态码:
- 400 用户认证失败
- 401 命令不正确
- 402 文件不存在
- 403 创建文件已经存在
- 404 磁盘空间不够
- 405 不续传
- 200 用户认证成功
- 201 命令可以执行
- 202 磁盘空间够用
- 203 文件具有一致性
- 205 续传
- # 作者介绍:
- author: hkey
- # 博客地址:
- http://www.cnblogs.com/hukey/p/8909046.html
- # 功能实现:
- 作业:开发一个支持多用户在线的FTP程序
- 要求:
- 用户加密认证
- 允许同时多用户登录
- 每个用户有自己的家目录 ,且只能访问自己的家目录
- 对用户进行磁盘配额,每个用户的可用空间不同
- 允许用户在ftp server上随意切换目录
- 允许用户查看当前目录下文件
- 允许上传和下载文件,保证文件一致性
- 文件传输过程中显示进度条
- 附加功能:支持文件的断点续传
- # 目录结构:
- FTP/
- ├── ftp_client/ # ftp客户端程序
- │ ├── ftp_client.py # 客户端主程序
- │ ├── __init__.py
- └── ftp_server/ # ftp服务端程序
- ├── conf/ # 配置文件目录
- │ ├── __init__.py
- │ └── settings.py
- ├── database/ # 用户数据库
- │ ├── hkey.db
- │ └── xiaofei.db
- ├── ftp_server.py
- ├── home/ # 用户家目录
- │ ├── hkey/
- │ └── xiaofei/
- ├── __init__.py
- ├── log/
- └── modules/ # 程序核心功能目录
- ├── auth_user.py
- ├── __init__.py
- └── socket_server.py
- # 功能实现:
- 1. 初始化配置在conf下的settings.py 文件里声明,第一次运行创建用户家目录(home/)和数据文件(database/)
- 2. 每个用户的磁盘配额为10M, 在conf/settings.py 中声明, 可以修改
- 3. 本程序适用于windows,命令:cd / mkdir / pwd / dir / put / get
- 4. 实现了get下载续传的功能:
- 服务器存在文件, 客户端不存在,直接下载;
- 服务器存在文件, 客户端也存在文件,比较大小, 一致则不传,不一致则追加续传;
- # 状态码:
- 400 用户认证失败
- 401 命令不正确
- 402 文件不存在
- 403 创建文件已经存在
- 404 磁盘空间不够
- 405 不续传
- 200 用户认证成功
- 201 命令可以执行
- 202 磁盘空间够用
- 203 文件具有一致性
- 205 续传
- 000 系统交互码
README
2、程序的结构
3、ftp客户端程序
- #!/usr/bin/env python
- # -*- coding:utf-8 -*-
- import socket
- import os, json, sys
- class Myclient(object):
- def __init__(self, ip_port):
- self.client = socket.socket()
- self.ip_port = ip_port
- def connect(self):
- self.client.connect(self.ip_port)
- def start(self):
- self.connect()
- while True:
- username = input('输入用户名:').strip()
- password = input('输入密码:').strip()
- login_info = '%s:%s' % (username, password)
- self.client.sendall(login_info.encode())
- status_code = self.client.recv(1024).decode()
- if status_code == '':
- print('[%s] 用户密码错误!' % status_code)
- elif status_code == '':
- print('[%s] 登录成功!' % status_code)
- self.interactive()
- def interactive(self):
- while True:
- command = input('-->').strip()
- if not command: continue
- command_str = command.split()[0]
- if hasattr(self, command_str):
- func = getattr(self, command_str)
- func(command)
- def get(self, command):
- self.client.sendall(command.encode())
- status_code = self.client.recv(1024).decode()
- if status_code == '':
- filename = command.split()[1]
- print(filename)
- if os.path.isfile(filename):
- self.client.sendall(''.encode())
- revice_size = os.stat(filename).st_size
- response = self.client.recv(1024)
- self.client.sendall(str(revice_size).encode())
- status_code = self.client.recv(1024).decode()
- print('-----------------')
- if status_code == '':
- print('[%s] 续传' % status_code)
- self.client.sendall(''.encode())
- elif status_code == '':
- print('[%s] 文件一致。' % status_code)
- return
- else:
- self.client.sendall(''.encode())
- revice_size = 0
- file_size = self.client.recv(1024).decode()
- file_size = int(file_size)
- response = self.client.sendall(''.encode())
- with open(filename, 'ab') as file:
- while revice_size != file_size:
- data = self.client.recv(1024)
- revice_size += len(data)
- file.write(data)
- self.__progress(revice_size, file_size, '下载中')
- else:
- print('[%s] Error!' % status_code)
- def put(self, command):
- if len(command.split()) > 1:
- filename = command.split()[1]
- if os.path.isfile(filename):
- self.client.sendall(command.encode())
- response = self.client.recv(1024)
- file_size = os.stat(filename).st_size
- self.client.sendall(str(file_size).encode())
- status_code = self.client.recv(1024).decode()
- if status_code == '':
- with open(filename, 'rb') as file:
- for line in file:
- send_size = file.tell()
- self.client.sendall(line)
- self.__progress(send_size, file_size, '上传中')
- elif status_code == '':
- print('[%s] Error!' % status_code)
- else:
- print('[401] Error!')
- def dir(self, command):
- self.__universal_method_data(command)
- def pwd(self, command):
- self.__universal_method_data(command)
- def mkdir(self, command):
- self.__universal_method_none(command)
- def cd(self, command):
- self.__universal_method_none(command)
- def __universal_method_none(self, command):
- self.client.sendall(command.encode())
- status_code = self.client.recv(1024).decode()
- if status_code == '':
- self.client.sendall(''.encode())
- else:
- print('[%s] Error!' % status_code)
- def __universal_method_data(self, command):
- self.client.sendall(command.encode())
- status_code = self.client.recv(1024).decode()
- print(status_code)
- if status_code == '':
- self.client.sendall(''.encode())
- result = self.client.recv(1024).decode()
- print(result)
- else:
- print('[%s] Error!' % status_code)
- def __progress(self, trans_size, file_size, mode):
- bar_length = 100
- percent = float(trans_size) / float(file_size)
- hashes = '=' * int(percent * bar_length)
- spaces = ' ' * int(bar_length - len(hashes))
- sys.stdout.write('\r%s:%.2fM/%.2fM %d%% [%s]' \
- % (mode, trans_size/1048576, file_size/1048576, percent*100, hashes+spaces))
- if __name__ == '__main__':
- client = Myclient(('localhost', 8000))
- client.start()
ftp_client.py
4、ftp服务端启动程序
- #!/usr/bin/env python
- # -*- coding:utf-8 -*-
- import os, json
- from conf import settings
- from modules import socket_server
- def create_db():
- user_database = {}
- limit_size = settings.LIMIT_SIZE
- for k, v in settings.USER_INFO.items():
- username = k
- password = v
- user_home_path = settings.HOME_DIR + r'\%s' % username
- user_db_path = settings.DATABASE_DIR + r'\%s.db' % username
- user_database['username'] = username
- user_database['password'] = password
- user_database['limitsize'] = limit_size
- user_database['homepath'] = user_home_path
- if not os.path.isfile(user_db_path):
- with open(user_db_path, 'w') as file:
- file.write(json.dumps(user_database))
- def create_home():
- for username in settings.USER_INFO:
- user_home_path = settings.HOME_DIR + r'\%s' % username
- if not os.path.isdir(user_home_path):
- os.popen('mkdir %s' % user_home_path)
- if __name__ == '__main__':
- create_db()
- create_home()
- server = socket_server.socketserver.ThreadingTCPServer(settings.IP_PORT, socket_server.Myserver)
- server.serve_forever()
ftp_server.py
5、conf配置文件
- #!/usr/bin/env python
- # -*- coding:utf-8 -*-
- import os, sys
- # 程序主目录
- BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
- sys.path.insert(0, BASE_DIR)
- # 数据库目录
- DATABASE_DIR = os.path.join(BASE_DIR, 'database')
- # 用户家目录
- HOME_DIR = os.path.join(BASE_DIR, 'home')
- # 用户配额
- LIMIT_SIZE = 10240000
- # 用户信息
- USER_INFO = {'hkey': '', 'xiaofei': 'abc'}
- # ip and port
- IP_PORT = ('localhost', 8000)
settings.py
6、database 用户数据库(初始化生成,生成程序 - conf/settings.py)
- {"homepath": "E:\\py_code\\FTP\\ftp_server\\home\\hkey", "username": "hkey", "limitsize": 10240000, "password": ""}
hkey.db
- {"homepath": "E:\\py_code\\FTP\\ftp_server\\home\\xiaofei", "username": "xiaofei", "limitsize": 10240000, "password": "abc"}
xiaofei.db
7、modules 核心功能模块
- #!/usr/bin/env python
- # -*- coding:utf-8 -*-
- import json, os
- from conf import settings
- class User_operation(object):
- def authentication(self, login_info):
- username, password = login_info.split(':')
- DB_FILE = settings.DATABASE_DIR + r'\%s' % username
- if os.path.isfile(DB_FILE):
- user_database = self.cat_database(DB_FILE)
- if username == user_database['username'] and \
- password == user_database['password']:
- return user_database
- def cat_database(self, DB_FILE):
- with open(DB_FILE, 'r') as file:
- data = json.loads(file.read())
- return data
auth_user.py
- #!/usr/bin/env python
- # -*- coding:utf-8 -*-
- import socketserver
- import os, json
- from os.path import getsize, join
- from modules import auth_user
- from conf import settings
- class Myserver(socketserver.BaseRequestHandler):
- def handle(self):
- try:
- while True:
- login_info = self.request.recv(1024).decode()
- print(login_info)
- result = self.authenticat(login_info)
- status_code = result[0]
- self.request.sendall(status_code.encode())
- if status_code == '':
- continue
- self.user_db = result[1]
- self.user_current_path = self.user_db['homepath']
- self.user_home_path = self.user_db['homepath']
- while True:
- command = self.request.recv(1024).decode()
- command_str = command.split()[0]
- if hasattr(self, command_str):
- func = getattr(self, command_str)
- func(command)
- else:
- self.request.sendall(''.encode())
- except ConnectionResetError as e:
- self.request.close()
- print('Error:', e)
- def authenticat(self, login_info):
- auth = auth_user.User_operation()
- result = auth.authentication(login_info)
- if result:
- return '', result
- else:
- return '', result
- def get(self, command):
- print('func: get()')
- if len(command.split()) > 1:
- filename = command.split()[1]
- user_file_path = self.user_current_path + r'\%s' % filename
- if os.path.isfile(user_file_path):
- print(user_file_path)
- self.request.sendall(''.encode())
- file_size = os.stat(user_file_path).st_size
- status_code = self.request.recv(1024).decode()
- if status_code == '':
- self.request.sendall(''.encode())
- has_send_data = int(self.request.recv(1024).decode())
- if has_send_data < file_size:
- self.request.sendall(''.encode())
- response = self.request.recv(1024).decode()
- else:
- self.request.sendall(''.encode())
- return
- else:
- has_send_data = 0
- self.request.sendall(str(file_size).encode())
- response = self.request.recv(1024)
- with open(user_file_path, 'rb') as file:
- file.seek(has_send_data)
- self.request.sendall(file.read())
- else:
- self.request.sendall(''.encode())
- else:
- self.request.sendall(''.encode())
- def put(self, command):
- filename = command.split()[1]
- file_path = self.user_current_path + r'\%s' % filename
- self.request.sendall(''.encode())
- file_size = self.request.recv(1024).decode()
- file_size = int(file_size)
- limit_size = self.user_db['limitsize']
- used_size = self.__getdirsize(self.user_home_path)
- if limit_size >= file_size + used_size:
- self.request.sendall(''.encode())
- revice_size = 0
- with open(file_path, 'wb') as file:
- while revice_size != file_size:
- data = self.request.recv(1024)
- revice_size += len(data)
- file.write(data)
- else:
- self.request.sendall(''.encode())
- def dir(self, command):
- if len(command.split()) == 1:
- self.request.sendall(''.encode())
- response = self.request.recv(1024)
- send_data = os.popen('dir %s' % self.user_current_path)
- self.request.sendall(send_data.read().encode())
- else:
- self.request.sendall(''.encode())
- def pwd(self, command):
- if len(command.split()) == 1:
- self.request.sendall(''.encode())
- response = self.request.recv(1024)
- self.request.sendall(self.user_current_path.encode())
- else:
- self.request.sendall(''.encode())
- def mkdir(self, command):
- if len(command.split()) > 1:
- dir_name = command.split()[1]
- dir_path = self.user_current_path + r'\%s' % dir_name
- if not os.path.isdir(dir_path):
- self.request.sendall(''.encode())
- response = self.request.recv(1024)
- os.popen('mkdir %s' % dir_path)
- else:
- self.request.sendall(''.encode())
- else:
- self.request.sendall(''.encode())
- def cd(self, command):
- print(command)
- if len(command.split()) > 1:
- dir_name = command.split()[1]
- dir_path = self.user_current_path + r'\%s' % dir_name
- user_home_path = settings.HOME_DIR + r'\%s' % self.user_db['username']
- if dir_name == '..' and len(self.user_current_path) > len(user_home_path):
- self.request.sendall(''.encode())
- response = self.request.recv(1024)
- self.user_current_path = os.path.dirname(self.user_current_path)
- elif os.path.isdir(dir_path):
- self.request.sendall(''.encode())
- response = self.request.recv(1024)
- if dir_name != '.' and dir_name != '..':
- self.user_current_path += r'\%s' % dir_name
- else:
- self.request.sendall(''.encode())
- else:
- self.request.sendall(''.encode())
- def __getdirsize(self, home_path):
- size = 0
- for root, dirs, files in os.walk(home_path):
- size += sum([getsize(join(root, name)) for name in files])
- return size
socket_server.py
程序运行效果图:
get 续传功能
[ python ] 项目一:FTP程序的更多相关文章
- 用python开发简单ftp程序
根据alex老师视频开发的简单ftp程序,只能实现简单的get功能 ftp客户端程序: #!/usr/bin/env python #_*_ coding:utf-8 _*_ import socke ...
- python简单的ftp程序
服务器端 '''1.读取文件名2.检测文件是否存在3.打开文件4.检测文件大小5.发送文件大小给客户端6.等客户端确认7.开始边读边发数据8.发送md5'''import socket,os,time ...
- Python开发【项目】:FTP程序
作业:开发一个支持多用户在线的FTP程序 要求: 用户加密认证 允许同时多用户登录 每个用户有自己的家目录 ,且只能访问自己的家目录 对用户进行磁盘配额,每个用户的可用空间不同 允许用户在ftp se ...
- Python开发程序:FTP程序
作业:开发一个支持多用户在线的FTP程序 要求: 用户加密认证 允许同时多用户登录 每个用户有自己的家目录 ,且只能访问自己的家目录 对用户进行磁盘配额,每个用户的可用空间不同 允许用户在ftp se ...
- python实现FTP程序
python实现FTP程序 程序源码 上传功能 查看文件 cd功能 创建目录 程序源码 目录结构 服务端 主程序 import optparse import socketserver import ...
- (转)Python开发程序:支持多用户在线的FTP程序
原文链接:http://www.itnose.net/detail/6642756.html 作业:开发一个支持多用户在线的FTP程序 要求: 用户加密认证 允许同时多用户登录 每个用户有自己的家目录 ...
- Jenkins构建Python项目提示:'python' 不是内部或外部命令,也不是可运行的程序
问题描述: jenkin集成python项目,立即构建后,发现未执行成功,查看Console Output 提示:'Python' 不是内部或外部命令,也不是可运行的程序,如下图: 1.在 Windo ...
- 【Jenkins】jenkins构建python项目提示:'python' 不是内部或外部命令,也不是可运行的程序或批处理文件
一.问题:jenkins构建python项目提示:'python' 不是内部或外部命令,也不是可运行的程序或批处理文件 二.原因:要在jenkins配置本地环境变量 三.解决方案:添加python.e ...
- 老男孩python作业7-开发一个支持多用户在线的FTP程序
作业6:开发一个支持多用户在线的FTP程序 要求: 用户加密认证 允许同时多用户登录 每个用户有自己的家目录 ,且只能访问自己的家目录 对用户进行磁盘配额,每个用户的可用空间不同 允许用户在ftp s ...
随机推荐
- [bzoj] 3669 NOI2014 魔法森林 || LCT
原题 copy一篇题解:原链接 将边按照a排序,然后从小到大枚举,加入图中. 在图中用lct维护一棵两点之间b最大值尽量小的生成树. 当加入一条边(u, v)时: 如果(u, v)不连通,则直接加入这 ...
- HDU4812 D tree 【点分治 + 乘法逆元】
D树 时间限制:10000/5000 MS(Java / Others)内存限制:102400/102400 K(Java / Others) 总共提交5400个已接受的提交1144 问题描述 南京理 ...
- App.config的典型应用
----.net中XML的典型应用 第一种修改方式: 添加xml节点figguration内容, 微软提供了一种方案来读取connectionStrings里的内容 这样就可以拿到连接sql serv ...
- bzoj1878: [SDOI2009]HH的项链(主席树/离线+BIT)
这题有离线和在线两种做法. 离线:将查询区间按左端点排序,预处理出所有数下一次的出现位置,一开始将所有第一次出现的数a[i]++,之后当扫到这个数的时候a[next[i]]++,相当于差分,给之后 ...
- YBT 2.4 AC自动机
其实这个专题NOIP几乎不考 AC自动机,就是能让题自动AC的东西,是不是十分神奇 对的,就是这么神奇 AC自动机是解决多模式串与文本串匹配的问题 是KMP+Trie树的结合,也是一个毒瘤算法 Key ...
- JS深度合并对象
/** * 如果target(也就是FirstOBJ[key])存在, * 且是对象的话再去调用deepObjectMerge, * 否则就是FirstOBJ[key]里面没这个对象,需要与Secon ...
- LVM分区
使用LVM对磁盘进行初始化 pvcreate /dev/vdd 创建卷组 vgcreate vg /dev/vdd 备注:vg是卷组的名称,可改变. 查看卷组的详细信息 vgdisplay 下图是我执 ...
- Centos版本6的使用教程
Centos版本6的使用教程 1.打开VMware workstation 12 PRO 创建新的虚拟机. 2.使用典型类型配置. 3.选择稍后安装操作系统,可以在后面进行安装. 4.选择安装的系统 ...
- SpringMVC源码解析-DispatcherServlet启动流程和初始化
在使用springmvc框架,会在web.xml文件配置一个DispatcherServlet,这正是web容器开始初始化,同时会在建立自己的上下文来持有SpringMVC的bean对象. 先从Dis ...
- django-jet 中文文档
关于 JET是新式的Django管理界面并且增强了功能. 内容 文档 开始 安装django-jet 安装仪表盘 配置 配置文件 自动补全 紧凑内联 过滤器 仪表盘 自定义仪表盘 仪表盘模块 ...