2023_open_source_contest_preliminary_1st_issue3

This commit is contained in:
jager 2023-10-01 23:49:47 +08:00
parent a1df906d16
commit 7e15ce0d71
20 changed files with 669 additions and 6 deletions

View File

@ -0,0 +1,321 @@
/*
* Copyright (c) 2020 AIIT Ubiquitous Team
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL
v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file: FTP_client.h
* @brief: a application of ftp client function
* @version: 1.0
* @author: bdislab_Rhodes
* @date: 2023/9/30
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "mysocket.h"
#include "log.h"
static int m_socket_cmd;
static int m_socket_data;
static char m_send_buffer[1024];
static char m_recv_buffer[1024];
//命令端口,发送命令
static int FtpSendCommand(char* cmd)
{
int ret;
LogInfo("send command: %s\r\n", cmd);
ret = SocketSend(m_socket_cmd, cmd, (int)strlen(cmd));
if (ret < 0)
{
LogInfo("failed to send command: %s", cmd);
return 0;
}
return 1;
}
//命令端口,接收应答
static int FtpRecvRespond(char* resp, int len)
{
int ret;
int off;
len -= 1;
for (off = 0; off < len; off += ret)
{
ret = SocketRecv(m_socket_cmd, &resp[off], 1);
if (ret < 0)
{
LogInfo("recv respond error(ret=%d)!\r\n", ret);
return 0;
}
if (resp[off] == '\n')
{
break;
}
}
resp[off + 1] = 0;
LogInfo("respond:%s", resp);
return atoi(resp);
}
//设置FTP服务器为被动模式并解析数据端口
static int FtpEnterPasv(char* ipaddr, int* port)
{
int ret;
char* find;
int a, b, c, d;
int pa, pb;
char command_pasv[] = "PASV\r\n";
ret = FtpSendCommand(command_pasv);
if (ret != 1)
{
return 0;
}
ret = FtpRecvRespond(m_recv_buffer, 1024);
if (ret != 227)
{
return 0;
}
find = strrchr(m_recv_buffer, '(');
sscanf(find, "(%d,%d,%d,%d,%d,%d)", &a, &b, &c, &d, &pa, &pb);
sprintf(ipaddr, "%d.%d.%d.%d", a, b, c, d);
*port = pa * 256 + pb;
return 1;
}
//上传文件
int FtpUpload(char* name, void* buf, int len)
{
int ret;
char ipaddr[32];
int port;
//查询数据地址
ret = FtpEnterPasv(ipaddr, &port);
if (ret != 1)
{
return 0;
}
ret = SocketConnect(m_socket_data, ipaddr, port);
if (ret != 1)
{
return 0;
}
//准备上传
sprintf(m_send_buffer, "STOR %s\r\n", name);
ret = FtpSendCommand(m_send_buffer);
if (ret != 1)
{
return 0;
}
ret = FtpRecvRespond(m_recv_buffer, 1024);
if (ret != 150)
{
SocketClose(m_socket_data);
return 0;
}
//开始上传
ret = SocketSend(m_socket_data, buf, len);
if (ret != len)
{
LogInfo("send data error!\r\n");
SocketClose(m_socket_data);
return 0;
}
SocketClose(m_socket_data);
//上传完成,等待回应
ret = FtpRecvRespond(m_recv_buffer, 1024);
return (ret == 226);
}
//下载文件
int FtpDownload(char* name, char* buf, int len)
{
int i;
int ret;
char ipaddr[32];
int port;
//查询数据地址
ret = FtpEnterPasv(ipaddr, &port);
if (ret != 1)
{
return 0;
}
//连接数据端口
ret = SocketConnect(m_socket_data, ipaddr, port);
if (ret != 1)
{
printf("errno = %d",errno);
LogInfo("failed to connect data port\r\n");
return 0;
}
//准备下载
sprintf(m_send_buffer, "RETR %s\r\n", name);
ret = FtpSendCommand(m_send_buffer);
if (ret != 1)
{
return 0;
}
ret = FtpRecvRespond(m_recv_buffer, 1024);
if (ret != 150)
{
SocketClose(m_socket_data);
return 0;
}
//开始下载,读取完数据后,服务器会自动关闭连接
for (i = 0; i < len; i += ret)
{
ret = SocketRecv(m_socket_data, ((char*)buf) + i, len);
LogInfo("download %d/%d.\r\n", i + ret, len);
if (ret < 0)
{
LogInfo("download was interrupted.\r\n");
break;
}
}
//下载完成
printf("\n下载完成 : \n %s",buf);
LogInfo("download %d/%d bytes complete.\r\n", i, len);
SocketClose(m_socket_data);
ret = FtpRecvRespond(m_recv_buffer, 1024);
return (ret == 226);
}
//返回文件大小
int FtpFileSize(char* name)
{
int ret;
int size;
sprintf(m_send_buffer, "SIZE %s\r\n", name);
ret = FtpSendCommand(m_send_buffer);
if (ret != 1)
{
return 0;
}
ret = FtpRecvRespond(m_recv_buffer, 1024);
if (ret != 213)
{
return 0;
}
size = atoi(m_recv_buffer + 4);
return size;
}
//登陆服务器,成功返回1失败返回0
int FtpLogIn(char* addr, int port, char* username, char* password)
{
int ret;
LogInfo("connect...\r\n");
ret = SocketConnect(m_socket_cmd, addr, port);
if (ret != 1)
{
LogInfo("connect server failed!\r\n");
return 0;
}
LogInfo("connect ok.\r\n");
//等待欢迎信息
ret = FtpRecvRespond(m_recv_buffer, 1024);
if (ret != 220)
{
LogInfo("bad server, ret=%d!\r\n", ret);
SocketClose(m_socket_cmd);
return 0;
}
ret = FtpRecvRespond(m_recv_buffer, 1024);
if (ret != 220)
{
LogInfo("bad server, ret=%d!\r\n", ret);
SocketClose(m_socket_cmd);
return 0;
}
ret = FtpRecvRespond(m_recv_buffer, 1024);
if (ret != 220)
{
LogInfo("bad server, ret=%d!\r\n", ret);
SocketClose(m_socket_cmd);
return 0;
}
LogInfo("login...\r\n");
//发送USER
sprintf(m_send_buffer, "USER %s\r\n", username);
ret = FtpSendCommand(m_send_buffer);
if (ret != 1)
{
SocketClose(m_socket_cmd);
return 0;
}
ret = FtpRecvRespond(m_recv_buffer, 1024);
if (ret != 331)
{
SocketClose(m_socket_cmd);
return 0;
}
//发送PASS
sprintf(m_send_buffer, "PASS %s\r\n", password);
ret = FtpSendCommand(m_send_buffer);
if (ret != 1)
{
SocketClose(m_socket_cmd);
return 0;
}
ret = FtpRecvRespond(m_recv_buffer, 1024);
if (ret != 230)
{
SocketClose(m_socket_cmd);
return 0;
}
LogInfo("login success.\r\n");
//设置为二进制模式
char command_binary[] = "TYPE I\r\n";
ret = FtpSendCommand(command_binary);
if (ret != 1)
{
SocketClose(m_socket_cmd);
return 0;
}
ret = FtpRecvRespond(m_recv_buffer, 1024);
if (ret != 200)
{
SocketClose(m_socket_cmd);
return 0;
}
return 1;
}
void FtpQuit(void)
{
char command_quit[] = "QUIT\r\n";
FtpSendCommand(command_quit);
SocketClose(m_socket_cmd);
}
void FtpInit(void)
{
m_socket_cmd = SocketCreate();
m_socket_data = SocketCreate();
}

View File

@ -0,0 +1,105 @@
# **初赛一级赛题3基于矽璓已实现的Lwip在ARM上实现FTP协议的Client功能**
参赛战队bdislab_Rhodes
赛题issue初赛一级赛题3
完成情况在ARM终端实现FTP Client的功能即基于XiZi内核移植支持FTP Client库执行 FTP协议的Client实现在搭建的FTP服务器上下载10个文件。
## 1. 简介
基于矽璓已实现的Lwip在ARM上实现FTP协议的Client功能并从在个人电脑中搭建的FTP server上下载十个文件。
## 2. 数据结构设计说明
使用ftp_info结构体存储基本信息
```c
//配置信息
typedef struct ftp_info
{
char* ip;//目的服务器ip
int port;//目的端口号
char* usrname;//登录ftp服务器使用的用户名
char* password;//用户名对应的密码
char** filepath;//要下载的文件路径
}Client_Info;
```
主要实现了以下函数:
```c
FtpInit();//创建套接字
FtpLogIn(char* addr, int port, char* username, char* password);//登录服务器
FtpFileSize(char* path);//查询path路径下的文件大小
FtpDownload(char* name, char* buf, int len);//下载path路径下的文件到buf
FtpQuit();//关闭套接字
```
## 3. 测试程序说明
测试程序 `TestFTP` 已经注册为 shell 命令,可以调用执行。
测试程序主要完成以下流程:
- 录入基本信息包括目标ip地址、端口号、用户名、密码、目标文件路径等。
- 创建套接字
- 登录服务器
- 询问目标文件大小
- 下载目标文件,并将下载到的内容打印出来
- 关闭套接字
- 重复上述动作共十次
由于程序中目标服务器端口号用户名密码以及要下载的文件路径在程序中被提前初始化好了运行时只需要输入目标服务器的ip地址即可。
## 4. 运行结果
利用华大提供的烧录工具烧录入ARM教育开发板
![image-20231001230717436](image/image-20231001230717436.png)
利用FileZilla建立FTP服务器
![image-20230930215803743](image/image-20230930215803743.png)
利用xshell通过相应串口连上开发板并通过Help指令查看帮助发现TestFTP已成功注册
![image-20231001230846140](image/image-20231001230846140.png)
利用setip指令设置ip
<img src="image/image-20230930214729100.png" alt="image-20230930214729100" style="zoom: 200%;" />
利用showip指令查看ip设置成功
<img src="image/image-20230930214750512.png" alt="image-20230930214750512" style="zoom: 200%;" />
使用已注册的TestFTP指令连接FTP服务器并下载十个文件
输入建立的FTP服务器ip连接成功并收到欢迎信息
<img src="image/image-20230930214819589.png" alt="image-20230930214819589" style="zoom:200%;" />
发送用户名及密码进行登录成功登录并发送TYPE I指令进入二进制模式
<img src="image/image-20230930215122449.png" alt="image-20230930215122449" style="zoom:200%;" />
从FTP服务器上查询目标文件大小并进行下载下载完成后输出下载到的内容
![image-20230930215346610](image/image-20230930215346610.png)
第一个文件下载完毕,紧接着下载后续九个文件,部分下载到的内容如下
![image-20230930215455339](image/image-20230930215455339.png)
![image-20230930215507232](image/image-20230930215507232.png)
![image-20230930215526406](image/image-20230930215526406.png)
回到FTP服务器的界面可以看到之前收到的命令请求
![image-20230930215726004](image/image-20230930215726004.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 285 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 484 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 KiB

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2020 AIIT Ubiquitous Team
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL
v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file: log.h
* @brief: a application of ftp client function
* @version: 1.0
* @author: bdislab_Rhodes
* @date: 2023/9/30
*/
#ifndef __my__LOG_H
#define __my__LOG_H
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
void LogInfo(const char* format, ...) {
va_list args;
va_start(args, format);
int len = strlen(format);
// 只使用空格作为分隔符
for (int i = 0; i < len; ++i) {
if (format[i] == '%') {
if (format[i + 1] == 'd') {
int val = va_arg(args, int);
printf("%d",val);
}
else if (format[i + 1] == 's') {
char* s = va_arg(args, char*);
printf("%s",s);
}
i++;
continue;
}
else if (format[i] == ' ') {
printf("%c",' ');
}
else {
printf("%c",format[i]);
}
}
printf("\n");
va_end(args);
}
#endif

