FTP云盘

Posted 行稳方能走远

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了FTP云盘相关的知识,希望对你有一定的参考价值。

参考:FTP云盘项目
作者:糯米啊啊
发布时间: 2021-08-19 10:34:05
网址:https://blog.csdn.net/weixin_43732386?spm=1001.2014.3001.5509

参考:自制FTP云盘项目
作者:不说话的小脑斧
发布时间: 2021-01-13 12:02:23
网址:https://blog.csdn.net/qq_44745336/article/details/112547781?spm=1001.2014.3001.5502

以及:https://blog.csdn.net/zouchengzhi1021/article/details/113668089

项目简介

FTP服务器(File Transfer Protocol Server)是在互联网上提供文件存储和访问服务的计算机,它们依照FTP协议提供服务。 FTP是File Transfer Protocol(文件传输协议)。

程序运行,服务端不断接收客户端指令,服务端可同时处理多个客户端接入并对指令作出解析,并把执行结果返回给客户端,客户端根据服务端对指令的解析并把由服务端传递过来的处理信息通过客户端呈现给客户,实现文件的各种操作。

功能说明

本文是基于Linux网络编程实现的FTP服务器,服务器由服务端和客户端组成,具有浏览远程服务端的文件和浏览客户端本地文件,同时支持对远程服务端文件的删除,存储,归档操作处理,以及客户端对远程服务端文件的上传和下载。

利用socket实现云盘的基本功能:

  • ls———查看服务端文件
  • lls———查看客户端自己的文件
  • cd———切换服务端目录
  • lcd———切换客户端自己的目录
  • put———上传文件
  • get———下载文件
  • pwd———显示路径
  • quit———退出

代码编写

config.h

#define LS		1
#define LLS		2
#define CD		3
#define GET		4
#define PUT		5
#define PWD		6
#define QUIT	0

typedef struct msg			//传递信息的结构体
{
	int type;//没有用到
	char cmd[128];//存放命令
	char data_buf[1024];//存放文件内容
}Msg;

服务端

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

int Analysis_Command(char *buf)		//分析命令
{
     //int strcmp(const char *s1, const char *s2);//字符串比较
	if(strcmp("ls",buf)==0)  				return LS;
	if(strcmp("pwd",buf)==0)  				return PWD;
	if(strcmp("quit",buf)==0)				return QUIT;
	if(strcmp("lls",buf)==0)				return LLS;
	//char *strstr(const char *haystack, const char *needle);//搜索一个字符串在另一个字符串中的第一次出现
	if(strstr(buf,"cd")!=NULL && strstr(buf,"lcd")==NULL)	return CD;
	if(strstr(buf,"get")!=NULL)				return GET;//因为用户输入指令 带参数
	if(strstr(buf,"put")!=NULL)				return PUT;
	return -1;
}

char *getDirName(char *cmd)		//获取文件名  最好定义成 get_dir(函数名 变量名)
{
	char *fileName = NULL;
	//char *strtok(char *s, char *delim)//分解字符串 str 为一组字符串,delim 为分隔符,返回值:分隔符匹配到的第一个子串
	fileName = strtok(cmd," ");		//分割字符串
	fileName = strtok(NULL," ");	//strtok函数固定用法	
	return fileName;
}


