Linux--FTP服务器功能--项目

一个子进程负责一条连接通道

一、项目要求:实现以下内容

客户端支持的指令:

远程控制:

复制代码
    1、获取服务器当前路径的文件:get  xxx
    2、 展示服务器有哪些文件:ls
    3、进入服务器某文件夹 :cd  xxx
    4、上传文件到服务器: put xxx

本地控制:

复制代码
    1、查看本地客户端文件 :lls
    2、查看进入客户端文件夹 :lcd 

二、步骤:

服务器:解析指令(创建子进程、对接客户端)

复制代码
    1、创建套接字socket
    2、绑定bind ip+端口号
    3、listen监听
    while(1)调用accept
    4、accept接受客户端请求,返回值小于0报错
            ①、有客户端接入调用fork创建子进程,返回值小于 0 报错;等于 0 对客户端进行交互。
            ②、对(buf)读取出来的数据做判断(ls、get、cd、pwd)
                    ①)get:open打开文件,read文件,send文件到客户端
                    ②)ls:popen文件,fread读取文件,send发送文件到客户端
// system()调用副服务器:
在子进程中:
	1、接收指令
	2、把指令写入共享内存 + get pid
	3、读取结果共享内存
	4、读到的结果返回客户端
在副服务器中:
	1、读取共享内存(指令共享内存)
	2、发现两次指令不一样,执行结果存入结果共享内存

客户端:发指令

复制代码
    1、socket创建套接字
    2、connect连接服务器
    3、连接上以后获取用户的输入,对输入的信息进行处理

三、代码实现

客户端client代码

c 复制代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
//#include <linux/in.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <config.h>
#include <sys/stat.h>
#include <fcntl.h>


char * getdir(char *cmd)
{
	char *p;
	
	p = strtok(cmsg," ");//分割字符串,用空格分隔
	p = strtok(NULL," ");
	return p; 
}

int get_cmd_type(char *cmd)
{
	if(strstr(cmd,"lcd")!=NULL)		return LCD;
	if(!strcmp("lls",cmd))			return LLS;
	
	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 -1;
}

int cmd_handler(struct Msg msg,int fd)
{
	char *dir = NULL;
	char buf[32];
	int ret;
	int filefd;
	
	ret = get_cmd_type(msg.data);
	
	switch(ret){
		case LS:
		case CD:
		case PWD:
			msg.type = 0;
			write(fd,&msg,sizeof(msg));
			
			break;
		case GET:
			msg.type = 2;
			write(fd,&msg,sizeof(msg));
			
			break;
		case PUT:
			strcpy(buf,msg.data);
			dir = getdir(buf);
			
			if(access(dir,F_OK == -1)){
				printf("%s No exsit !",dir);
			}else{
				fdfile = open(dir,O_RDWR);
				read(filefd,msg.secondBuf,sizeof(msg.secondBuf));
				close(filefd);
				
				write(fd,&msg,sizeof(msg));
			}
			
			break;
		case LLS:
			system("ls");
			
			break;
		case LCD:
			dir = getdir(msg.data);
			chdir(dir);
			
			break;
		case QUIT:
			strcpy(msg.data,"quit");
			write(fd,&msg,sizeof(msg));
			close(fd);
			exit(-1);
	}
	return ret;
}

void handler_server_message(int c_fd,struct Msg msg)
{
	int n_read;
	struct Msg msg;
	int newfilefd;
	
	n_read = read(c_fd,&msgget,sizeof(msgget));
	
	if(n_read == 0){
		printf("server is out,quit \n");
		exit(-1);
	}else if(msgget.type == DOFILE){
		char *p = getdir(msg.data);
		newfilefd = open(p,O_RDWR|O_CREAT,0666);
		write(newfilefd,msgget,strlen(msgget));
		putchar(">");
		fflush(stdout);
	}else{
		printf("......................\n");
		printf("\n %s \n",msgget.data);
		printf("......................\n");
		
		putchar(">");
		fflush(stdout);
	}
}

int main(int argc,char **argv)
{
	int c_fd;
	
	//定义结构体
	struct sockaddr_in c_addr;
	struct Msg msg;
	
	//数据清空

	memset(&c_addr,0,sizeof(struct sockaddr_in));
	
	if(argc != 3){
		printf("param is not good");	//参数不好
		exit(-1);
	}

//1、创建套接字 socket
	c_fd = socket(AF_INET,SOCK_STREAM,0);//用到IPV4,TCP协议,0自动配合起来
	if(c_fd == -1){						//返回-1,错误
		perror("socket");
		exit(-1);
	}
	
	c_addr.sin_family = AF_INET;	//协议族
	c_addr.sin_port = htons(atoi(argv[2]));	//端口号,一般为5000--9000
	//电脑为x86是小端字节序,网络字节序为大端字节序。所以要进行转换用htons
	inet_aton(argv[1],&c_addr.sin_addr);
	//把字符串形式的127.0.0.1转换成网络能识别的格式。用 到inet_aton


//2、connect 连接客户端的listen

	if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr)) == -1){
		perror("connect");
		exit(-1);
	}
	printf("connect ....\n");
	//printf("get connect : %s\n",inet_ntoa(c_addr.sin_addr));//把网络格式的IP转换为字符格式

	int mark = 0;
	while(1){
		
		memset(msg.data,0,sizeof(msg.data));//初始化
		if(mark == 0)	printf(">");
			
		gets(msg.data);
		
		if(strlen(msg.data) == 0){
			if(mark == 1){
				printf(">");
			}
			continue;
		}
		
		mark = 1;
		
		int ret = cmd_handler(msg,c_fd);
		
		if(ret > IFGO){
			putchar(">");
			fflush(stdout);
			continue;
		}
		if(ret == -1){
			printf("command not \n");
			printf(">");
			fflush(stdout);
			continue;
		}
		handler_server_message(c_fd,msg);
	}
	return 0;
}

