2023_open_source_contest_final_1st_issue3

This commit is contained in:
JasenChao 2023-09-20 22:13:39 +08:00
parent 10e672371e
commit fe3c8938e5
17 changed files with 92 additions and 105 deletions

View File

@ -10,6 +10,18 @@
#include "lwip/sockets.h"
#include "lwip/netdb.h"
static pthread_mutex_t *mutex;
int ftp_init()
{
return PrivMutexCreate(mutex, NULL);
}
int ftp_close()
{
return PrivMutexDelete(mutex);
}
/**
* @description: Send a cmd to FTP server
* @param socket - Control socket
@ -19,7 +31,7 @@
* @param other - Store output parameter if needed
* @return 0: success; others: failure
*/
static int ftp_cmd(int socket, int wait_time, int cmd, char *param, int *other)
int ftp_cmd(int socket, int wait_time, int cmd, char *param, int *other)
{
fd_set readset;
struct timeval timeout;
@ -124,8 +136,8 @@ static int ftp_cmd(int socket, int wait_time, int cmd, char *param, int *other)
/* Waiting for server response */
if (select(socket + 1, &readset, NULL, NULL, &timeout) <= 0) {
LOG_I("select the socket timeout!\n");
return -1;
LOG_I("select the socket timeout!\n");
return -1;
}
/* Wait and receive the packet back from the server. */
@ -141,7 +153,7 @@ static int ftp_cmd(int socket, int wait_time, int cmd, char *param, int *other)
++i;
}
buff[i + 1] = '\0';
LOG_I("Recv:%s\n", buff);
// LOG_I("Recv:%s\n", buff);
/* Identify if the status code is correct according to cmd */
switch (cmd)
@ -308,8 +320,9 @@ static int ftp_cmd(int socket, int wait_time, int cmd, char *param, int *other)
* @param getlen - Actual length of data received
* @return 0: success; others: failure
*/
static int ftp_downloaddata(int socket, int wait_time, char *buf, int bufsize, int *getlen)
int ftp_downloaddata(int socket, int wait_time, char *buf, int bufsize, int *getlen)
{
memset(buf, 0, bufsize);
fd_set readset;
struct timeval timeout;
int len = 0;
@ -345,7 +358,7 @@ static int ftp_downloaddata(int socket, int wait_time, char *buf, int bufsize, i
* @param getlen - Actual length of data sended
* @return 0: success; others: failure
*/
static int ftp_uploaddata(int socket, char *buf, int bufsize, int *getlen)
int ftp_uploaddata(int socket, char *buf, int bufsize, int *getlen)
{
int len = 0;
@ -451,13 +464,12 @@ __exit:
int ftp_downloadfile(ftp_client *ftp, char *file_name)
{
int ret = 0, fd = 0;
struct addrinfo hints, *result = NULL, *cur = NULL;
int getlen = 0;
int file_pos = 0;
int port = 0;
int file_size = 0;
char filebuf[128] = {0};
char filebuf[256] = {0};
/* Enter the pasv mode */
if (ftp_cmd(ftp->control_socket, 10000, PASV, NULL, &port) != 0) {
@ -466,32 +478,19 @@ int ftp_downloadfile(ftp_client *ftp, char *file_name)
}
/* Creat the data socket link */
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
fd = socket(AF_INET, SOCK_STREAM, 0);
int bufsize = 1024 * 1024;
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(bufsize));
sprintf(ftp->data_port, "%d", port);
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = inet_addr(ftp->server_ip);
/* Do name resolution with both IPv6 and IPv4 */
if (getaddrinfo(ftp->server_ip, ftp->data_port, &hints, &result) != 0) {
goto __exit;
}
for (cur = result; cur != NULL; cur = cur->ai_next) {
fd = socket(cur->ai_family, cur->ai_socktype, cur->ai_protocol);
if (fd < 0) {
continue;
}
if (connect(fd, cur->ai_addr, cur->ai_addrlen) == 0) {
ftp->data_socket = fd;
break;
}
closesocket(fd);
}
freeaddrinfo(result);
if (connect(fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == 0)
ftp->data_socket = fd;
if(ftp->data_socket < 0)
{
@ -505,6 +504,30 @@ int ftp_downloadfile(ftp_client *ftp, char *file_name)
goto __exit;
}
char name[64];
sprintf(name, "/%s", file_name);
int f = PrivOpen(name, O_RDWR|O_CREAT);
/* Read the file */
while(1) {
if (ftp_downloaddata(ftp->data_socket, 10000, filebuf, 128, &getlen) == 0) {
if (getlen) {
PrivMutexObtain(mutex);
ret = PrivWrite(f, filebuf, strlen(filebuf));
PrivMutexAbandon(mutex);
if (ret < 0) {
break;
}
} else {
break;
}
} else {
break;
}
file_pos = file_pos + getlen;
}
printf("Total length: %d\n", file_pos); // Compare the size of the file previously returned by the server
PrivClose(f);
/* Waite the download file finish */
if (ftp_cmd(ftp->control_socket, 10000, FINISH, NULL, NULL) != 0) {
ret = -1;
@ -512,30 +535,6 @@ int ftp_downloadfile(ftp_client *ftp, char *file_name)
ret = 0;
}
char name[64];
sprintf(name, "/%s", file_name);
int f = PrivOpen(name, O_RDWR|O_CREAT);
/* Read the file */
while(file_size > file_pos) {
if (ftp_downloaddata(ftp->data_socket, 10000, filebuf, 128, &getlen) == 0) {
if (getlen) {
ret = PrivWrite(f, filebuf, strlen(filebuf));
if (ret < 0) {
printf("write failed,error:%d\n", ret);
goto __exit;
}
} else {
ret = -1;
goto __exit;
}
} else {
ret = -1;
goto __exit;
}
file_pos = file_pos + getlen;
}
printf("Total length: %d\n", file_pos); // Compare the size of the file previously returned by the server
PrivClose(f);
__exit:
if(ftp->data_socket >= 0)
{
@ -569,32 +568,19 @@ int ftp_uploadfile(ftp_client *ftp, char *file_name)
}
/* Creat the data socket link */
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
sprintf(ftp->data_port, "%d", port);
/* Do name resolution with both IPv6 and IPv4 */
if (getaddrinfo(ftp->server_ip, ftp->data_port, &hints, &result) != 0) {
goto __exit;
}
fd = socket(AF_INET, SOCK_STREAM, 0);
int bufsize = 1024 * 1024;
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(bufsize));
for (cur = result; cur != NULL; cur = cur->ai_next) {
fd = socket(cur->ai_family, cur->ai_socktype, cur->ai_protocol);
if (fd < 0) {
continue;
}
sprintf(ftp->data_port, "%d", port);
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = inet_addr(ftp->server_ip);
if (connect(fd, cur->ai_addr, cur->ai_addrlen) == 0) {
ftp->data_socket = fd;
break;
}
closesocket(fd);
}
freeaddrinfo(result);
if (connect(fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == 0)
ftp->data_socket = fd;
if(ftp->data_socket < 0)
{
@ -619,28 +605,21 @@ int ftp_uploadfile(ftp_client *ftp, char *file_name)
while((ret = PrivRead(f, filebuf, 128)) != 0) {
if (ret < 0) {
printf("read failed.\n");
goto __exit;
break;
}
if (ftp_uploaddata(ftp->data_socket, filebuf, ret, &getlen) == 0) {
if (!getlen) {
ret = -1;
goto __exit;
break;
}
} else {
ret = -1;
goto __exit;
break;
}
file_pos = file_pos + getlen;
file_pos += getlen;
}
printf("Total length: %d\n", file_pos);
/* Uploading a file requires the client to actively close the socket. */
if(ftp->data_socket >= 0)
{
closesocket(ftp->data_socket);
ftp->data_socket = -1;
}
/* Waite the upload file finish */
if (ftp_cmd(ftp->control_socket, 10000, FINISH, NULL, NULL) != 0) {
ret = -1;

View File

@ -34,6 +34,8 @@ typedef struct ftp_client_struct
int data_socket;
}ftp_client;
int ftp_init();
int ftp_close();
ftp_client *ftp_login(char *addr, char *username, char *password);
int ftp_downloadfile(ftp_client *ftp, char *file_name);
int ftp_uploadfile(ftp_client *ftp, char *file_name);

View File

@ -36,6 +36,8 @@ typedef struct ftp_client_struct
### FTP server
FTP server 的代码托管在 https://github.com/JasenChao/ftp_server.git 。
FTP server设计为
```c
@ -78,9 +80,7 @@ typedef struct _ftp_server
3. 将开发板与路由器连接,根据实际情况修改代码中的网卡配置部分,使得开发板可以上网。
4. `TestFtpClientFinal` 命令需要一个参数,参数可选 `upload``download`,分别会启动 10 个线程,进行文件名拼接,然后登陆到 FTP server进行对应文件的上传/下载。注意需要将测试程序中 `ftp_login` 的 server ip、用户名以及密码替换为实际情况的内容。
5. 关闭 FTP client。
4. `TestFtpClientFinal` 命令需要一个参数,参数可选 `init`、`close`、`upload`、`download`分别会初始化和关闭FTP启动 10 个线程,进行文件名拼接,然后登陆到 FTP server进行对应文件的上传/下载。注意需要将测试程序中 `ftp_login` 的 server ip、用户名以及密码替换为实际情况的内容。
## 4. 运行结果(需结合运行测试截图按步骤说明)
@ -96,28 +96,30 @@ typedef struct _ftp_server
![fig2](fig2.png)
5. 执行 `TestFtpClientFinal download` 命令10 个线程并发创建 10 个 client 下载对应的 10 个文件,可以看到下载过程是并发进行的
5. 执行 `TestFtpClientFinal init` 命令,初始化网卡和互斥量
![fig3](fig3.png)
6. 执行 `TestFtpClientFinal download` 命令10 个线程并发创建 10 个 client 下载对应的 10 个文件,可以看到下载过程是并发进行的。
![fig4](fig4.png)
![fig5](fig5.png)
7. 执行 `ls` 命令,看到文件全部下载成功,大小与 server 一致。
![fig6](fig6.png)
6. 执行 `ls` 命令,看到文件全部下载成功,大小与 server 一致。
![fig7](fig7.png)
7. 在 server 端执行 `rm file_*` 命令,删除服务器端的测试文件。
8. 在 server 端执行 `rm file_*` 命令,删除服务器端的测试文件。
8. 执行 `TestFtpClientFinal upload` 命令10 个线程并发创建 10 个 client 上传刚刚下载的 10 个文件,可以看到上传过程是并发进行的。
![fig7](fig7.png)
![fig8](fig8.png)
![fig9](fig9.png)
![fig10](fig10.png)
9. 在 server 端执行 `ll --block-size=1` 命令,可以看到文件全部重新上传,时间与之前删除的相比有变化,大小与之前一致,通过打开比对可以发现内容也一致。
![fig11](fig11.png)
9. 在 server 端执行 `ll --block-size=1` 命令,可以看到文件全部重新上传,大小与之前一致。
![fig12](fig12.png)
10. 测试结束。

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 39 KiB

View File

@ -42,14 +42,14 @@ void TestFtpClientFinal(int argc, char *argv[]) {
pthread_attr_t attr;
attr.schedparam.sched_priority = 22;
attr.stacksize = 4096;
attr.stacksize = 2048;
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};
char self_gwaddr[] = {192, 168, 130, 78};
lwip_config_tcp(0, self_ipaddr, self_netmask, self_gwaddr);
if (strcmp(argv[1], "upload") == 0) {
@ -64,6 +64,10 @@ void TestFtpClientFinal(int argc, char *argv[]) {
pthread_t down;
PrivTaskCreate(&down, &attr, &downloadfunc, &i);
}
} else if (strcmp(argv[1], "init") == 0) {
ftp_init();
} else if (strcmp(argv[1], "close") == 0) {
ftp_close();
}
}
PRIV_SHELL_CMD_FUNCTION(TestFtpClientFinal, 2023 open source contest final 1 st issue3, PRIV_SHELL_CMD_MAIN_ATTR);