Add README and design report updates, implement FTP test client, and enhance session handling
This commit is contained in:
		
							parent
							
								
									e51829abfa
								
							
						
					
					
						commit
						62a99abe3f
					
				
							
								
								
									
										238
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										238
									
								
								README.md
									
									
									
									
									
								
							@ -0,0 +1,238 @@
 | 
				
			|||||||
 | 
					# FTP 服务器实现 - 计算机网络课程设计
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					一个基于 Python 的多线程 FTP 服务器实现,支持 Windows 命令行客户端访问。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 项目概述
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					本项目实现了一个功能完整的 FTP 服务器,严格遵循 RFC 959 标准,支持:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- ✅ **多线程并发**: 支持多个客户端同时连接
 | 
				
			||||||
 | 
					- ✅ **用户认证**: USER/PASS 命令实现用户登录
 | 
				
			||||||
 | 
					- ✅ **目录操作**: LIST/DIR 命令显示文件列表
 | 
				
			||||||
 | 
					- ✅ **文件下载**: RETR/GET 命令下载文件
 | 
				
			||||||
 | 
					- ✅ **路径导航**: PWD/CWD 命令目录切换
 | 
				
			||||||
 | 
					- ✅ **错误处理**: 完善的错误响应机制
 | 
				
			||||||
 | 
					- ✅ **Windows 兼容**: 完全支持 Windows FTP 客户端
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 快速开始
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 1. 启动 FTP 服务器
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					python main.py
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					服务器将在 `127.0.0.1:2121` 启动(使用非特权端口避免需要管理员权限)。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 2. 使用 Windows FTP 客户端连接
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					打开 Windows 命令提示符:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```cmd
 | 
				
			||||||
 | 
					ftp 127.0.0.1 2121
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 3. 登录测试
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					使用以下测试账户:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					| 用户名 | 密码 |
 | 
				
			||||||
 | 
					|--------|------|
 | 
				
			||||||
 | 
					| admin | admin123 |
 | 
				
			||||||
 | 
					| user | password |
 | 
				
			||||||
 | 
					| test | test123 |
 | 
				
			||||||
 | 
					| guest | guest |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 4. 基本操作示例
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```cmd
 | 
				
			||||||
 | 
					# 连接服务器
 | 
				
			||||||
 | 
					ftp 127.0.0.1 2121
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 登录
 | 
				
			||||||
 | 
					User (127.0.0.1:(none)): admin
 | 
				
			||||||
 | 
					Password: admin123
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 查看当前目录
 | 
				
			||||||
 | 
					ftp> pwd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 列出文件
 | 
				
			||||||
 | 
					ftp> dir
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 下载文件
 | 
				
			||||||
 | 
					ftp> get readme.txt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 切换目录
 | 
				
			||||||
 | 
					ftp> cd documents
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 退出
 | 
				
			||||||
 | 
					ftp> quit
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 支持的 FTP 命令
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					| FTP 命令 | Windows 命令 | 功能描述 |
 | 
				
			||||||
 | 
					|----------|--------------|----------|
 | 
				
			||||||
 | 
					| USER | USER | 用户身份验证 |
 | 
				
			||||||
 | 
					| PASS | PASS | 密码验证 |
 | 
				
			||||||
 | 
					| LIST | DIR | 详细文件列表 |
 | 
				
			||||||
 | 
					| NLST | LS | 简单文件列表 |
 | 
				
			||||||
 | 
					| RETR | GET | 文件下载 |
 | 
				
			||||||
 | 
					| PWD | PWD | 显示当前目录 |
 | 
				
			||||||
 | 
					| CWD | CD | 改变目录 |
 | 
				
			||||||
 | 
					| PASV | - | 被动模式 |
 | 
				
			||||||
 | 
					| PORT | - | 主动模式 |
 | 
				
			||||||
 | 
					| TYPE | - | 传输类型设置 |
 | 
				
			||||||
 | 
					| SYST | - | 系统信息 |
 | 
				
			||||||
 | 
					| QUIT | QUIT | 退出连接 |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 项目结构
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					CN-design-ftp/
 | 
				
			||||||
 | 
					├── main.py                 # 程序入口点
 | 
				
			||||||
 | 
					├── ftp_server.py          # 主服务器类
 | 
				
			||||||
 | 
					├── ftp_session.py         # 客户端会话处理
 | 
				
			||||||
 | 
					├── config.py              # 服务器配置
 | 
				
			||||||
 | 
					├── test_ftp_client.py     # 测试客户端
 | 
				
			||||||
 | 
					├── design_report.md       # 详细设计报告
 | 
				
			||||||
 | 
					├── README.md              # 项目说明
 | 
				
			||||||
 | 
					├── ftp_root/              # FTP 服务器根目录
 | 
				
			||||||
 | 
					│   ├── readme.txt         # 服务器说明文件
 | 
				
			||||||
 | 
					│   ├── sample.txt         # 示例文本文件
 | 
				
			||||||
 | 
					│   ├── data.json          # JSON 数据文件
 | 
				
			||||||
 | 
					│   └── documents/         # 子目录示例
 | 
				
			||||||
 | 
					│       └── test_doc.txt   # 测试文档
 | 
				
			||||||
 | 
					└── test_files/            # 测试文件目录
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 技术特性
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 架构设计
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- **多线程服务器**: 每个客户端连接独立线程处理
 | 
				
			||||||
 | 
					- **模块化设计**: 清晰的代码结构和职责分离
 | 
				
			||||||
 | 
					- **配置化管理**: 易于修改服务器参数
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 安全特性
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- **路径安全**: 防止目录遍历攻击
 | 
				
			||||||
 | 
					- **用户认证**: 基于用户名/密码的访问控制
 | 
				
			||||||
 | 
					- **错误处理**: 全面的异常处理和错误响应
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 协议兼容性
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- **RFC 959 标准**: 严格遵循 FTP 协议规范
 | 
				
			||||||
 | 
					- **双连接模式**: 支持控制连接和数据连接
 | 
				
			||||||
 | 
					- **传输模式**: 支持被动模式和主动模式
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 测试
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 自动化测试
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					运行内置测试脚本:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					# 启动服务器(在一个终端)
 | 
				
			||||||
 | 
					python main.py
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 运行测试(在另一个终端)
 | 
				
			||||||
 | 
					python test_ftp_client.py
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 手动测试
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. **基本连接测试**
 | 
				
			||||||
 | 
					   ```bash
 | 
				
			||||||
 | 
					   telnet 127.0.0.1 2121
 | 
				
			||||||
 | 
					   ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2. **FTP 客户端测试**
 | 
				
			||||||
 | 
					   ```cmd
 | 
				
			||||||
 | 
					   ftp 127.0.0.1 2121
 | 
				
			||||||
 | 
					   ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					3. **并发测试**
 | 
				
			||||||
 | 
					   - 同时打开多个 FTP 客户端连接
 | 
				
			||||||
 | 
					   - 验证多用户并发访问
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 配置说明
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					编辑 `config.py` 文件可以修改服务器配置:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```python
 | 
				
			||||||
 | 
					# 服务器设置
 | 
				
			||||||
 | 
					FTP_HOST = '127.0.0.1'        # 服务器地址
 | 
				
			||||||
 | 
					FTP_PORT = 2121               # 服务器端口
 | 
				
			||||||
 | 
					DATA_PORT_RANGE = (20000, 20100)  # 数据连接端口范围
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 服务器目录
 | 
				
			||||||
 | 
					SERVER_ROOT = './ftp_root'    # FTP 根目录
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 用户账户
 | 
				
			||||||
 | 
					USERS = {
 | 
				
			||||||
 | 
					    'admin': 'admin123',
 | 
				
			||||||
 | 
					    'user': 'password',
 | 
				
			||||||
 | 
					    'test': 'test123',
 | 
				
			||||||
 | 
					    'guest': 'guest'
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 故障排除
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 常见问题
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. **端口被占用**
 | 
				
			||||||
 | 
					   - 修改 `config.py` 中的 `FTP_PORT` 为其他端口
 | 
				
			||||||
 | 
					   - 确保防火墙允许该端口通信
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2. **权限错误**
 | 
				
			||||||
 | 
					   - 确保 `ftp_root` 目录有读写权限
 | 
				
			||||||
 | 
					   - 在 macOS/Linux 上可能需要 `chmod 755 ftp_root`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					3. **连接被拒绝**
 | 
				
			||||||
 | 
					   - 检查服务器是否正常启动
 | 
				
			||||||
 | 
					   - 验证客户端连接的 IP 和端口是否正确
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					4. **文件传输失败**
 | 
				
			||||||
 | 
					   - 检查被动模式端口范围是否被防火墙阻止
 | 
				
			||||||
 | 
					   - 确保数据连接端口 (20000-20100) 可用
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 调试模式
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					服务器会在控制台输出详细的连接和命令日志,便于调试:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					FTP Server started on 127.0.0.1:2121
 | 
				
			||||||
 | 
					New connection from ('127.0.0.1', 54321)
 | 
				
			||||||
 | 
					Received from ('127.0.0.1', 54321): USER admin
 | 
				
			||||||
 | 
					Sent to ('127.0.0.1', 54321): 331 User admin OK. Password required
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 开发说明
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 扩展功能
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					要添加新的 FTP 命令:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. 在 `ftp_session.py` 的 `handle_command` 方法中添加命令路由
 | 
				
			||||||
 | 
					2. 实现对应的 `handle_xxx` 方法
 | 
				
			||||||
 | 
					3. 在 `config.py` 中添加相应的响应码
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 代码结构
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- `FTPServer`: 主服务器类,处理客户端连接
 | 
				
			||||||
 | 
					- `FTPSession`: 单个客户端会话处理
 | 
				
			||||||
 | 
					- `config.py`: 集中配置管理
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 许可证
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					本项目仅用于教育和学习目的。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 作者
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					计算机网络课程设计项目
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					更多详细信息请参阅 [设计报告](design_report.md)。
 | 
				
			||||||
@ -403,9 +403,11 @@ python main.py
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
### 2. Windows 客户端连接
 | 
					### 2. Windows 客户端连接
 | 
				
			||||||
```cmd
 | 
					```cmd
 | 
				
			||||||
ftp 127.0.0.1
 | 
					ftp 127.0.0.1 2121
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					注意:由于使用非标准端口 2121(避免需要管理员权限),需要指定端口号。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### 3. 测试用户账号
 | 
					### 3. 测试用户账号
 | 
				
			||||||
| 用户名 | 密码 |
 | 
					| 用户名 | 密码 |
 | 
				
			||||||
|--------|------|
 | 
					|--------|------|
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										8
									
								
								ftp_root/text1.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								ftp_root/text1.txt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					This is a test file for FTP download.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Content:
 | 
				
			||||||
 | 
					- Line 1: Hello World
 | 
				
			||||||
 | 
					- Line 2: FTP Server Test
 | 
				
			||||||
 | 
					- Line 3: File download working correctly
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You can download this file using the GET command in FTP client.
 | 
				
			||||||
@ -64,7 +64,9 @@ class FTPSession:
 | 
				
			|||||||
                    args = parts[1] if len(parts) > 1 else ''
 | 
					                    args = parts[1] if len(parts) > 1 else ''
 | 
				
			||||||
                    
 | 
					                    
 | 
				
			||||||
                    # Handle command
 | 
					                    # Handle command
 | 
				
			||||||
                    self.handle_command(command, args)
 | 
					                    should_quit = self.handle_command(command, args)
 | 
				
			||||||
 | 
					                    if should_quit:
 | 
				
			||||||
 | 
					                        break
 | 
				
			||||||
                    
 | 
					                    
 | 
				
			||||||
                except ConnectionResetError:
 | 
					                except ConnectionResetError:
 | 
				
			||||||
                    print(f"Client {self.client_address} disconnected")
 | 
					                    print(f"Client {self.client_address} disconnected")
 | 
				
			||||||
@ -85,7 +87,7 @@ class FTPSession:
 | 
				
			|||||||
        elif command == 'PASS':
 | 
					        elif command == 'PASS':
 | 
				
			||||||
            self.handle_pass(args)
 | 
					            self.handle_pass(args)
 | 
				
			||||||
        elif command == 'QUIT':
 | 
					        elif command == 'QUIT':
 | 
				
			||||||
            self.handle_quit()
 | 
					            return self.handle_quit()
 | 
				
			||||||
        elif command == 'PWD':
 | 
					        elif command == 'PWD':
 | 
				
			||||||
            self.handle_pwd()
 | 
					            self.handle_pwd()
 | 
				
			||||||
        elif command == 'CWD':
 | 
					        elif command == 'CWD':
 | 
				
			||||||
@ -106,6 +108,7 @@ class FTPSession:
 | 
				
			|||||||
            self.send_response('200')
 | 
					            self.send_response('200')
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            self.send_response('500', f'Command {command} not recognized')
 | 
					            self.send_response('500', f'Command {command} not recognized')
 | 
				
			||||||
 | 
					        return False
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    def handle_user(self, username):
 | 
					    def handle_user(self, username):
 | 
				
			||||||
        """Handle USER command"""
 | 
					        """Handle USER command"""
 | 
				
			||||||
@ -178,7 +181,9 @@ class FTPSession:
 | 
				
			|||||||
        new_path = os.path.normpath(new_path)
 | 
					        new_path = os.path.normpath(new_path)
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        # Security check: ensure path is within server root
 | 
					        # Security check: ensure path is within server root
 | 
				
			||||||
        if not new_path.startswith(SERVER_ROOT):
 | 
					        server_root_abs = os.path.abspath(SERVER_ROOT)
 | 
				
			||||||
 | 
					        new_path_abs = os.path.abspath(new_path)
 | 
				
			||||||
 | 
					        if not new_path_abs.startswith(server_root_abs):
 | 
				
			||||||
            self.send_response('550', 'Permission denied')
 | 
					            self.send_response('550', 'Permission denied')
 | 
				
			||||||
            return
 | 
					            return
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
@ -356,8 +361,10 @@ class FTPSession:
 | 
				
			|||||||
        filepath = os.path.join(self.current_directory, filename)
 | 
					        filepath = os.path.join(self.current_directory, filename)
 | 
				
			||||||
        filepath = os.path.normpath(filepath)
 | 
					        filepath = os.path.normpath(filepath)
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        # Security check
 | 
					        # Security check: ensure path is within server root
 | 
				
			||||||
        if not filepath.startswith(SERVER_ROOT):
 | 
					        server_root_abs = os.path.abspath(SERVER_ROOT)
 | 
				
			||||||
 | 
					        filepath_abs = os.path.abspath(filepath)
 | 
				
			||||||
 | 
					        if not filepath_abs.startswith(server_root_abs):
 | 
				
			||||||
            self.send_response('550', 'Permission denied')
 | 
					            self.send_response('550', 'Permission denied')
 | 
				
			||||||
            return
 | 
					            return
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										55
									
								
								test_ftp_client.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								test_ftp_client.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,55 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env python3
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					Simple FTP Client Test Script
 | 
				
			||||||
 | 
					Tests the basic functionality of our FTP server
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import socket
 | 
				
			||||||
 | 
					import time
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_ftp_server():
 | 
				
			||||||
 | 
					    """Test basic FTP server functionality"""
 | 
				
			||||||
 | 
					    print("Testing FTP Server...")
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        # Connect to FTP server
 | 
				
			||||||
 | 
					        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 | 
				
			||||||
 | 
					        sock.connect(('127.0.0.1', 2121))
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        # Read welcome message
 | 
				
			||||||
 | 
					        response = sock.recv(1024).decode('utf-8')
 | 
				
			||||||
 | 
					        print(f"Server: {response.strip()}")
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        # Test USER command
 | 
				
			||||||
 | 
					        sock.send(b'USER admin\r\n')
 | 
				
			||||||
 | 
					        response = sock.recv(1024).decode('utf-8')
 | 
				
			||||||
 | 
					        print(f"Server: {response.strip()}")
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        # Test PASS command
 | 
				
			||||||
 | 
					        sock.send(b'PASS admin123\r\n')
 | 
				
			||||||
 | 
					        response = sock.recv(1024).decode('utf-8')
 | 
				
			||||||
 | 
					        print(f"Server: {response.strip()}")
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        # Test PWD command
 | 
				
			||||||
 | 
					        sock.send(b'PWD\r\n')
 | 
				
			||||||
 | 
					        response = sock.recv(1024).decode('utf-8')
 | 
				
			||||||
 | 
					        print(f"Server: {response.strip()}")
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        # Test SYST command
 | 
				
			||||||
 | 
					        sock.send(b'SYST\r\n')
 | 
				
			||||||
 | 
					        response = sock.recv(1024).decode('utf-8')
 | 
				
			||||||
 | 
					        print(f"Server: {response.strip()}")
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        # Test QUIT command
 | 
				
			||||||
 | 
					        sock.send(b'QUIT\r\n')
 | 
				
			||||||
 | 
					        response = sock.recv(1024).decode('utf-8')
 | 
				
			||||||
 | 
					        print(f"Server: {response.strip()}")
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        sock.close()
 | 
				
			||||||
 | 
					        print("✅ Basic FTP commands test passed!")
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					    except Exception as e:
 | 
				
			||||||
 | 
					        print(f"❌ Test failed: {e}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    test_ftp_server()
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user