diff --git a/APP_Framework/Applications/app_test/test_ftpclient_final/README.md b/APP_Framework/Applications/app_test/test_ftpclient_final/README.md new file mode 100644 index 000000000..364143051 --- /dev/null +++ b/APP_Framework/Applications/app_test/test_ftpclient_final/README.md @@ -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 大小的测试文件 + + ![fig0](fig0.png) + +3. 将开发板与路由器连接,根据实际情况修改代码中的网卡配置部分,使得开发板可以上网。 + +4. `TestFtpClientFinal` 命令需要一个参数,参数可选 `upload` 和 `download`,分别会启动 10 个线程,进行文件名拼接,然后登陆到 FTP server,进行对应文件的上传/下载。注意需要将测试程序中 `ftp_login` 的 server ip、用户名以及密码替换为实际情况的内容。 + +5. 关闭 FTP client。 + +## 4. 运行结果(需结合运行测试截图按步骤说明) + +1. 在 server 端编译代码并运行. + + ![fig1](fig1.png) + +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` 命令可以看到根目录为空。 + + ![fig2](fig2.png) + +5. 执行 `TestFtpClientFinal download` 命令,10 个线程并发创建 10 个 client 下载对应的 10 个文件,可以看到下载过程是并发进行的。 + + ![fig3](fig3.png) + ![fig4](fig4.png) + ![fig5](fig5.png) + ![fig6](fig6.png) + +6. 执行 `ls` 命令,看到文件全部下载成功,大小与 server 一致。 + + ![fig7](fig7.png) + +7. 在 server 端执行 `rm file_*` 命令,删除服务器端的测试文件。 + +8. 执行 `TestFtpClientFinal upload` 命令,10 个线程并发创建 10 个 client 上传刚刚下载的 10 个文件,可以看到上传过程是并发进行的。 + + ![fig8](fig8.png) + ![fig9](fig9.png) + ![fig10](fig10.png) + ![fig11](fig11.png) + +9. 在 server 端执行 `ll --block-size=1` 命令,可以看到文件全部重新上传,大小与之前一致。 + + ![fig12](fig12.png) + +10. 测试结束。 \ No newline at end of file diff --git a/APP_Framework/Applications/app_test/test_ftpclient_final/fig0.png b/APP_Framework/Applications/app_test/test_ftpclient_final/fig0.png new file mode 100644 index 000000000..0ad445a9e Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient_final/fig0.png differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient_final/fig1.png b/APP_Framework/Applications/app_test/test_ftpclient_final/fig1.png new file mode 100644 index 000000000..cc8172c0c Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient_final/fig1.png differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient_final/fig10.png b/APP_Framework/Applications/app_test/test_ftpclient_final/fig10.png new file mode 100644 index 000000000..b2f145fa9 Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient_final/fig10.png differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient_final/fig11.png b/APP_Framework/Applications/app_test/test_ftpclient_final/fig11.png new file mode 100644 index 000000000..a5d402eed Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient_final/fig11.png differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient_final/fig12.png b/APP_Framework/Applications/app_test/test_ftpclient_final/fig12.png new file mode 100644 index 000000000..0af484487 Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient_final/fig12.png differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient_final/fig2.png b/APP_Framework/Applications/app_test/test_ftpclient_final/fig2.png new file mode 100644 index 000000000..52c9de348 Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient_final/fig2.png differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient_final/fig3.png b/APP_Framework/Applications/app_test/test_ftpclient_final/fig3.png new file mode 100644 index 000000000..b4ca8739c Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient_final/fig3.png differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient_final/fig4.png b/APP_Framework/Applications/app_test/test_ftpclient_final/fig4.png new file mode 100644 index 000000000..00164c5ee Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient_final/fig4.png differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient_final/fig5.png b/APP_Framework/Applications/app_test/test_ftpclient_final/fig5.png new file mode 100644 index 000000000..bca61e85a Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient_final/fig5.png differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient_final/fig6.png b/APP_Framework/Applications/app_test/test_ftpclient_final/fig6.png new file mode 100644 index 000000000..4aa7c3780 Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient_final/fig6.png differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient_final/fig7.png b/APP_Framework/Applications/app_test/test_ftpclient_final/fig7.png new file mode 100644 index 000000000..10f5c1702 Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient_final/fig7.png differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient_final/fig8.png b/APP_Framework/Applications/app_test/test_ftpclient_final/fig8.png new file mode 100644 index 000000000..b9668a777 Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient_final/fig8.png differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient_final/fig9.png b/APP_Framework/Applications/app_test/test_ftpclient_final/fig9.png new file mode 100644 index 000000000..37461ac52 Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient_final/fig9.png differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient_final/test_ftpclient_final.c b/APP_Framework/Applications/app_test/test_ftpclient_final/test_ftpclient_final.c new file mode 100644 index 000000000..bc348b51b --- /dev/null +++ b/APP_Framework/Applications/app_test/test_ftpclient_final/test_ftpclient_final.c @@ -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); \ No newline at end of file