View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2020 AIIT Ubiquitous Team
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL
v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file: mysocket.c
* @brief: a application of ftp client function
* @version: 1.0
* @author: bdislab_Rhodes
* @date: 2023/9/30
*/
#ifndef __SOCKET_H
#define __SOCKET_H
#include <lwip/sockets.h>
#include <unistd.h>
int SocketCreate(void);
int SocketConnect(int ,char* , int );
void SocketClose(int );
int SocketSend(int sock, void* data, int len);
int SocketRecv(int sock, void* data, int len);
int SocketCreate(void) {
return socket(AF_INET, SOCK_STREAM, 0);
}
int SocketConnect(int sock, char* addr, int port) {
struct sockaddr_in seraddr;
memset(&seraddr, 0, sizeof(seraddr));//初始化seraddr
seraddr.sin_family = AF_INET;
//本机字节序转换为网络字节序(包括ip与端口号)
//通过传给main的参数获取服务器端口号与ip
seraddr.sin_port = htons(port);//端口号
seraddr.sin_addr.s_addr = inet_addr(addr);//ip
memset(&(seraddr.sin_zero), 0, sizeof(seraddr.sin_zero));
printf("test point 1\n");
return 1+connect(sock, (struct sockaddr*)&seraddr, sizeof(seraddr));
}
void SocketClose(int sock) {
close(sock);
}
int SocketSend(int sock, void* buf, int len) {
return send(sock, buf, len, 0);
}
int SocketRecv(int sock, void* buf, int len) {
return recv(sock, buf, len, 0);
}
#endif

