493 lines
12 KiB
Markdown
493 lines
12 KiB
Markdown
# FTP 服务器设计与实现报告
|
||
|
||
## 项目概述
|
||
|
||
### 设计题目
|
||
**编程实现 FTP 服务器 ★★★**
|
||
|
||
### 设计要求
|
||
1. 客户端通过 Windows 的命令行访问 FTP 服务器
|
||
2. FTP 服务器可以并发地服务多个客户
|
||
3. 至少实现对 FTP 命令 user、pass、dir、get 的支持
|
||
4. FTP 服务器必须对出现的问题或错误做出响应
|
||
|
||
### 技术栈
|
||
- **编程语言**: Python 3.13+
|
||
- **网络编程**: Socket 编程
|
||
- **并发处理**: Threading 多线程
|
||
- **协议标准**: RFC 959 FTP 协议
|
||
|
||
## 系统架构设计
|
||
|
||
### 整体架构
|
||
|
||
```mermaid
|
||
graph TB
|
||
A[Windows FTP Client] --> B[FTP Server Main]
|
||
B --> C[Control Connection Handler]
|
||
B --> D[Threading Manager]
|
||
C --> E[Command Parser]
|
||
C --> F[Data Connection Manager]
|
||
E --> G[User Authentication]
|
||
E --> H[File Operations]
|
||
F --> I[Active Mode]
|
||
F --> J[Passive Mode]
|
||
D --> K[Client Thread 1]
|
||
D --> L[Client Thread 2]
|
||
D --> M[Client Thread N]
|
||
|
||
style A fill:#e1f5fe
|
||
style B fill:#f3e5f5
|
||
style C fill:#e8f5e8
|
||
style D fill:#fff3e0
|
||
```
|
||
|
||
### 类设计图
|
||
|
||
```mermaid
|
||
classDiagram
|
||
class FTPServer {
|
||
+host: str
|
||
+port: int
|
||
+server_socket: socket
|
||
+running: bool
|
||
+client_threads: list
|
||
+start_server()
|
||
+handle_client()
|
||
+stop_server()
|
||
+cleanup_threads()
|
||
}
|
||
|
||
class FTPSession {
|
||
+client_socket: socket
|
||
+client_address: tuple
|
||
+data_socket: socket
|
||
+authenticated: bool
|
||
+username: str
|
||
+current_directory: str
|
||
+handle_session()
|
||
+handle_command()
|
||
+send_response()
|
||
}
|
||
|
||
class CommandHandler {
|
||
+handle_user()
|
||
+handle_pass()
|
||
+handle_list()
|
||
+handle_retr()
|
||
+handle_pwd()
|
||
+handle_cwd()
|
||
+handle_pasv()
|
||
+handle_port()
|
||
}
|
||
|
||
FTPServer --> FTPSession
|
||
FTPSession --> CommandHandler
|
||
```
|
||
|
||
### 数据流图
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant Client as Windows FTP Client
|
||
participant Server as FTP Server
|
||
participant Session as FTP Session
|
||
participant Auth as Authentication
|
||
participant FileOp as File Operations
|
||
|
||
Client->>Server: TCP Connection (Port 21)
|
||
Server->>Session: Create New Session
|
||
Session->>Client: 220 Service Ready
|
||
|
||
Client->>Session: USER username
|
||
Session->>Auth: Validate User
|
||
Auth->>Session: User OK
|
||
Session->>Client: 331 Password Required
|
||
|
||
Client->>Session: PASS password
|
||
Session->>Auth: Authenticate
|
||
Auth->>Session: Login Success
|
||
Session->>Client: 230 User Logged In
|
||
|
||
Client->>Session: LIST
|
||
Session->>Client: 150 Opening Data Connection
|
||
Session->>FileOp: Get Directory Listing
|
||
FileOp->>Session: File List
|
||
Session->>Client: Directory Data
|
||
Session->>Client: 226 Transfer Complete
|
||
|
||
Client->>Session: RETR filename
|
||
Session->>Client: 150 Opening Data Connection
|
||
Session->>FileOp: Read File
|
||
FileOp->>Session: File Data
|
||
Session->>Client: File Data
|
||
Session->>Client: 226 Transfer Complete
|
||
```
|
||
|
||
## FTP 协议分析
|
||
|
||
### RFC 959 标准
|
||
FTP (File Transfer Protocol) 是基于 TCP 的应用层协议,使用两个连接:
|
||
- **控制连接** (端口 21): 传输命令和响应
|
||
- **数据连接**: 传输文件数据和目录列表
|
||
|
||
### 支持的 FTP 命令
|
||
|
||
| 命令 | 功能 | 实现状态 |
|
||
|------|------|----------|
|
||
| USER | 用户身份验证 | ✅ 已实现 |
|
||
| PASS | 密码验证 | ✅ 已实现 |
|
||
| LIST | 目录列表 (对应 DIR) | ✅ 已实现 |
|
||
| NLST | 简单文件列表 | ✅ 已实现 |
|
||
| RETR | 文件下载 (对应 GET) | ✅ 已实现 |
|
||
| PWD | 显示当前目录 | ✅ 已实现 |
|
||
| CWD | 改变目录 | ✅ 已实现 |
|
||
| PASV | 被动模式 | ✅ 已实现 |
|
||
| PORT | 主动模式 | ✅ 已实现 |
|
||
| TYPE | 传输类型 | ✅ 已实现 |
|
||
| SYST | 系统信息 | ✅ 已实现 |
|
||
| QUIT | 退出连接 | ✅ 已实现 |
|
||
|
||
### FTP 响应码
|
||
|
||
```mermaid
|
||
graph LR
|
||
A[FTP 响应码] --> B[2xx 成功]
|
||
A --> C[3xx 需要更多信息]
|
||
A --> D[4xx 临时错误]
|
||
A --> E[5xx 永久错误]
|
||
|
||
B --> B1[220 服务就绪]
|
||
B --> B2[230 用户登录成功]
|
||
B --> B3[226 传输完成]
|
||
|
||
C --> C1[331 需要密码]
|
||
|
||
D --> D1[425 无法打开数据连接]
|
||
|
||
E --> E1[530 未登录]
|
||
E --> E2[550 文件不存在]
|
||
```
|
||
|
||
## 核心模块设计
|
||
|
||
### 1. 配置模块 (config.py)
|
||
```python
|
||
# 服务器配置
|
||
FTP_HOST = '127.0.0.1'
|
||
FTP_PORT = 21
|
||
DATA_PORT_RANGE = (20000, 20100)
|
||
|
||
# 用户认证
|
||
USERS = {
|
||
'admin': 'admin123',
|
||
'user': 'password',
|
||
'test': 'test123',
|
||
'guest': 'guest'
|
||
}
|
||
|
||
# FTP 响应码
|
||
FTP_RESPONSES = {
|
||
'220': '220 Service ready for new user.',
|
||
'230': '230 User logged in, proceed.',
|
||
'331': '331 User name okay, need password.',
|
||
# ... 更多响应码
|
||
}
|
||
```
|
||
|
||
### 2. 主服务器模块 (ftp_server.py)
|
||
- **多线程处理**: 每个客户端连接创建独立线程
|
||
- **信号处理**: 优雅关闭服务器
|
||
- **连接管理**: 管理活跃连接和线程清理
|
||
|
||
### 3. 会话处理模块 (ftp_session.py)
|
||
- **命令解析**: 解析和路由 FTP 命令
|
||
- **状态管理**: 维护用户认证状态和当前目录
|
||
- **数据传输**: 处理被动/主动模式数据连接
|
||
|
||
## 关键技术实现
|
||
|
||
### 1. 多线程并发处理
|
||
|
||
```mermaid
|
||
graph TD
|
||
A[主服务器线程] --> B[监听端口 21]
|
||
B --> C[接受客户端连接]
|
||
C --> D[创建客户端线程]
|
||
D --> E[FTP 会话处理]
|
||
E --> F[命令处理循环]
|
||
F --> G[响应客户端]
|
||
G --> F
|
||
F --> H[连接关闭]
|
||
H --> I[线程结束]
|
||
|
||
style A fill:#ffeb3b
|
||
style D fill:#4caf50
|
||
style E fill:#2196f3
|
||
```
|
||
|
||
### 2. 用户认证机制
|
||
|
||
```mermaid
|
||
stateDiagram-v2
|
||
[*] --> 未认证
|
||
未认证 --> 用户名验证 : USER command
|
||
用户名验证 --> 密码验证 : PASS command
|
||
密码验证 --> 已认证 : 认证成功
|
||
密码验证 --> 未认证 : 认证失败
|
||
已认证 --> 未认证 : QUIT command
|
||
已认证 --> [*] : 连接断开
|
||
```
|
||
|
||
### 3. 数据连接管理
|
||
|
||
#### 被动模式 (PASV)
|
||
```python
|
||
def handle_pasv(self):
|
||
# 创建数据监听套接字
|
||
self.passive_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||
|
||
# 绑定到可用端口
|
||
for port in range(DATA_PORT_RANGE[0], DATA_PORT_RANGE[1]):
|
||
try:
|
||
self.passive_socket.bind(('127.0.0.1', port))
|
||
break
|
||
except OSError:
|
||
continue
|
||
|
||
# 返回 PASV 响应
|
||
p1 = port // 256
|
||
p2 = port % 256
|
||
self.send_response('227', f'Entering Passive Mode (127,0,0,1,{p1},{p2})')
|
||
```
|
||
|
||
#### 主动模式 (PORT)
|
||
```python
|
||
def handle_port(self, args):
|
||
# 解析 PORT 命令参数
|
||
parts = args.split(',')
|
||
ip = '.'.join(parts[:4])
|
||
port = int(parts[4]) * 256 + int(parts[5])
|
||
|
||
# 保存客户端数据连接地址
|
||
self.data_address = (ip, port)
|
||
```
|
||
|
||
### 4. 文件传输实现
|
||
|
||
#### 目录列表 (LIST/DIR)
|
||
```python
|
||
def handle_list(self, command):
|
||
# 建立数据连接
|
||
if not self.establish_data_connection():
|
||
return
|
||
|
||
# 获取目录内容
|
||
files = os.listdir(self.current_directory)
|
||
listing = []
|
||
|
||
for filename in files:
|
||
if command == 'LIST':
|
||
# 详细列表格式
|
||
stat = os.stat(filepath)
|
||
listing.append(f'{permissions} {size} {mtime} {filename}')
|
||
else:
|
||
# 简单列表格式
|
||
listing.append(filename)
|
||
|
||
# 发送数据
|
||
data = '\r\n'.join(listing) + '\r\n'
|
||
self.data_socket.send(data.encode('utf-8'))
|
||
```
|
||
|
||
#### 文件下载 (RETR/GET)
|
||
```python
|
||
def handle_retr(self, filename):
|
||
# 安全检查
|
||
filepath = os.path.normpath(os.path.join(self.current_directory, filename))
|
||
if not filepath.startswith(SERVER_ROOT):
|
||
self.send_response('550', 'Permission denied')
|
||
return
|
||
|
||
# 建立数据连接
|
||
if not self.establish_data_connection():
|
||
return
|
||
|
||
# 传输文件
|
||
with open(filepath, 'rb') as f:
|
||
while True:
|
||
data = f.read(8192)
|
||
if not data:
|
||
break
|
||
self.data_socket.send(data)
|
||
```
|
||
|
||
## 安全性设计
|
||
|
||
### 1. 路径安全
|
||
- **路径规范化**: 使用 `os.path.normpath()` 防止路径遍历
|
||
- **根目录限制**: 确保所有文件操作在服务器根目录内
|
||
- **权限检查**: 验证文件访问权限
|
||
|
||
### 2. 用户认证
|
||
- **密码验证**: 简单的用户名/密码认证机制
|
||
- **会话管理**: 维护用户登录状态
|
||
- **权限控制**: 未认证用户无法执行文件操作
|
||
|
||
### 3. 错误处理
|
||
- **异常捕获**: 全面的异常处理机制
|
||
- **错误响应**: 标准 FTP 错误码响应
|
||
- **资源清理**: 确保连接和文件句柄正确关闭
|
||
|
||
## 测试方案
|
||
|
||
### 1. 功能测试
|
||
|
||
#### Windows 命令行测试
|
||
```cmd
|
||
# 连接到 FTP 服务器
|
||
ftp 127.0.0.1
|
||
|
||
# 用户认证
|
||
USER admin
|
||
PASS admin123
|
||
|
||
# 目录操作
|
||
PWD
|
||
DIR
|
||
CD documents
|
||
|
||
# 文件下载
|
||
GET readme.txt
|
||
GET sample.txt
|
||
|
||
# 退出
|
||
QUIT
|
||
```
|
||
|
||
### 2. 并发测试
|
||
- 多个客户端同时连接
|
||
- 并发文件传输测试
|
||
- 线程安全验证
|
||
|
||
### 3. 错误处理测试
|
||
- 无效用户名/密码
|
||
- 不存在的文件/目录
|
||
- 网络连接中断
|
||
- 权限拒绝场景
|
||
|
||
## 项目文件结构
|
||
|
||
```
|
||
CN-design-ftp/
|
||
├── main.py # 程序入口
|
||
├── ftp_server.py # 主服务器类
|
||
├── ftp_session.py # 会话处理类
|
||
├── config.py # 配置文件
|
||
├── design_report.md # 设计报告
|
||
├── ftp_root/ # FTP 服务器根目录
|
||
│ ├── readme.txt # 说明文件
|
||
│ ├── sample.txt # 示例文本文件
|
||
│ ├── data.json # JSON 数据文件
|
||
│ └── documents/ # 子目录
|
||
│ └── test_doc.txt # 测试文档
|
||
└── test_files/ # 测试文件目录
|
||
```
|
||
|
||
## 使用说明
|
||
|
||
### 1. 启动服务器
|
||
```bash
|
||
python main.py
|
||
```
|
||
|
||
### 2. Windows 客户端连接
|
||
```cmd
|
||
ftp 127.0.0.1 2121
|
||
```
|
||
|
||
注意:由于使用非标准端口 2121(避免需要管理员权限),需要指定端口号。
|
||
|
||
### 3. 测试用户账号
|
||
| 用户名 | 密码 |
|
||
|--------|------|
|
||
| admin | admin123 |
|
||
| user | password |
|
||
| test | test123 |
|
||
| guest | guest |
|
||
|
||
### 4. 支持的命令映射
|
||
| Windows FTP 命令 | FTP 协议命令 | 功能 |
|
||
|------------------|--------------|------|
|
||
| USER username | USER | 用户登录 |
|
||
| PASS password | PASS | 密码验证 |
|
||
| DIR | LIST | 目录列表 |
|
||
| LS | NLST | 简单列表 |
|
||
| GET filename | RETR | 下载文件 |
|
||
| PWD | PWD | 当前目录 |
|
||
| CD dirname | CWD | 改变目录 |
|
||
| QUIT | QUIT | 退出连接 |
|
||
|
||
## 性能特点
|
||
|
||
### 1. 并发性能
|
||
- **多线程架构**: 支持多客户端并发访问
|
||
- **线程池管理**: 自动清理完成的线程
|
||
- **资源优化**: 合理的端口范围和连接管理
|
||
|
||
### 2. 可扩展性
|
||
- **模块化设计**: 清晰的模块分离
|
||
- **配置化**: 易于修改服务器参数
|
||
- **命令扩展**: 容易添加新的 FTP 命令
|
||
|
||
### 3. 稳定性
|
||
- **异常处理**: 全面的错误处理机制
|
||
- **优雅关闭**: 信号处理和资源清理
|
||
- **状态管理**: 可靠的会话状态维护
|
||
|
||
## 技术难点与解决方案
|
||
|
||
### 1. FTP 协议的双连接机制
|
||
**难点**: FTP 使用控制连接和数据连接分离的设计
|
||
**解决方案**:
|
||
- 实现被动模式 (PASV) 和主动模式 (PORT)
|
||
- 动态端口分配和连接管理
|
||
- 数据传输完成后及时关闭数据连接
|
||
|
||
### 2. 多线程并发处理
|
||
**难点**: 多客户端并发访问的线程安全
|
||
**解决方案**:
|
||
- 每个客户端独立线程处理
|
||
- 线程安全的资源管理
|
||
- 优雅的线程生命周期管理
|
||
|
||
### 3. Windows 兼容性
|
||
**难点**: 确保与 Windows FTP 客户端完全兼容
|
||
**解决方案**:
|
||
- 严格遵循 RFC 959 标准
|
||
- 正确的响应码和消息格式
|
||
- 支持 Windows FTP 客户端的命令映射
|
||
|
||
## 总结
|
||
|
||
本项目成功实现了一个功能完整的 FTP 服务器,满足了所有设计要求:
|
||
|
||
1. ✅ **Windows 命令行兼容**: 完全支持 Windows FTP 客户端
|
||
2. ✅ **并发处理**: 多线程架构支持多客户端同时访问
|
||
3. ✅ **核心命令支持**: 实现了 USER、PASS、DIR、GET 等关键命令
|
||
4. ✅ **错误处理**: 完善的错误响应和异常处理机制
|
||
|
||
### 技术亮点
|
||
- 严格遵循 RFC 959 FTP 协议标准
|
||
- 模块化和可扩展的代码架构
|
||
- 全面的安全性考虑
|
||
- 详细的文档和测试方案
|
||
|
||
### 学习收获
|
||
- 深入理解了 FTP 协议的工作原理
|
||
- 掌握了 Python Socket 网络编程
|
||
- 学会了多线程并发编程技术
|
||
- 提高了系统设计和架构能力
|
||
|
||
该 FTP 服务器可以作为计算机网络课程设计的优秀示例,展示了网络协议实现的完整过程。
|