int dowork(int *c_fd)  //函数名规范定义 msgs_Handler
{
	int cmd = 666;		//无效的值
	FILE *p_fd;			//popen的返回值类型
	int n_read;				
	char *file_name = NULL;
	Msg r_msg_buf;		//socket通信间信息的载体
	Msg w_msg_buf;		//socket通信间信息的载体
	memset(&r_msg_buf,0,sizeof(Msg));
	memset(&w_msg_buf,0,sizeof(Msg));


    // ssize_t recv(int sockfd, void *buf, size_t len, int flags);//与read功能类似
    //视频里讲 用read读完就没了 这里使用recv返回值为0判断客户端断开连接
    //ssize_t read(int fd, void *buf, size_t count);
	read(*c_fd,&r_msg_buf,sizeof(Msg));		//从socket套接字中读取命令
	cmd = Analysis_Command(r_msg_buf.cmd);	//分析命令

	switch(cmd)
	{     //客户端那边也有一样的这些指令   相互对接
		case LS:
			p_fd = popen("ls -l","r");	//调用popen函数执行 "ls-l"
			if(p_fd == NULL)		//判断是否popen成功
			{
				printf("popen error\\n");
				exit(-1);
			}	
			fread(w_msg_buf.data_buf,1024,1,p_fd);//从块设备读到缓存
			write(*c_fd,&w_msg_buf,sizeof(Msg)); //缓存发给客户端,客户端调用read获得结果
			fclose(p_fd);		//关闭
			printf("get cmd : %s\\n",r_msg_buf.cmd);		//服务端调试信息
			break;
		case PWD:		//pwd和ls一样
			p_fd = popen("pwd","r");//调用popen函数执行 "pwd"
			if(p_fd == NULL)
			{
				printf("popen error\\n");
				exit(-1);
			}
			fread(w_msg_buf.data_buf,1024,1,p_fd);//将popen执行结果放在w_msg_buf.data_buf中
			write(*c_fd,&w_msg_buf,sizeof(Msg));//通过套接字将w_msg_buf.data_buf写到客户端吗,客户端调用read,然后输出即可获得结果
			fclose(p_fd);
			printf("get cmd : %s\\n",r_msg_buf.cmd);//服务端调试信息
			break;
		case LLS:
			printf("get cmd : lls\\n"); 		//lls指令是打印出客户端该目录下的文件,所以服务端不做操作,只打印一个调试信息
			break;
		case GET:
			file_name = getDirName(r_msg_buf.cmd);//获取文件名
			if(access(file_name,F_OK)==0)//通过文件名判断文件是否存在
			{
				int fd = open(file_name,O_RDWR);
				read(fd,w_msg_buf.data_buf,1024);
				write(*c_fd,&w_msg_buf,sizeof(Msg));//如果存在,即打开,读取,写入。
				close(fd);
			}
			else
			{
				strcpy(w_msg_buf.data_buf,"no this document!");//不存在则写入"no this document!"
				write(*c_fd,&w_msg_buf,sizeof(Msg));
			}
			printf("get cmd : %s %s\\n",r_msg_buf.cmd,file_name);
			break;
		case CD:		//进入服务端某文件夹
			file_name = getDirName(r_msg_buf.cmd);//(分割)获取文件夹名
			if(access(file_name,F_OK)==0)//判断该文件是否存在
			{
		    	//int chdir(const char *path)//改变当前工作目录
				chdir(file_name);//系统调用函数(同cd)改变当前目录,即进入了文件夹
				//不能用system(源码是fork 另起了一个shell  这里要求自己进入文件夹)
				
				strcpy(w_msg_buf.data_buf,file_name);
				write(*c_fd,&w_msg_buf,sizeof(Msg));
			}
			else
			{
				strcpy(w_msg_buf.data_buf,"the server no have this file directory!");//如果没有则写入"the server no have this file directory!"
				write(*c_fd,&w_msg_buf,sizeof(Msg));
			}
			printf("get cmd : %s %s\\n",r_msg_buf.cmd,file_name);//服务端调试信息
			break;
		case PUT:		//上传某文件到服务端
			file_name = getDirName(r_msg_buf.cmd);
			read(*c_fd,&r_msg_buf,sizeof(Msg));
			if(strcmp(r_msg_buf.data_buf, "The client no have this document!") != 0)
			{
				if(access(file_name,F_OK)==0) //如果文件存在
				{
					int fd = open(file_name,O_RDWR|O_TRUNC);//调用O_TRUNC将源文件内容删除,写入新内容
					write(fd,r_msg_buf.data_buf,strlen(r_msg_buf.data_buf));
					close(fd);
				}
				else
				{
					int fd = creat(file_name, 0666);//如果不存在,创建
					if(fd == -1)
					{
						perror("creat error!\\n");
					}
					if(write(fd, r_msg_buf.data_buf, strlen(r_msg_buf.data_buf)) == -1)//写入新内容
					{
						perror("write error!\\n");
					}
					close(fd);
				}
			
			}
			printf("get cmd : %s %s\\n",r_msg_buf.cmd,file_name);
			break;
		case QUIT:		//客户端退出
			write(*c_fd, &w_msg_buf, sizeof(Msg));
			printf("=====client exit=====\\n");
			close(*c_fd);
			exit(0);
			break;
		case -1:
			strcpy(w_msg_buf.data_buf, "Command error!");//指令错误
			write(*c_fd, &w_msg_buf, sizeof(Msg));
			printf("===== cmd error =====\\n");
			break;
	}
	return 0;
}

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

	int s_fd;
	int c_fd;

	struct sockaddr_in s_addr; 
	struct sockaddr_in c_addr;	//socket套接字所需要的结构体
	memset(&s_addr,0,sizeof(struct sockaddr_in));//清空
	memset(&c_addr,0,sizeof(struct sockaddr_in));
	int clen = sizeof(struct sockaddr_in);
	if(argc != 3){	//判断运行时传参是否正确
		printf("param error\\n");
		exit(-1);
	}

	s_addr.sin_family = AF_INET;
	s_addr.sin_port = htons(atoi(argv[2]));
	inet_aton(argv[1],&(s_addr.sin_addr));

  
    //1.socket//创建套接字
    //int socket(int domain, int type, int protocol);
    
	s_fd = socket(AF_INET,SOCK_STREAM,0);
	if(s_fd == -1)
	{
		printf("socket error\\n");
		perror("why");
	}
	
    //2.bind 绑定IP号及端口
    //int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

	if(bind(s_fd,(struct sockaddr *)&s_addr,clen) == -1)
	{
		printf("bind error\\n");
		perror("why");
	}

     //3.lieten 监听
     // int listen(int sockfd, int backlog);
	if(listen(s_fd,10) == -1)
	{
		printf("listen error\\n");
	}

	while(1){
        //4.accept 连接
        //int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen);
		c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clen);
		if(c_fd == -1)
		{
			printf("accept error\\n");
			perror("why");

		}
		if(fork()==0){		//有客户端连接,创建子进程来对接
			printf("***hava client***\\n");
			while(1)
			{
				dowork(&c_fd);
			}
		}

	}
	close(s_fd);
	return 0;
}

