Linux——FTP云盘

FTP云盘整体功能

在这里插入图片描述

先认识一些API

popen应用于执行shell命令,并读取此命令的执行结果
FILE *popen(const char *command, const char *type);

popen()的返回值是个标准I/O流,必须由pclose来终止
int pclose(FILE *stream);


在这里主要做清空内存使用
void *memset(void *s, int c, size_t n); 
s指向要填充的内存块。
c是要被设置的值。
n是要被设置该值的字符数。
返回类型是一个指向存储区s的指针。
比较字符串s1和s2
int strcmp(const char *s1,const char *s2);
自左向右逐个按照ASCII码值进行比较,直到出现不同的字符或遇’\0’为止。
如果返回值 < 0,则表示 s1 小于 s2。
如果返回值 > 0,则表示 s1 大于 s2。
如果返回值 = 0,则表示 s1 等于 s2

char *strstr(const char *str1, const char *str2)
查找第一次出现字符串 s2 的位置,未找到返回NULL

char *strtok(char *str, const char *delim)
str—要被分解的字符串
delim—用作分隔符的字符(可以是一个,也可以是集合)
第二次要把str设置为NULL

char *strcpy(char *dest, const char *src) 把 src 所指向的字符串复制到 dest
需要注意的是如果目标数组 dest 不够大,而源字符串的长度又太长,可能会造成缓冲溢出的情况。

