2023_open_source_contest_final_1st_issue3
|
@ -0,0 +1,123 @@
|
|||
# 基于初赛一级赛题3,在云服务器上实现FTP Server功能
|
||||
|
||||
## 1. 简介
|
||||
|
||||
基于赛事提供的云服务器,实现FTP协议的Server功能,其功能支持至少10个Client端并发向Server端传输4KB大小的文件,支持Server端并发地向至少10个Client端传输4KB大小的文件,可通过在shell终端打印相关配置、相关截图说明来验证功能实现
|
||||
|
||||
## 2. 数据结构设计说明
|
||||
|
||||
### FTP client
|
||||
|
||||
FTP client设计为:
|
||||
|
||||
```c
|
||||
typedef struct ftp_client_struct
|
||||
{
|
||||
char username[64];
|
||||
char password[64];
|
||||
char server_ip[64];
|
||||
char data_port[6];
|
||||
char control_port[6];
|
||||
int control_socket;
|
||||
int data_socket;
|
||||
}ftp_client;
|
||||
```
|
||||
|
||||
一共实现了 8 个函数,其中 5 个为接口函数,分别为:
|
||||
|
||||
- `ftp_cmd`:向 FTP server 发送指令
|
||||
- `ftp_downloaddata`:从 FTP server 接收数据
|
||||
- `ftp_uploaddata`:向 FTP server 上传数据
|
||||
- `ftp_login`:登陆 FTP server
|
||||
- `ftp_downloadfile`:从 FTP server 下载文件
|
||||
- `ftp_uploadfile`:向 FTP server 上传文件
|
||||
- `ftp_changedir`:切换目录
|
||||
- `ftp_quit`:关闭 FTP client
|
||||
|
||||
### FTP server
|
||||
|
||||
FTP server设计为:
|
||||
|
||||
```c
|
||||
typedef struct _ftp_server
|
||||
{
|
||||
int sock_data;
|
||||
int sock_control;
|
||||
int sock_listen;
|
||||
int data_port;
|
||||
char ip[64];
|
||||
pthread_t tid;
|
||||
void *arg;
|
||||
} ftp_server;
|
||||
```
|
||||
|
||||
一共实现了 12 个函数,分别为:
|
||||
|
||||
- `socket_create`:封装了创建 socket 的过程,参数 port 为指针,可以返回分配的端口号,便于使用动态端口作为数据端口
|
||||
- `socket_accept`:封装了 accept 的过程
|
||||
- `recv_data`:从 FTP client 接收数据
|
||||
- `send_response`:向 FTP client 发送数据
|
||||
- `retr`:实现 RETR 命令
|
||||
- `list`:实现 LIST 命令
|
||||
- `pasv`:实现 PASV 命令,分配动态端口
|
||||
- `size`:实现 SIZE 命令
|
||||
- `check_user`:检查用户名和密码是否正确
|
||||
- `login`:实现 client 登陆的过程
|
||||
- `recv_cmd`:解析 client 发送的命令,调用对应的处理函数
|
||||
- `process`:server 的进程函数
|
||||
|
||||
## 3. 测试程序说明
|
||||
|
||||
测试程序 `TestFtpClientFinal` 已经注册为 shell 命令,可以调用执行。编译时需要打开 lwip 和 USB。
|
||||
|
||||
1. 首先编译运行 FTP server,通过命令 `gcc -pthread ftpserver.c -o ftp_server` 编译,再使用 `./ftp_server 9991` 命令运行,端口号可以任意选择未被占用的端口,此处选择大赛规定的端口之一,同时保持 client 配置的端口与 server 一致。
|
||||
|
||||
2. 在 server 目录下生成了 10 个 4KB 大小的测试文件
|
||||
|
||||

|
||||
|
||||
3. 将开发板与路由器连接,根据实际情况修改代码中的网卡配置部分,使得开发板可以上网。
|
||||
|
||||
4. `TestFtpClientFinal` 命令需要一个参数,参数可选 `upload` 和 `download`,分别会启动 10 个线程,进行文件名拼接,然后登陆到 FTP server,进行对应文件的上传/下载。注意需要将测试程序中 `ftp_login` 的 server ip、用户名以及密码替换为实际情况的内容。
|
||||
|
||||
5. 关闭 FTP client。
|
||||
|
||||
## 4. 运行结果(需结合运行测试截图按步骤说明)
|
||||
|
||||
1. 在 server 端编译代码并运行.
|
||||
|
||||