客户端

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

int Analysis_Command(char *buf)//分析指令
{
	if(strcmp(buf,"ls")==0)		return LS;
	if(strcmp(buf,"lls")==0)	return LLS;
	if(strcmp(buf,"pwd")==0)	return PWD;
	if(strcmp(buf,"quit")==0)	return QUIT;
	if(strstr(buf,"cd")!=NULL && strstr(buf,"lcd")==NULL)	return CD;
	if(strstr(buf,"get")!=NULL)	return GET;
	if(strstr(buf,"put")!=NULL)	return PUT;
	return -1;
}

char *getDirName(char *cmd)//获取文件名
{
        char *file_Name = NULL;
        file_Name = strtok(cmd," ");
        file_Name = strtok(NULL," ");//strtok函数固定用法
        return file_Name;
}

int doWork(int *c_fd)
{
	int cmd = 666;//无效的值
	FILE *p_fd;//popen的返回类型为FILE*
	char *file_name = NULL;
	Msg w_msg_buf;
	Msg r_msg_buf;//套接字信息传递过程中的载体
	memset(&w_msg_buf,0,sizeof(Msg));
	memset(&r_msg_buf,0,sizeof(Msg));//清空
	printf(">>");
	gets(w_msg_buf.cmd);//获取用户输入
	write(*c_fd,&w_msg_buf,sizeof(Msg));//将用户输入的指令写入套接字中,供服务端读取
	cmd = Analysis_Command(w_msg_buf.cmd);//分析指令
	printf("*****************************\\n");
	printf("\\n");
	switch(cmd)
	{
		case LS:
			read(*c_fd,&r_msg_buf,sizeof(Msg));//读取客户端popen的返回内容
			printf("%s",r_msg_buf.data_buf);以上是关于FTP云盘的主要内容,如果未能解决你的问题,请参考以下文章

FTP云盘程序

模拟百度云盘版的ftp

常用的FTP软件及其优缺点,如何轻松搭建安全稳定的NAS私有云盘?

常用的FTP软件及其优缺点,如何轻松搭建安全稳定的NAS私有云盘?

java Ftp上传创建多层文件的代码片段

Linux定时备份数据到百度云盘