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


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

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

    客户端支持的指令:
    远程控制

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

    本地控制:

        1、查看本地客户端文件 :lls
        2、查看进入客户端文件夹 :lcd 
    
    • 1
    • 2

    二、步骤:

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

        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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    客户端:发指令

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

    三、代码实现

    客户端client代码

    #include 
    #include 
    #include 
    //#include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193

    服务器代码server

    #include 
    #include 
    #include 
    //#include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170

    定义

    //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];
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
  • 相关阅读:
    代码随想录算法训练营第1天 | 704.二分查找、27.去除元素
    21 C++设计模式之访问者(Visitor)模式
    激活函数简述
    Nvidia驱动卸载干净了,新驱动却还是安装不上?
    Liunx Jenkins 部署vue项目
    WebSocket首次使用踩坑记录
    BOA服务器和CGI程序移植中遇到的问题及解决方案
    【数据结构】带头双向链表的简单实现
    Greek Alphabet Letters & Symbols
    Flask 实战笔记3 - SQLAlchemy实现mysql编码、列类型
  • 原文地址:https://blog.csdn.net/weixin_48208102/article/details/133550612