int system(const char * command)
执行 dos(windows系统)shell(Linux/Unix系统) 命令,执行结果显示在终端```
#include<unistd.h>
int access(const char* pathname, int mode);
pathname 是文件的路径名+文件名
mode:指定access的作用,取值如下:
	F_OK 值为0,判断文件是否存在
	X_OK 值为1,判断对文件是可执行权限
	W_OK 值为2,判断对文件是否有写权限
	R_OK 值为4,判断对文件是否有读权限
 注:后三种可以使用或“|”的方式,一起使用,如W_OK|R_OK

源码

分为三个文件:server.c 、client.c、config.h
server端一直在accept,等待客户端连接,有客户端接入就创建子进程对接处理指令

config.h

/*配置*/

 #define LS		0   //显示服务端的文件
 #define PWD	1	//显示服务端路径
 #define CD		2	//切换服务端路径
 #define GET 	3	//获取服务端文件
 #define PUT	4	//上传客户端文件到服务端
 
 #define LLS	5	//显示客户端文件
 #define LCD	6	//切换客户端路径
 
 #define QUIT	7   //退出客户端
 
 #define CLC	8	//客户端清屏
struct Msg {
	char data[1024]; //存放指令
	char buffer[1024*4]; //存放数据
};

server.c

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
//#include <linux/in.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "config.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
/*struct sockaddr_in
{
    u_short sin_family;// 地址族
    u_short sin_port;// 端口
    struct in_addr sin_addr;// IPV4 地址
    char sin_zero[8];
};*/



int Cmd_transition(char *cmd)
{
	/* strcmp(s1,s1)比较 s1 和 s2 
    若s1=s2,返回0*/

    /*strstr(s1,s1)在字符串 s1 中
    查找第一次出现字符串 s2 的位置,未找到返回NULL*/
	
	if(strcmp(cmd,"ls") == 0){
		return LS;
	}
	if(strcmp(cmd,"pwd") == 0){
		return PWD;
	}
	if(strcmp(cmd,"lls") == 0){
		return LLS;
	}

	if(strcmp(cmd,"quit") == 0){
		return QUIT;
	}
	if(strstr(cmd,"lcd") != NULL){		
		return LCD;
	}
	if(strstr(cmd,"cd") != NULL){		
		return CD;
	}
	if(strstr(cmd,"get") != NULL){
		return GET;
	}
	if(strstr(cmd,"put") != NULL){
		return PUT;
	}else {
		return -1;
	}
	
	
}


char *Cmd_division(char *cmd)
{
	char *p = NULL;
		strtok(cmd," ");
	p = strtok(NULL," ");
	
	return p;
}

int Cmd_dispose(struct Msg msg,int c_fd)
{
	int Cmd_int;
	int File_fd;
	char *File_name;
	FILE *p;
	/* 1.获取命令msg.data,并将数据转换为int整数类型*/
	Cmd_int = Cmd_transition(msg.data);
	printf("server Cmd_int:%d\n",Cmd_int);
	 /* 2.调用switch处理命令*/
	 switch(Cmd_int){
		 case LS:
		 case PWD:
			p = popen(msg.data,"r");   //使用popen调用命令,将输出的结果存放到p中
			fread(msg.buffer,sizeof(msg.buffer),1,p); //再使用fread,读取p中的内容
			write(c_fd,&msg,sizeof(msg));
			pclose(p);
			//printf("server return \n");
			break;
		case CD:
			File_name = Cmd_division(msg.data);
			printf("File_name:%s\n",File_name);
			if(chdir(File_name) == -1){
				perror("chdir");	
				printf("chdir eror\n");
			}		
			break;
		case GET:
			File_name = Cmd_division(msg.data);
			if(access(File_name,F_OK) == -1){
				printf("file does not exist ");
				strcpy(msg.buffer,"file does not exist\n");
				write(c_fd,&msg,sizeof(msg));
			}else {
				File_fd = open(File_name,O_RDWR);
				read(File_fd,&msg.buffer,sizeof(msg.buffer));
				write(c_fd,&msg,sizeof(msg));
			}
				
			break;	
		case PUT:
				File_name = Cmd_division(msg.data);
				//printf("File_name:%s\n",File_name);
				if(access(File_name,F_OK) != -1){
				strcpy(msg.buffer,"The file already exists\n");
				write(c_fd,&msg,sizeof(msg));
				}else {
				File_fd = open(File_name,O_RDWR|O_CREAT,0666);
				
				if(File_fd == -1&&errno != EEXIST ){
					printf("open %s error\n",File_name);
				}
				write(File_fd,&msg.buffer,sizeof(msg.buffer));
				close(File_fd);
				strcpy(msg.buffer,"put file succeed\n");
				write(c_fd,&msg,sizeof(msg));
				}
			break;
			
	 }
	
}


int main()
{
	int s_fd;
	int c_fd;
	struct sockaddr_in s_addr;	
	struct sockaddr_in c_addr;


	memset(&s_addr,0,sizeof(struct sockaddr_in));
	memset(&c_addr,0,sizeof(struct sockaddr_in));

	s_addr.sin_family = AF_INET;
	s_addr.sin_port = htons(8888);
	inet_aton("192.168.20.131",&s_addr.sin_addr);

	s_fd = socket(AF_INET,SOCK_STREAM,0);
	if(s_fd == -1){
		printf("socket error\n");
		exit(-1);
	}
	
	bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
	
	listen(s_fd,5);

	int c_len = sizeof(struct sockaddr_in);

while(1){
	c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&c_len);
	if(c_fd == -1){
		perror("accept:");
		exit(-1);
	}
	
	printf("client ip :%s\n",inet_ntoa(c_addr.sin_addr));
	
	
	struct Msg msg;
	int n_read;
	if(fork() == 0)
		while(1){
			memset(&msg,0,sizeof(msg));
			n_read = read(c_fd,&msg,sizeof(msg));
			//printf("get %s cmd\n",msg.data);
		
			if(strcmp(msg.data,"quit") == 0){
				printf("client exit\n");
				exit(0);
			}
			if(n_read == 0){
				printf("client abnormal  exit\n");
				exit(-1);
			}
			
			if(n_read > 0){
				Cmd_dispose(msg,c_fd);
				
			}
			
			
		}
	
	
}
	

	
	return 0;
}


client.c

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


/*struct sockaddr_in
  {
  u_short sin_family;// 地址族
  u_short sin_port;// 端口
  struct in_addr sin_addr;// IPV4 地址
  char sin_zero[8];
  };*/


int Cmd_transition(char *cmd)
{
	/* strcmp(s1,s1)比较 s1 和 s2 
    若s1=s2,返回0*/

    /*strstr(s1,s1)在字符串 s1 中
    查找第一次出现字符串 s2 的位置,未找到返回NULL*/
	
	if(strcmp(cmd,"ls") == 0){
		return LS;
	}
	if(strcmp(cmd,"pwd") == 0){
		return PWD;
	}
	if(strcmp(cmd,"lls") == 0){
		return LLS;
	}

	if(strcmp(cmd,"quit") == 0){
		return QUIT;
	}
	if(strcmp(cmd,"clc") == 0){
		return CLC;
	}
	if(strstr(cmd,"lcd") != NULL){		
		return LCD;
	}
	if(strstr(cmd,"cd") != NULL){		
		return CD;
	}
	if(strstr(cmd,"get") != NULL){
		return GET;
	}
	if(strstr(cmd,"put") != NULL){
		return PUT;
	}else {
		return -1;
	}
	
	
}



char *Cmd_division(char *cmd)
{
	char *p = NULL;
		strtok(cmd," ");
	p = strtok(NULL," ");
	
	return p;
}


int Cmd_dispose(struct Msg msg,int c_fd)
{
		char *File_name = NULL;
		char *TEMP;
		TEMP = malloc(40);
		int File_fd;
		int Cmd_int;
		/* 1.将字符串指令,转换为int整数类型*/
		Cmd_int = Cmd_transition(msg.data);
		//printf("Cmd_int:%d\n",Cmd_int);
		/* 2.调用switch处理ret*/
	switch(Cmd_int){
			case LS:
			case PWD:
			case CD:
				write(c_fd,&msg,sizeof(msg));
				break;
			case LLS:
			printf("=======================================================");	
			
				system("ls");
				
			printf("=======================================================");	
				break;
			case LCD:
				File_name = Cmd_division(msg.data);
				//printf("File_name:%s\n",File_name);
				if(access(File_name,F_OK) == -1){
						printf("file does not exist ");
				}else {
					printf("=======================================================");	
					chdir(File_name);		
					system("pwd");
					printf("=======================================================");	
				}
				break;
			case GET:
				write(c_fd,&msg,sizeof(msg));
				break;
			case PUT:		
				TEMP = strdup(msg.data);  //拷贝字符串,不要改变msg.data
				printf("==== %s\n",msg.data);
				File_name = Cmd_division(TEMP);
				if(access(File_name,F_OK) == -1){
				printf("file does not exist ");
				return 100;
			}else {
				
				File_fd = open(File_name,O_RDWR);
				read(File_fd,&msg.buffer,sizeof(msg.buffer));
				close(File_fd);
				write(c_fd,&msg,sizeof(msg));
				//printf("client send cmd:%s\n",msg.data);
				//printf("client send TEMP:%s\n",TEMP);
				
		} 
		
		break;
			case QUIT:
				write(c_fd,&msg,sizeof(msg));
				exit(0);
				break;	
		case CLC:
			system("clear");
			break;				
	}	
		
	return Cmd_int;
}
/*
int access(const char *pathname, int mode);    
参数: 
pathname: 需要测试的文件路径名。   
mode: 需要测试的操作模式,可能值是一个或多个R_OK(可读?), W_OK(可写?),
 X_OK(可执行?) 或 F_OK(文件存在?)组合体
成功执行时,返回0。失败返回-1
*/

int Server_Process_output(struct Msg msg,int c_fd,int cmd_ret,char *File_name)
{
	int File_fd;
		
	memset(&msg.buffer,0,sizeof(msg.buffer));
	printf("client reading......\n");
	read(c_fd,&msg,sizeof(msg));
	if(cmd_ret == GET){
		File_fd = open(File_name,O_RDWR|O_CREAT);
		write(File_fd,&msg.buffer,sizeof(msg.buffer));
		close(File_fd);
			
	}else {
	printf("=======================================================");	
	printf("\nOutput:%s\n",msg.buffer);
	printf("=======================================================");	
	}
}



int main(int argc,char **argv)
{
	int con;
	int c_fd;
	if(argc != 3){
		printf("Input param error!!\n");
		exit(-1);
	}
	struct sockaddr_in c_addr;

	c_addr.sin_family = AF_INET;
	c_addr.sin_port =htons(atoi(argv[2]));
	inet_aton(argv[1],&c_addr.sin_addr);
	
	c_fd = socket(AF_INET,SOCK_STREAM,0);
	if(c_fd == -1){
		printf("socket error\n");
		exit(-1);
	}
	
	
	

	
		con = connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr_in));
		if(con == -1){
			perror("connect");
			exit(-1);
	}
	

	struct Msg msg;
	char *File_name;
	int cmd_ret;
	
	while(1){
		printf("\nInut cmd:");
		memset(&msg.data,0,sizeof(msg.data));
		//fgets(msg.data,20,stdin);
		gets(msg.data); // gets不会去检查字符串的长度,如果字符串过长就会导致溢出。如果溢出的字符覆盖了其他一些重要数据就会导致不可预测的后果。
		
	//	printf("client Input:%s\n",msg.data);
		
		cmd_ret = Cmd_dispose(msg,c_fd);
		if(cmd_ret == -1||cmd_ret == 100){
			continue;
		}
		
		
		if(cmd_ret != CD&&cmd_ret != LCD&&cmd_ret != LLS&&cmd_ret !=CLC){  //此处判断是因为防止server执行完cd后没有内容返回,导致read阻塞
		if(cmd_ret == GET){
			File_name = Cmd_division(msg.data);
			//printf("get %s sucess\n",File_name);
			//printf("client File_name:%s\n",File_name);
		}
		Server_Process_output(msg,c_fd,cmd_ret,File_name);
		}	
	}
			
		
	
			
			
			
			
			
	
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值