【linux小项目FTP云盘实现】

linux小项目FTP云盘实现


前言

这两天将之前学的linux基础知识(文件IO操作、进程、线程、网络编程、进程间通信)重新过了一遍,嗯整体来说比第一次学习对知识点的理解更加深刻了,很多之前模棱两可的概念,也有了自己的理解。俗话说:“温故而知新,可以为师矣”这些古人的说的都是很有道理的。

对于我个人学习来说,可能并不是很聪明,但是我也相信勤能补拙,所以也愿意花时间去将之前学的知识点一遍又一遍的复习,将学习到的知识点通过一个又一个的小实验进行演示,这样的学习方式对我个人来说是很有效的,确实感觉到了自己的不断进步。
对于编程学习来说,光通过看视频就想变强,可以说真的不可能,真的只能不断的敲代码,不断的制造Bug 又不断的花时间去解决最后不断的总结知识点,这样我们才能在编程道路上不断的成长。对每个新知识的学习,我自己感觉还是很有自信的,总的来说自己还是比较自律,也有明确的计划和目标,嗯,总之每天都要让自己前进一小步 加油加油。(一直都在奋斗的小殷同学)

嗯 FTP云盘这个小项目服务端和客户端加起来差不多500多行代码,当然对于其中的很多细节可能并没有处理,只是大概将功能实现了,get xxx 和 put xxx进行文件的下载和上传时还有一些小问题,不过能可以获取到我们想要的内容,后面会在优化。


提示:以下是本篇文章正文内容,下面案例可供参考

一、服务端 Server实现



/*********************************FTP-Server************************************
*实现客户端与服务端消息发送(服务端只进行接受处理指令)
*Date:2022-2-25
*Author:小殷同学
*Version:1.0
*******************************************************************************/

#include <stdio.h>
#include <sys/types.h>			/* See NOTES */
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>

//命令宏定义
#define LS  1
#define CD  2
#define PWD 3
#define LCD 4
#define LLS 5
#define GET 6
#define PUT 7
#define QUIT 8
#define DOFILE 9

#define MAX_LISTEN 20 //同时进行最大监听数

struct FTP
{
    
    
	int type;             //类型
	char databuf[1024];   //数据
	char buf[1024]; //数据
	char cmd[24];         //命令
};

struct FTP msg;


int get_cmd_type(char *cmd );
char *getDesDir(char *str);
void MSG_Handler(struct FTP msg,int fd);//信息处理

int main(int argc,char *argv[])
{
    
    

	int s_fd = 0,c_fd = 0;

	int addr_len = 0;
	int n_read = 0;
	struct sockaddr_in s_addr,c_addr;


	//1.创建套接字
	//int socket(int domain, int type, int protocol);
	s_fd = socket(AF_INET,SOCK_STREAM,0);
	if(s_fd == 0)
	{
    
    
		printf("socket error\n");
		exit(-1);
		
	}
	//清空
	//void *memset(void *s, int c, size_t n);
	memset(&s_addr,'0',sizeof(struct sockaddr_in));
	memset(&c_addr,'0',sizeof(struct sockaddr_in));

	s_addr.sin_family = AF_INET;
	
	//uint16_t htons(uint16_t hostshort);
	//int atoi(const char *nptr);
	
	s_addr.sin_port = htons(atoi(argv[2]));   //端口号转换

	//int inet_aton(const char *cp, struct in_addr *inp);
	
	inet_aton(argv[1],&s_addr.sin_addr);	 //IP 地址
	//2.绑定
	// int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
	
	if(bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in)) == -1)
	{
    
    
		printf("bind error\n");
		exit(-1);
	}
	//3.监听
	//int listen(int sockfd, int backlog);

	
	if(listen(s_fd,MAX_LISTEN) == -1)
	{
    
    
		printf("listen error\n");
		exit(-1);
	}
	addr_len = sizeof(struct sockaddr_in);
	while(1)
	{
    
    
		//4.接受
		static int i = 0;
		//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
		c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&addr_len);
		if(c_fd == -1)
		{
    
    
			printf("accept error\n");
			exit(-1);
		}
		i++;
		//char *inet_ntoa(struct in_addr in);
		//连接成功将每次的ip和端口打印
		printf("connect success No %d client ip:%s port:%d\n",i,inet_ntoa(c_addr.sin_addr),ntohs(c_addr.sin_port));
		//5.读写
		if(fork() == 0)
			{
    
    
						while(1)
							{
    
    
								printf("--------------------------wait cmd----------------------\n");
								n_read = read(c_fd,msg.cmd,sizeof(msg.cmd));
								if(n_read > 0)
									{
    
    
											MSG_Handler(msg,c_fd);											

									}
								else if(n_read == 0)
									{
    
    

										printf("Client had quit connect\n");
										exit(0);
									}
								else
									{
    
    
										printf("read error\n");
										exit(-1);
									}
								
								
							}
						
					}
			}
	
		//6.关闭
		close(c_fd);
		close(s_fd);
		return 0;

	}
	



