2023_open_source_contest_final_1st_issue3
|
@ -10,6 +10,18 @@
|
||||||
#include "lwip/sockets.h"
|
#include "lwip/sockets.h"
|
||||||
#include "lwip/netdb.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
|
* @description: Send a cmd to FTP server
|
||||||
* @param socket - Control socket
|
* @param socket - Control socket
|
||||||
|
@ -19,7 +31,7 @@
|
||||||
* @param other - Store output parameter if needed
|
* @param other - Store output parameter if needed
|
||||||
* @return 0: success; others: failure
|
* @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;
|
fd_set readset;
|
||||||
struct timeval timeout;
|
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 */
|
/* Waiting for server response */
|
||||||
if (select(socket + 1, &readset, NULL, NULL, &timeout) <= 0) {
|
if (select(socket + 1, &readset, NULL, NULL, &timeout) <= 0) {
|
||||||
LOG_I("select the socket timeout!\n");
|
LOG_I("select the socket timeout!\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wait and receive the packet back from the server. */
|
/* 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;
|
++i;
|
||||||
}
|
}
|
||||||
buff[i + 1] = '\0';
|
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 */
|
/* Identify if the status code is correct according to cmd */
|
||||||
switch (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
|
* @param getlen - Actual length of data received
|
||||||
* @return 0: success; others: failure
|
* @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;
|
fd_set readset;
|
||||||
struct timeval timeout;
|
struct timeval timeout;
|
||||||
int len = 0;
|
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
|
* @param getlen - Actual length of data sended
|
||||||
* @return 0: success; others: failure
|
* @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;
|
int len = 0;
|
||||||
|
|
||||||
|
@ -451,13 +464,12 @@ __exit:
|
||||||
int ftp_downloadfile(ftp_client *ftp, char *file_name)
|
int ftp_downloadfile(ftp_client *ftp, char *file_name)
|
||||||
{
|
{
|
||||||
int ret = 0, fd = 0;
|
int ret = 0, fd = 0;
|
||||||
struct addrinfo hints, *result = NULL, *cur = NULL;
|
|
||||||
int getlen = 0;
|
int getlen = 0;
|
||||||
int file_pos = 0;
|
int file_pos = 0;
|
||||||
int port = 0;
|
int port = 0;
|
||||||
int file_size = 0;
|
int file_size = 0;
|
||||||
|
|
||||||
char filebuf[128] = {0};
|
char filebuf[256] = {0};
|
||||||
|
|
||||||
/* Enter the pasv mode */
|
/* Enter the pasv mode */
|
||||||
if (ftp_cmd(ftp->control_socket, 10000, PASV, NULL, &port) != 0) {
|
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 */
|
/* Creat the data socket link */
|
||||||
memset(&hints, 0, sizeof(hints));
|
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
hints.ai_family = AF_UNSPEC;
|
int bufsize = 1024 * 1024;
|
||||||
hints.ai_socktype = SOCK_STREAM;
|
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(bufsize));
|
||||||
hints.ai_protocol = IPPROTO_TCP;
|
|
||||||
|
|
||||||
sprintf(ftp->data_port, "%d", port);
|
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 (connect(fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == 0)
|
||||||
if (getaddrinfo(ftp->server_ip, ftp->data_port, &hints, &result) != 0) {
|
ftp->data_socket = fd;
|
||||||
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(ftp->data_socket < 0)
|
if(ftp->data_socket < 0)
|
||||||
{
|
{
|
||||||
|
@ -505,6 +504,30 @@ int ftp_downloadfile(ftp_client *ftp, char *file_name)
|
||||||
goto __exit;
|
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 */
|
/* Waite the download file finish */
|
||||||
if (ftp_cmd(ftp->control_socket, 10000, FINISH, NULL, NULL) != 0) {
|
if (ftp_cmd(ftp->control_socket, 10000, FINISH, NULL, NULL) != 0) {
|
||||||
ret = -1;
|
ret = -1;
|
||||||
|
@ -512,30 +535,6 @@ int ftp_downloadfile(ftp_client *ftp, char *file_name)
|
||||||
ret = 0;
|
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:
|
__exit:
|
||||||
if(ftp->data_socket >= 0)
|
if(ftp->data_socket >= 0)
|
||||||
{
|
{
|
||||||
|
@ -569,32 +568,19 @@ int ftp_uploadfile(ftp_client *ftp, char *file_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Creat the data socket link */
|
/* Creat the data socket link */
|
||||||
memset(&hints, 0, sizeof(hints));
|
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
hints.ai_family = AF_UNSPEC;
|
int bufsize = 1024 * 1024;
|
||||||
hints.ai_socktype = SOCK_STREAM;
|
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(bufsize));
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (cur = result; cur != NULL; cur = cur->ai_next) {
|
sprintf(ftp->data_port, "%d", port);
|
||||||
fd = socket(cur->ai_family, cur->ai_socktype, cur->ai_protocol);
|
struct sockaddr_in server_addr;
|
||||||
if (fd < 0) {
|
memset(&server_addr, 0, sizeof(server_addr));
|
||||||
continue;
|
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) {
|
if (connect(fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == 0)
|
||||||
ftp->data_socket = fd;
|
ftp->data_socket = fd;
|
||||||
break;
|
|
||||||
}
|
|
||||||
closesocket(fd);
|
|
||||||
|
|
||||||
}
|
|
||||||
freeaddrinfo(result);
|
|
||||||
|
|
||||||
if(ftp->data_socket < 0)
|
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) {
|
while((ret = PrivRead(f, filebuf, 128)) != 0) {
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
printf("read failed.\n");
|
printf("read failed.\n");
|
||||||
goto __exit;
|
break;
|
||||||
}
|
}
|
||||||
if (ftp_uploaddata(ftp->data_socket, filebuf, ret, &getlen) == 0) {
|
if (ftp_uploaddata(ftp->data_socket, filebuf, ret, &getlen) == 0) {
|
||||||
if (!getlen) {
|
if (!getlen) {
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto __exit;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto __exit;
|
break;
|
||||||
}
|
}
|
||||||
file_pos = file_pos + getlen;
|
file_pos += getlen;
|
||||||
}
|
}
|
||||||
printf("Total length: %d\n", file_pos);
|
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 */
|
/* Waite the upload file finish */
|
||||||
if (ftp_cmd(ftp->control_socket, 10000, FINISH, NULL, NULL) != 0) {
|
if (ftp_cmd(ftp->control_socket, 10000, FINISH, NULL, NULL) != 0) {
|
||||||
ret = -1;
|
ret = -1;
|
||||||
|
|
|
@ -34,6 +34,8 @@ typedef struct ftp_client_struct
|
||||||
int data_socket;
|
int data_socket;
|
||||||
}ftp_client;
|
}ftp_client;
|
||||||
|
|
||||||
|
int ftp_init();
|
||||||
|
int ftp_close();
|
||||||
ftp_client *ftp_login(char *addr, char *username, char *password);
|
ftp_client *ftp_login(char *addr, char *username, char *password);
|
||||||
int ftp_downloadfile(ftp_client *ftp, char *file_name);
|
int ftp_downloadfile(ftp_client *ftp, char *file_name);
|
||||||
int ftp_uploadfile(ftp_client *ftp, char *file_name);
|
int ftp_uploadfile(ftp_client *ftp, char *file_name);
|
||||||
|
|
|
@ -36,6 +36,8 @@ typedef struct ftp_client_struct
|
||||||
|
|
||||||
### FTP server
|
### FTP server
|
||||||
|
|
||||||
|
FTP server 的代码托管在 https://github.com/JasenChao/ftp_server.git 。
|
||||||
|
|
||||||
FTP server设计为:
|
FTP server设计为:
|
||||||
|
|
||||||
```c
|
```c
|
||||||
|
@ -78,9 +80,7 @@ typedef struct _ftp_server
|
||||||
|
|
||||||
3. 将开发板与路由器连接,根据实际情况修改代码中的网卡配置部分,使得开发板可以上网。
|
3. 将开发板与路由器连接,根据实际情况修改代码中的网卡配置部分,使得开发板可以上网。
|
||||||
|
|
||||||
4. `TestFtpClientFinal` 命令需要一个参数,参数可选 `upload` 和 `download`,分别会启动 10 个线程,进行文件名拼接,然后登陆到 FTP server,进行对应文件的上传/下载。注意需要将测试程序中 `ftp_login` 的 server ip、用户名以及密码替换为实际情况的内容。
|
4. `TestFtpClientFinal` 命令需要一个参数,参数可选 `init`、`close`、`upload`、`download`,分别会初始化和关闭FTP,启动 10 个线程,进行文件名拼接,然后登陆到 FTP server,进行对应文件的上传/下载。注意需要将测试程序中 `ftp_login` 的 server ip、用户名以及密码替换为实际情况的内容。
|
||||||
|
|
||||||
5. 关闭 FTP client。
|
|
||||||
|
|
||||||
## 4. 运行结果(需结合运行测试截图按步骤说明)
|
## 4. 运行结果(需结合运行测试截图按步骤说明)
|
||||||
|
|
||||||
|
@ -96,28 +96,30 @@ typedef struct _ftp_server
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
5. 执行 `TestFtpClientFinal download` 命令,10 个线程并发创建 10 个 client 下载对应的 10 个文件,可以看到下载过程是并发进行的。
|
5. 执行 `TestFtpClientFinal init` 命令,初始化网卡和互斥量。
|
||||||
|
|
||||||

|

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

|

|
||||||

|

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

|

|
||||||
|
|
||||||
6. 执行 `ls` 命令,看到文件全部下载成功,大小与 server 一致。
|
8. 在 server 端执行 `rm file_*` 命令,删除服务器端的测试文件。
|
||||||
|
|
||||||

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

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
|
|
||||||
|
9. 在 server 端执行 `ll --block-size=1` 命令,可以看到文件全部重新上传,时间与之前删除的相比有变化,大小与之前一致,通过打开比对可以发现内容也一致。
|
||||||
|
|
||||||

|

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

|
|
||||||
|
|
||||||
10. 测试结束。
|
10. 测试结束。
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 115 KiB |
Before Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 124 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 136 KiB After Width: | Height: | Size: 74 KiB |
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 105 KiB |
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 72 KiB |
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 98 KiB |
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 39 KiB |
|
@ -42,14 +42,14 @@ void TestFtpClientFinal(int argc, char *argv[]) {
|
||||||
|
|
||||||
pthread_attr_t attr;
|
pthread_attr_t attr;
|
||||||
attr.schedparam.sched_priority = 22;
|
attr.schedparam.sched_priority = 22;
|
||||||
attr.stacksize = 4096;
|
attr.stacksize = 2048;
|
||||||
|
|
||||||
memset(f, 0, sizeof(f));
|
memset(f, 0, sizeof(f));
|
||||||
|
|
||||||
/* Initialize the network IP */
|
/* Initialize the network IP */
|
||||||
char self_ipaddr[] = {192, 168, 130, 77};
|
char self_ipaddr[] = {192, 168, 130, 77};
|
||||||
char self_netmask[] = {255, 255, 254, 0};
|
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);
|
lwip_config_tcp(0, self_ipaddr, self_netmask, self_gwaddr);
|
||||||
|
|
||||||
if (strcmp(argv[1], "upload") == 0) {
|
if (strcmp(argv[1], "upload") == 0) {
|
||||||
|
@ -64,6 +64,10 @@ void TestFtpClientFinal(int argc, char *argv[]) {
|
||||||
pthread_t down;
|
pthread_t down;
|
||||||
PrivTaskCreate(&down, &attr, &downloadfunc, &i);
|
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);
|
PRIV_SHELL_CMD_FUNCTION(TestFtpClientFinal, 2023 open source contest final 1 st issue3, PRIV_SHELL_CMD_MAIN_ATTR);
|