作业需求:
1. 用户加密认证
2. 多用户同时登陆
3. 每个用户有自己的家目录且只能访问自己的家目录
4. 对用户进行磁盘配额、不同用户配额可不同
5. 用户可以登陆server后,可切换目录
6. 查看当前目录下文件
7. 上传下载文件,保证文件一致性
8. 传输过程中现实进度条
9. 支持断点续传
思路分析:
上一个简单服务器的升级版本,先一个版本链接:http://www.cnblogs.com/sean-yao/p/7772159.html,在原有代码中,重构并实现9个需求,提升程序健壮性:
更新如下:
1. FTP数据存储目录,使用相对路径 ,提升迁移性。
2. FTP在上传下载的时候有粘包处理,其他命令如ls,pls等也做了粘包处理。
3.增加了ConnectionResetError,Exception,UnicodeDecodeError,socket.error等异常处理。
对于高级FTP需求:
1. 用hashlib加密用户输入的密码让Server保存Md5值,实现简单认证加密。
2. 多用户同时登陆使用socketserver模块(上一版本已经实现),控制线程并发多用户同时登陆和操作。
3. 创建用户时候将密码文件FTP目录,相对路径写到密码文件中,认证成功后可以调用相对路径,然后使用OS模块的os.chdir($dir)进行切换用户家目录操作。
4. 用random函数随机一个512M-1024M之间的磁盘配额,(用户剩余空间 = 限额 - 家目录总文件大小)对比文件大小就可以进行磁盘配额的操作。
5. 用户操作使用cd命令,可以切换到家目录的任意目录(前一版本已经实现)。
6. 通过ls查看家目录下的二级目录三级目录等文件(前一版本已经实现)。
7. 上传下载文件,保证文件一致性使用hashlib,让服务端传送客户端进行校验。
8. 传输过程中现实进度条 上传和下载的进度条都已经完成,使用progressbar模块。
9. 断点续传,创建临时文件,客户端上传时,服务器检查临时文件,有就发大小发给客户端,客户端seek到文件断点处给服务器端发送数据。
代码示例:
此次作业是以上一个版本代码做的重构http://www.cnblogs.com/sean-yao/p/7772159.html,所以这里只放入新增加的部分包含ftp_client.py,ftp_server.py,total_size_class.py,auth.py
README:
作者:yaobin
版本:高级Ftp示例版本 v0.2
开发环境: python3.6
程序介绍:
1. 用户加密认证
2. 多用户同时登陆
3. 每个用户有自己的家目录且只能访问自己的家目录
4. 对用户进行磁盘配额、不同用户配额可不同
5. 用户可以登陆server后,可切换目录
6. 查看当前目录下文件
7. 上传下载文件,保证文件一致性
8. 传输过程中现实进度条
9. 支持断点续传
使用说明:
1.可以在Linux和Windows都可以运行
2.Linux调用了cd,mkdir,ls,rm,命令
3.Windows调用了cd,md,dir,del,命令
On Linux,Windows
Client: Python3 ./Ftp_Client.py
put 上传
get 下载
mkdir 创建目录
ls 查看文件信息
rm 删除文件
drm 删除目录
Server:Python3 ./Ftp_Server.py
put 上传
get 下载
mkdir 创建目录
ls 查看文件信息
rm 删除文件
drm 删除目录
文件目录结构:
├─简单Ftp #程序执行目录
│ README
│ __init__.py
│
├─bin
│ Ftp_Client.py #客户端程序
│ Ftp_Server.py #服务器端程序
│ __init__.py
│
├─conf
│ │ setting.py #配置文件
│ │ __init__.py
│ │
│ └─__pycache__
│ setting.cpython-36.pyc
│ __init__.cpython-36.pyc
│
├─core
│ │ auth.py #用户验证逻辑交互
│ │ commands.py #命令逻辑交互
│ │ ftp_client.py #sock_客户端逻辑交互
│ │ ftp_server.py #sock_服务端逻辑交互
│ │ logger.py #日志逻辑交互---未完成
│ │ main.py #客户端程序
│ │ __init__.py
│ │
│ └─__pycache__
│ auth.cpython-36.pyc
│ commands.cpython-36.pyc
│ ftp_client.cpython-36.pyc
│ ftp_server.cpython-36.pyc
│ main.cpython-36.pyc
│ __init__.cpython-36.pyc
│
├─db
│ │ __init__.py
│ │
│ ├─colin #用户目录
│ │ │ colin.bak
│ │ │ colin.dat #用户账号密码文件
│ │ │ colin.dir
│ │ │ __init__.py
│ │ │
│ │ └─colin #用户ftp家目录
│ │ │ __init__.py
│ │ │
│ │ └─aaa
│ ├─pub #ftp程序模拟pub目录
│ │ FTP作业.7z
│ │ socket通信client.py
│ │ __init__.py
│ │ 选课系统.png
│ │
│ └─user_path #用户路径文件,判断用户家目录
│ path
│
├─logs #日志未完成
│ access.log
│ transmission.log
│ __init__.py
│
├─src
│ │ auth_class.py #用户验证类
│ │ linux_cmd_class.py #linux命令类
│ │ server_class.py #server_socket类
│ │ windows_cmd_class.py #server命令类
│ │ __init__.py
│ │ total_size_class.py #磁盘配额类
│ └─__pycache__
│ auth_class.cpython-36.pyc
│ linux_cmd_class.cpython-36.pyc
│ server_class.cpython-36.pyc
│ windows_cmd_class.cpython-36.pyc
│ __init__.cpython-36.pyc
│
└─test #测试
args_test.py
__init__.py
ftp_client.py: FTP客户端交互程序
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: Colin Yao
import os
import sys
import socket
import time
import hashlib
import json
import progressbar
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)
from conf import setting
class Ftp_client(object):
def link(self):
try:
self.sending_msg_list = []
self.ip_addr = '127.0.0.1'
self.ip_port = 62000
self.client = socket.socket()
self.client.connect((self.ip_addr, self.ip_port))
while True:
self.sending_msg = None
self.data = self.client.recv(1024)
print("