/*---------------------------------------相关功能函数--------------------------------*/

//获取命令
int get_cmd_type(char *cmd )
{
    
    
	if(!strcmp("ls",cmd))  return LS;
	if(!strcmp("quit",cmd))  return QUIT;
   	if(!strcmp("pwd",cmd))  return PWD;
	
	if(strstr(cmd,"cd") != NULL)  return CD;
	if(strstr(cmd,"get") != NULL)  return GET;
	if(strstr(cmd,"put") != NULL)  return PUT;
	
	return 100;

}



//获取分隔文件
char *getDesDir(char *str)
{
    
    
		
	char *p;
	p = strtok(str," "); //str 要分隔的字符串 以空格进行分隔
	p = strtok(NULL," "); //第二次要以NULL 作为str

	printf("p is  <%s>\n",p); //打印获取的文件
	return p;
} 



//服务端获取命令后进行处理解析
void MSG_Handler(struct FTP msg,int fd)
{
    
    
	int ret = 0;
	FILE *fp = NULL;
	char *file = NULL; //获取文件
	int ffile = 0; //文件打开返回描述符
	int len = 0; //计算文件长度
	char buf[1024] = {
    
    0}; //缓存内容
	char *p = NULL;
	
	//获取命令
	ret = get_cmd_type(msg.cmd);
	printf("Get cmd = %d\n",ret);
	switch(ret)
		{
    
    
			case LS:
			case PWD:
				
				//FILE *popen(const char *command, const char *type);
				fp = popen(msg.cmd,"r"); //将获取的内容通过popen 函数打印出来
				if(NULL == fp)
					{
    
    
						printf("popen failed\n");
						exit(-1);
					}
				//读取
				//size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
				fread(msg.databuf,sizeof(msg.databuf),1,fp);
				pclose(fp);
				//将获取的信息通过c_fd写回客户端
				
				//ssize_t write(int fd, const void *buf, size_t count);
				write(fd,msg.databuf,sizeof(msg.databuf));
				break;
			case CD:
				p = getDesDir(msg.cmd);
				chdir(p);  //int chdir(const char *path); 路径处理
				break;
			case GET:
				//获取文件
			
				file = getDesDir(msg.cmd);
				//判断该文件是否存在
				//int access(const char *pathname, int mode);
				if(access(file,F_OK) == -1) //不存在
					{
    
    
						//写入错误信息
						strcpy(msg.databuf,"this file not exit");
						//将信息返回给客户端
						write(fd,msg.databuf,sizeof(msg.databuf));
					}
				//该文件存在
				//打开文件将文件所以内容复制到buf中 在将其赋值给msg.data 发送到客户端
				ffile = open(file,O_RDWR);  //以可读可写的方式打开
				len = lseek(ffile,0,SEEK_END);  //计算文件总长度
				lseek(ffile,0,SEEK_SET); //将其再次移动到开头 否则读取不到数据
				read(ffile,buf,len); //读取内容
				close(ffile);
				msg.type = DOFILE;  //标志
				strcpy(msg.databuf,buf);  //将读取的内容复制到msg.data
				write(fd,&msg,sizeof(msg)); //发送到客户端
				printf("get success\n");
				break;
			case QUIT:
				printf("Client quit\n");
				exit(-1);
				break;
			case PUT:
				//先判断文件是否存在 在打开 将内容写入
				 ffile = open(getDesDir(msg.cmd),O_RDWR|O_CREAT,0666);
				 write(ffile,msg.buf,strlen(msg.buf)); 
				 close(ffile);
			default:
				strcpy(buf,"cmd not exit");
				write(fd,msg.databuf,sizeof(msg.databuf));
				break;
		}

}



二、客户端 Client 实现



/*********************************FTP-Client************************************
*实现客户端与服务端消息发送(服务端只进行接受处理指令)
*Date:2022-2-25
*Author:小殷同学
*Version:1.0
*******************************************************************************/

#include <stdio.h>
#include <sys/types.h>			/* See NOTES */
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>



//命令宏定义
#define LS  1
#define CD  2
#define PWD 3
#define LCD 4
#define LLS 5
#define GET 6
#define PUT 7
#define QUIT 8
#define DOFILE 9

#define MAX_LISTEN 20 //同时进行最大监听数

struct FTP
{
    
    
	int type;             //类型
	char databuf[1024];   //数据
	char buf[1024];  //数据
	char cmd[24];         //命令
};


struct FTP msg;

int get_cmd_type(char *cmd );
char *getDesDir(char *str);
int MSG_Write_Handler(struct FTP msg,int fd);
void 	MSG_Read_Handler(struct FTP msg,int fd);