View File

@ -0,0 +1,107 @@
/*
* Copyright (c) 2020 AIIT Ubiquitous Team
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL
v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file: test_ftpclient.c
* @brief: a application of ftp client function
* @version: 1.0
* @author: bdislab_Rhodes
* @date: 2023/9/30
*/
#include"FTP_client.h"
#include<transform.h>
#define NUM_OF_FILES 10
//配置信息
typedef struct ftp_info
{
char* ip;//目的服务器ip
int port;//目的端口号
char* usrname;//登录ftp服务器使用的用户名
char* password;//用户名对应的密码
char** filepath;//要下载的文件路径
}Client_Info;
int TestFTP(){
//信息初始化
Client_Info info = {.ip = "192.168.1.102",
.port = 21,
.usrname = "lyq1",
.password = "255967558"
};
info.filepath = (char**)malloc(10* sizeof(char*));
char *file[] = {"testfile1.txt","testfile2.txt","testfile3.txt","testfile4.txt","testfile5.txt",
"testfile6.txt","testfile7.txt","testpicture1.txt","testpicture2.txt","testpicture3.txt"};
info.filepath = file;
char _ip[15];
printf("请输入ip: ");
scanf("%s",_ip);
info.ip = _ip;
printf("ip input = %s\n",info.ip);
//逐个询问filepath中每个文件的大小并下载
for(int i = 0;i<NUM_OF_FILES;++i){
//创建套接字
FtpInit();
int ret = FtpLogIn(info.ip, info.port, info.usrname, info.password);
if (!ret) {
printf("login failed\n");
return -1;
}
printf("开始访问文件【%s】\n",info.filepath[i]);
int size = FtpFileSize(info.filepath[i]);
printf("文件大小为:%d\n",size);
char* buf = (char*)malloc(size);
ret = FtpDownload(info.filepath[i], buf, size);
if(!ret){
printf("download failed\n");
return -1;
}
FtpQuit();
free(buf);
}
return 0;
}
PRIV_SHELL_CMD_FUNCTION(TestFTP,download 10 files from FTP server, PRIV_SHELL_CMD_MAIN_ATTR);

View File

@ -29,7 +29,7 @@ int write(int fd, const void *buf, size_t len);
int open(const char* path, int flags, ...);
int close(int fd);
int ioctl(int fd, int cmd, ...);
int ioctl(int fd, long cmd, void* argp);
off_t lseek(int fd, off_t offset, int whence);
int rename(const char *from, const char *to);
int unlink(const char *path);

View File

@ -575,7 +575,7 @@ int write(int fd, const void *buf, size_t len)
}
#ifndef LIB_MUSLLIB
int ioctl(int fd, int cmd, ...)
int ioctl(int fd, long cmd, void* argp)
{
int ret;
struct FileDescriptor *fdp;
@ -591,10 +591,9 @@ int ioctl(int fd, int cmd, ...)
return -1;
}
va_list ap;
va_start(ap, cmd);
ret = fdp->mntp->fs->ioctl(fdp, cmd, (void*)va_arg(ap, long));
va_end(ap);
ret = fdp->mntp->fs->ioctl(fdp, cmd, (void*)argp);
if (ret < 0) {
SYS_ERR("%s: ioctl file failed\n", __func__);
KUpdateExstatus(ret);