服务器代码server

c 复制代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
//#include <linux/in.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <config.h>
#include <sys/stat.h>
#include <fcntl.h>


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 *cmsg)
{
	char *p;
	p = strtok(cmsg," ");//分割字符串,用空格分隔
	p = strtok(NULL," ");
	return p;
}

void msg_handler(struct Msg msg,int fd)
{
	char dataBuf[1024] = {0};
	char *file = NULL;
	int fdfile;
	
	//解析指令,把指令转换成想要的整型数
	
	printf("cmd : %s\n",msg.data);
	int ret = get_cmd_type(msg.data);
	
	switch(ret){
		case LS:
		case PWD:
			msg.type = 0;
			FILE *r = popen(msg.data,"r");
			fread(msg.data,sizeof(msg.data),1,r);
			write(fd,&msg,sizeof(msg));
			
			break;
		case CD:
			msg.type = 0;
			char *dir = getDesDir(msg.data);//分割字符串
			printf("dir : %s\n",dir);
			chdir(dir);
			
			break;
		case GET:
			file = getDesDir(msg.data);
			
			if(access(file,F_OK == -1)){
				strcpy(msg.data,"No this file !");
				write(fd,&msg,sizeof(msg));
			}else{
				msg.type = DOFILE;
				
				fdfile = open(file,O_RDWR);
				read(fdfile,dataBuf,sizeof(dataBuf));
				close(fdfile);
				
				strcpy(msg.data,dataBuf);
				write(fd,&msg,sizeof(msg));
			}
			
			break;
		case PUT:
			fdfile = open(getDesDir(msg.data),O_RDWR|O_CREAT,0666);
			write(fdfile,msg.secondBuf,strlen(msg.secondBuf));//buf放内容,msg.data放指令
			close(fdfile);
			
			break;
		case QUIT:
			printf("client quit ! \n");
			exit(-1);
	}
}


int main(int argc,char **argv)//配置端口
{
	int s_fd;
	int c_fd;
	int n_read;
	char redBuf[128];
	
	struct sockaddr_in s_addr;		//定义结构体
	struct sockaddr_in c_addr;
	struct Msg msg;
	
	if(argc != 3){
		printf("param is not good\n");	//参数不好
		exit(-1);
	}
	
	
	//数据清空
	memset(&s_addr,0,sizeof(struct sockaddr_in));
	memset(&c_addr,0,sizeof(struct sockaddr_in));
	

//1、创建套接字 socket
	s_fd = socket(AF_INET,SOCK_STREAM,0);//用到IPV4,TCP协议,0自动配合起来
	if(s_fd == -1){						//返回-1,错误
		perror("socket");
		exit(-1);
	}
	
	
//2、添加地址 bind		
	
	s_addr.sin_family = AF_INET;	//协议族
	s_addr.sin_port = htons(atoi(argv[2]));	//端口号,一般为5000--9000
	//电脑为x86是小端字节序,网络字节序为大端字节序。所以要进行转换用htons
	inet_aton(argv[1],&s_addr.sin_addr);
	//把字符串形式的127.0.0.1转换成网络能识别的格式。用到inet_aton


	bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct socket_in));
	

//3、监听listen
	listen(s_fd,10);//监听10个
	
//4、连接 accept
	int clen = sizeof(struct socket_in);
	while(1){

		c_fd = accept(s_fd,(struct sockaddr *)&c_addr ,&clen);
		//连接到客户端之后,后续的操作用返回值c_fd来操作
	
		if(c_fd == -1){
			perror("accept");
		}

		printf("get connect : %s\n",inet_ntoa(c_addr.sin_addr));//把网络格式的IP转换为字符格式
	//新的客户端接入,创建子进程,一个子进程负责一条连接通道
		if(fork() == 0){		//fock返回值=0进入子进程,>0进入父进程
			
			while(1){		
				memset(retmessage,0,sizeof(retmessage));//初始化
//5、read
			n_read = read(c_fd,&msg,sizeof(msg));
			if(n_read == 0){
				printf("client out !\n");
				break;
			}else if(n_read > 0){
				msg_handler(msg,c_fd);
			}
//6、write
			}
			
		}
	}
	close(c_fd);
	close(s_fd);
	return 0;
}

定义

c 复制代码
//msg结构体

#define LS		0
#define GET		1
#define PWD		2

#define IFGO	3

#define LCD		4
#define LLS		5
#define CD		6
#define PUT		7

#define QUIT	8
#define DOFILE	9

struct Msg
{
	int type;
	char data[1024];
	char secondBuf[128];
};
相关推荐
张居斜2 小时前
GitHub Actions + 阿里云 OSS:OIDC 免密同步构建产物
github·oss·llm-wiki
用户3228360084475 小时前
python-rapidjson:用 C++ 速度处理 JSON 的 Python 库
github
逛逛GitHub5 小时前
4 个比较实用的 GitHub 开源项目,浅浅的收藏一波。
github
大树885 小时前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠5 小时前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
Hommy885 小时前
【剪映小助手】添加贴纸接口(Add Sticker)
后端·github·剪映小助手·视频剪辑自动化·剪映api
bush45 小时前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行5206 小时前
Linux 11 动态监控指令top
linux
小宇宙Zz6 小时前
Maven依赖冲突
java·服务器·maven
不会C语言的男孩7 小时前
Linux 系统编程 · 第 8 章:进程基础
linux·c语言