2023_open_source_contest_final_1st_issue3
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
|||
|
||||

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

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

|
||||

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

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

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

|
||||

|
||||

|
||||

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

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

|
||||
|
||||
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;
|
||||
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);
|