int main(int argc,char *argv[])
{
    
    

	int c_fd = 0;
	int ret = 0,mark = 0;
	struct sockaddr_in c_addr;

	//1.创建套接字
	//int socket(int domain, int type, int protocol);
	c_fd = socket(AF_INET,SOCK_STREAM,0);
	if(c_fd == 0)
	{
    
    
		printf("socket error\n");
		exit(-1);
		
	}
	//清空
	//void *memset(void *s, int c, size_t n);
	memset(&c_addr,'0',sizeof(struct sockaddr_in));

	c_addr.sin_family = AF_INET;
	
	//uint16_t htons(uint16_t hostshort);
	//int atoi(const char *nptr);
	
	c_addr.sin_port = htons(atoi(argv[2]));   //端口号转换

	//int inet_aton(const char *cp, struct in_addr *inp);
	
	inet_aton(argv[1],&c_addr.sin_addr);	 //IP 地址

	//2.连接connect
	//int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
	if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr_in)) == -1)
	{
    
    

	    printf("connect error\n");
		exit(-1);
	}
	//连接成功  打印相关信息 IP 
	printf("connect success ip:%s\n",inet_ntoa(c_addr.sin_addr));
	while(1)
		{
    
    

			//创建子进程进行命令写入 父进程进行数据接收显示
			if(fork() == 0) //子进程创建成功
				{
    
    
					while(1)
						{
    
    
							//每次进行命令的输入将前一次清空
							memset(msg.cmd,'0',sizeof(msg.cmd));
							printf(">>>");
							fflush(stdout);
							//printf("input cmd:");
							gets(msg.cmd);
							//将命令发送给服务端
							//write(c_fd,msg.cmd,sizeof(msg.cmd));
							MSG_Write_Handler(msg,c_fd);
							printf("---------------------send cmd done----------------\n\n");
						}
				}

			while(1)
				{
    
    
					MSG_Read_Handler(msg,c_fd);

				}			
			
		}

	//6.关闭

	close(c_fd);
	return 0;

}



/*---------------------------------------相关功能函数--------------------------------*/

//获取命令
int get_cmd_type(char *cmd )
{
    
    
	if(!strcmp("ls",cmd))  return LS;
	if(!strcmp("quit",cmd))  return QUIT;
   	if(!strcmp("pwd",cmd))  return PWD;
	if(!strcmp("lls",cmd))  return LLS;
	if(!strcmp("lcd",cmd)) return LCD;
	
	if(strstr(cmd,"cd") != NULL)  return CD;
	if(strstr(cmd,"get") != NULL)  return GET;
	if(strstr(cmd,"put") != NULL)  return PUT;
	
	return 100;

}



char *getDesDir(char *str)
{
    
    
		
	char *p;
	p = strtok(str," ");
	p = strtok(NULL," ");

	printf("p is  <%s>\n",p);
	return p;
} 



int MSG_Write_Handler(struct FTP msg,int fd)
{
    
    
	int ret = 0;
	char *dir = NULL;
	int filefd = 0;
	ret = get_cmd_type(msg.cmd);
	switch(ret)
		{
    
    

			case LS:
			case PWD:
			case CD:
				write(fd,msg.cmd,sizeof(msg.cmd));
				break;
			case GET:
				//msg.type = DOFILE;
				write(fd,msg.cmd,sizeof(msg.cmd));
				break;
			case LLS:
				system("ls");
				break;
			case QUIT:
				write(fd,msg.cmd,sizeof(msg.databuf));
				exit(-1);
				break;
			case PUT:
				//先判断该文件是否存在物
				dir = getDesDir(msg.cmd);
				if(access(dir,F_OK)  == 0)
					{
    
    
						printf("file not exit\n");
						fflush(stdout);;
					}
				//存在该内容读取到啊文件
				filefd = open(dir,O_RDWR);
				read(filefd,msg.buf,sizeof(msg.buf));
				close(filefd);
				//写入
				write(fd,&msg,sizeof(msg));	
				break;

		}

}


void 	MSG_Read_Handler(struct FTP msg,int fd)
{
    
    
	int n_read = 0;
	int newfilefd = 0;

	n_read = read(fd,&msg,sizeof(msg));
	if(n_read == 0)
		{
    
    
			printf("Server Had Quit\n");
			exit(0);
		}
	else if(msg.type == DOFILE)
		{
    
    
			printf("had read file1\n");
			char *file = getDesDir(msg.cmd); //获取该文件
			newfilefd = open(file,O_RDWR | O_CREAT,0666); //以可读可写打开 如果不存在则创建
			write(newfilefd,msg.databuf,strlen(msg.databuf));//将内容写入文件中
			close(newfilefd);
			printf(">>>");
			fflush(stdout);	
		}
	else
		{
    
    

			printf("---------------------get data------------------\n");
			printf("%s\n",msg.databuf);
			printf("------------------------------------------------\n\n");
			
			printf(">>>");
			fflush(stdout);
		}
}

三、实现结果

在这里插入图片描述


总结

对自己学习的检验最好的方法就是做一个比较综合的小项目,查漏补缺,及时进行复习巩固。加油鸭

猜你喜欢

转载自blog.csdn.net/boybs/article/details/123157185