|
||||
|
||||
2. 在 client 代码工作区终端中进入 `menuconfig` 配置页面,打开 `Using LwIP by ethernet device`、`Using USB device` 以及 `test app` 中的 `Config test ftp client`。
|
||||
|
||||
3. 执行编译命令:`make BOARD=edu-arm32`,正常情况下应当编译无误,将编译好的 bin 文件烧录进开发板。
|
||||
|
||||
4. 在开发板的 USB 接口上接入 U 盘,启动开发板,通过串口终端观察 USB 挂载成功,用 `ls` 命令可以看到根目录为空。
|
||||
|
||||

|
||||
|
||||
5. 执行 `TestFtpClientFinal download` 命令,10 个线程并发创建 10 个 client 下载对应的 10 个文件,可以看到下载过程是并发进行的。
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
6. 执行 `ls` 命令,看到文件全部下载成功,大小与 server 一致。
|
||||
|
||||

|
||||
|
||||
7. 在 server 端执行 `rm file_*` 命令,删除服务器端的测试文件。
|
||||
|
||||
8. 执行 `TestFtpClientFinal upload` 命令,10 个线程并发创建 10 个 client 上传刚刚下载的 10 个文件,可以看到上传过程是并发进行的。
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
9. 在 server 端执行 `ll --block-size=1` 命令,可以看到文件全部重新上传,大小与之前一致。
|
||||
|
||||

|
||||
|
||||
10. 测试结束。
|
After Width: | Height: | Size: 49 KiB |
After Width: | Height: | Size: 4.8 KiB |
After Width: | Height: | Size: 115 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 124 KiB |
After Width: | Height: | Size: 136 KiB |
After Width: | Height: | Size: 118 KiB |
After Width: | Height: | Size: 52 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 106 KiB |
After Width: | Height: | Size: 106 KiB |
|
@ -0,0 +1,69 @@
|
|||
#include "../test_ftpclient/ftp_client/ftp_client.h"
|
||||
#include "lwip/sys.h"
|
||||
|
||||
static ftp_client *f[10];
|
||||
|
||||
static void *downloadfunc(void *param) {
|
||||
int i = *(int *)param;
|
||||
/* Use the appropriate username and password as login parameters */
|
||||
f[i] = ftp_login("8.140.53.225", "user", "pass");
|
||||
if (f[i] != NULL) {
|
||||
/* Choosing the right path */
|
||||
// ftp_changedir(f[i], "test");
|
||||
|
||||
char filename[64];
|
||||
sprintf(filename, "file_%d.txt", i);
|
||||
ftp_downloadfile(f[i], filename);
|
||||
|
||||
/* Close FTP client */
|
||||
ftp_quit(f[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void *uploadfunc(void *param) {
|
||||
int i = *(int *)param;
|
||||
/* Use the appropriate username and password as login parameters */
|
||||
f[i] = ftp_login("8.140.53.225", "user", "pass");
|
||||
if (f[i] != NULL) {
|
||||
char filename[64];
|
||||
sprintf(filename, "file_%d.txt", i);
|
||||
ftp_uploadfile(f[i], filename);
|
||||
|
||||
/* Close FTP client */
|
||||
ftp_quit(f[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void TestFtpClientFinal(int argc, char *argv[]) {
|
||||
if (argc != 2) {
|
||||
printf("Need a param.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_attr_t attr;
|
||||
attr.schedparam.sched_priority = 22;
|
||||
attr.stacksize = 4096;
|
||||
|
||||
memset(f, 0, sizeof(f));
|
||||
|
||||
/* Initialize the network IP */
|
||||
char self_ipaddr[] = {192, 168, 130, 77};
|
||||
char self_netmask[] = {255, 255, 254, 0};
|
||||
char self_gwaddr[] = {192, 168, 130, 1};
|
||||
lwip_config_tcp(0, self_ipaddr, self_netmask, self_gwaddr);
|
||||
|
||||
if (strcmp(argv[1], "upload") == 0) {
|
||||
/* Upload 10 files of about 4kb in size */
|
||||
for (int i = 1; i <= 10; ++i) {
|
||||
pthread_t up;
|
||||
PrivTaskCreate(&up, &attr, &uploadfunc, &i);
|
||||
}
|
||||
} else if (strcmp(argv[1], "download") == 0) {
|
||||
/* Download 10 files of about 4kb in size */
|
||||
for (int i = 1; i <= 10; ++i) {
|
||||
pthread_t down;
|
||||
PrivTaskCreate(&down, &attr, &downloadfunc, &i);
|
||||
}
|
||||
}
|
||||
}
|
||||
PRIV_SHELL_CMD_FUNCTION(TestFtpClientFinal, 2023 open source contest final 1 st issue3, PRIV_SHELL_CMD_MAIN_ATTR);
|