首页 > 系统相关 >Linux网盘,编程者的选择,让技术为数据服务,创造无限价值!“#Linux系统编程《网盘项目》

Linux网盘,编程者的选择,让技术为数据服务,创造无限价值!“#Linux系统编程《网盘项目》

时间:2024-09-09 20:20:39浏览次数:3  
标签:cmd return puts int 网盘 编程 fd Linux msg

"Linux网盘,编程者的选择,让技术为数据服务,创造无限价值!"#Linux系统编程《网盘项目》

前言

  “本篇博文深入探讨了Linux系统编程中的《网盘项目》,详尽解析了项目的核心功能、构建了程序的基本框架、逐一剖析了程序代码的关键点,并展示了程序的实际运行结果。若您对此项目感兴趣,不妨先点赞支持,再细细品读,相信您会从中收获满满!”

预备知识

  一、Linux文件编程。
  二、Linux进程编程。
  三、Linux进程间通信编程。
  四、Linux网络编程。

  如果以上知识不清楚,请自行学习后再来浏览,也可以看我我写的博文。如果我有没例出的,请在评论区写一下。谢谢啦!

一、 项目功能

  如下图
请添加图片描述

二、 程序基本框架

2.1 服务器程序流图

  如下图
请添加图片描述

2.2 客户端程序流图

  如下图
请添加图片描述

三、 程序代码解析

3.1 服务器代码解析

3.1.1 主函数代码解析
int main(int argc, char **argv)
{
	int s_fd;																定义网络描述符
	int a_fd;																定义连接服务器描述符
	pid_t pid;																定义进程描述符
	struct sockaddr_in s_addr;												定义配置网络信息结构体												
	struct sockaddr_in c_addr;												定义输出客户端网络信息结构体
	struct Buffer msg;														定义网络传输数据结构体包含在"public.h"库中
	int c_len;																定义输出客户端网络信息的长度
	int mark = 0;															定义客户端连接的数量
	int n_read = 0;															定义从客户端读取到的数据量
	//1.socket
	s_fd = socket(AF_INET,SOCK_STREAM,0);									建立socket套接字IPV4 TCP 
	if(s_fd == -1)															判断是否成功创建套接字
	{
		puts("Socket creat fail");
		exit(-1);
	}
	s_addr.sin_family = AF_INET;											配置网络为IPV4的绑定信息
	s_addr.sin_port   = htons(atoi(argv[2]));								配置网络绑定的端口号为输入参数三
	inet_aton(argv[1],&s_addr.sin_addr);									配置网络绑定的IP地址为输入的参数二
	//2.bind
	//int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
	bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));		绑定刚才配置的网络信息
	//3.listen
	listen(s_fd,10);														设置服务器为监听状态,设置监听排队数量最大值10
	c_len = sizeof(struct sockaddr_in);										计算输出客户端的信息大小	
	while(1)
	{
		//4.accept
		a_fd = accept(s_fd,(struct sockaddr *)&c_addr,&c_len);				等待客户端连接,连接成功返回连接服务器描述符
		if(a_fd == -1)														判断客户端是否成功连接 
		{
			puts("Connect fail");
			perror("Why");
			exit(-1);
		}
		mark++;																每当有一个客户端连接就加一
		pid = getpid();														获取父进程描述符
		if(fork()==0)														创建子进程并进入子进程
		{
			puts("---------------------------------------------------------------------");优化输出
			printf("Connect %d usr\n",mark);								输出连接服务器的客户端的数量
			while(1)																
			{
				n_read = read(a_fd,&msg,sizeof(msg));						接收客户端传输的信息
				if(n_read == 0)												判断客户端是否有信息发送过来
				{
					printf("client out\n");
					break;
				}
				else if(n_read > 0)											有信息发送过来
				{	
					puts("---------------------------------------------------------------------");优化输出   
					printf("get msg num %d\n",n_read);						输出发送过来的数据量
					msg_handler(msg,a_fd,pid);								解析客户端发送信息,将网络连接描述符,传输数据结构体,父进程的进程描述传给信息处理函数
					puts("---------------------------------------------------------------------");优化输出   
				}
			}
		}
	}
	
	close(s_fd);															关闭socket套接字
	close(a_fd);															关闭网络连接

	return 0;
}
3.1.2 信息处理函数代码解析
void msg_handler(struct Buffer msg, int ah_fd, pid_t pid)			信息处理函数
{
	FILE *r = NULL;													定义数据流指针
	char *dir;														定义cd路径变量
	char *file;														定义文件名变量
	char fileBuf[1024];												定义文件内容变量
	int fd;															定义文件描述符
	
	printf("CMD: %s\n",msg.cmd);									输出客户端发送的指令
	int ret = get_cmd(msg.cmd);										解析客户端发送的指令,输出命令宏
	printf("ret = %d\n",ret);										输出解析到的宏结果
	switch(ret)
	{
		case LS:													当命令为ls,pwd时执行以下语句
		case PWD:
			puts("---------------------------------------------------------------------");输出优化   
			puts("in pwd&ls");										提示进入ls,pwd模式
			msg.mark = 0;											将信息结构体中的mark置零
			r = popen(msg.cmd,"r");									利用popen函数执行指令,并将执行指令的结果传输给r
			fread(msg.data,sizeof(msg.data),1,r);					采用fread函数将r中的输出结果读取到msg的data中
			write(ah_fd,&msg,sizeof(msg));							将输出结果返回给客户端
			
			break;
		case CD:													当命令为cd时执行以下语句
			puts("---------------------------------------------------------------------");输出优化   
			puts("in cd");											提示进入cd模式
			msg.mark = 0;											将信息结构体中的mark置零
			dir = getDir(msg.cmd);									解析cd命令的路径存于dir中
			printf("dir: %s\n",dir);								输出路径
			chdir(dir);												采用chdir改变当前工作路径
			break;	
		case GET:													当命令为get时执行以下语句
			puts("---------------------------------------------------------------------");输出优化   
			puts("in get");											提示进入get模式
			file = getDir(msg.cmd);									解析文件名
			printf("file: %s\n",file);								输出文件名
			fd = open(file,O_RDWR);									当开相应文件
			read(fd,fileBuf,1024);									读取文件数据,存于fileBuf中
			strcpy(msg.filedata,fileBuf);							将fileBuf中的文件数据拷贝进msg.filedata中
			strcpy(msg.data,file);									将文件名拷贝到msg.data中
			msg.mark = 1;											将信息结构体中的mark置一
			write(ah_fd,&msg,sizeof(struct Buffer));				将打包好的信息传回客户端
			
			break;
		case PUT:													当命令为put时执行以下语句
			puts("---------------------------------------------------------------------");优化输出   
			puts("int put");										提示进入put模式
			file = getDir(msg.cmd);									解析文件名
			printf("file: %s\n",file);								输出文件名
			fd = open(file,O_RDWR|O_CREAT,0600);					打开并创建文件
			write(fd,msg.filedata,strlen(msg.filedata));			向文件中写入客户端发送的文件内容
			close(fd);												关闭文件
			break;		
		case QUIT:													当命令为quit时执行以下语句
			puts("---------------------------------------------------------------------");优化输出   
			puts("quit!!!");										提示进入quit模式
			kill(pid,9);											终止父进程
			kill(getpid(),9);										终止子进程
			//exit(-1);
			break;				
	}
}
3.1.3 获取命令函数代码解析
int get_cmd(char *cmd)												获取命令函数
{		
	if(!strcmp(cmd,"ls"))	return LS;								获取到命令ls返回LS宏						
	if(!strcmp(cmd,"pwd"))	return PWD;								获取到命令pwd返回PWD宏
	if(!strcmp(cmd,"quit"))	return QUIT;							获取到命令quit返回QUIT宏
	if(strstr(cmd,"cd") != NULL)	return CD;						获取到命令cd返回CD宏
    if(strstr(cmd,"get") != NULL)	return GET;						获取到命令get返回GET宏
    if(strstr(cmd,"input") != NULL)	return PUT;						获取到命令put返回PUT宏
		
	return 0;														其他情况下返回0
}
3.1.4 cd路径,文件名解析函数代码解析
char *getDir(char *smdr)											cd路径,文件名解析函数
{
	char *p = NULL;
	
	p = strtok(smdr," ");											采用strtok函数分割字符串即可
	p = strtok(NULL," ");
	
	return p;
}
3.1.5 服务器完整代码解析
#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "public.h"
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>



int get_cmd(char *cmd)												获取命令函数
{		
	if(!strcmp(cmd,"ls"))	return LS;								获取到命令ls返回LS宏						
	if(!strcmp(cmd,"pwd"))	return PWD;								获取到命令pwd返回PWD宏
	if(!strcmp(cmd,"quit"))	return QUIT;							获取到命令quit返回QUIT宏
	if(strstr(cmd,"cd") != NULL)	return CD;						获取到命令cd返回CD宏
    if(strstr(cmd,"get") != NULL)	return GET;						获取到命令get返回GET宏
    if(strstr(cmd,"input") != NULL)	return PUT;						获取到命令put返回PUT宏
		
	return 0;														其他情况下返回0
}

char *getDir(char *smdr)											cd路径,文件名解析函数
{
	char *p = NULL;
	
	p = strtok(smdr," ");											采用strtok函数分割字符串即可
	p = strtok(NULL," ");
	
	return p;
}

void msg_handler(struct Buffer msg, int ah_fd, pid_t pid)			信息处理函数
{
	FILE *r = NULL;													定义数据流指针
	char *dir;														定义cd路径变量
	char *file;														定义文件名变量
	char fileBuf[1024];												定义文件内容变量
	int fd;															定义文件描述符
	
	printf("CMD: %s\n",msg.cmd);									输出客户端发送的指令
	int ret = get_cmd(msg.cmd);										解析客户端发送的指令,输出命令宏
	printf("ret = %d\n",ret);										输出解析到的宏结果
	switch(ret)
	{
		case LS:													当命令为ls,pwd时执行以下语句
		case PWD:
			puts("---------------------------------------------------------------------");输出优化   
			puts("in pwd&ls");										提示进入ls,pwd模式
			msg.mark = 0;											将信息结构体中的mark置零
			r = popen(msg.cmd,"r");									利用popen函数执行指令,并将执行指令的结果传输给r
			fread(msg.data,sizeof(msg.data),1,r);					采用fread函数将r中的输出结果读取到msg的data中
			write(ah_fd,&msg,sizeof(msg));							将输出结果返回给客户端
			
			break;
		case CD:													当命令为cd时执行以下语句
			puts("---------------------------------------------------------------------");输出优化   
			puts("in cd");											提示进入cd模式
			msg.mark = 0;											将信息结构体中的mark置零
			dir = getDir(msg.cmd);									解析cd命令的路径存于dir中
			printf("dir: %s\n",dir);								输出路径
			chdir(dir);												采用chdir改变当前工作路径
			break;	
		case GET:													当命令为get时执行以下语句
			puts("---------------------------------------------------------------------");输出优化   
			puts("in get");											提示进入get模式
			file = getDir(msg.cmd);									解析文件名
			printf("file: %s\n",file);								输出文件名
			fd = open(file,O_RDWR);									当开相应文件
			read(fd,fileBuf,1024);									读取文件数据,存于fileBuf中
			strcpy(msg.filedata,fileBuf);							将fileBuf中的文件数据拷贝进msg.filedata中
			strcpy(msg.data,file);									将文件名拷贝到msg.data中
			msg.mark = 1;											将信息结构体中的mark置一
			write(ah_fd,&msg,sizeof(struct Buffer));				将打包好的信息传回客户端
			
			break;
		case PUT:													当命令为put时执行以下语句
			puts("---------------------------------------------------------------------");优化输出   
			puts("int put");										提示进入put模式
			file = getDir(msg.cmd);									解析文件名
			printf("file: %s\n",file);								输出文件名
			fd = open(file,O_RDWR|O_CREAT,0600);					打开并创建文件
			write(fd,msg.filedata,strlen(msg.filedata));			向文件中写入客户端发送的文件内容
			close(fd);												关闭文件
			break;		
		case QUIT:													当命令为quit时执行以下语句
			puts("---------------------------------------------------------------------");优化输出   
			puts("quit!!!");										提示进入quit模式
			kill(pid,9);											终止父进程
			kill(getpid(),9);										终止子进程
			//exit(-1);
			break;				
	}
}

int main(int argc, char **argv)
{
	int s_fd;																定义网络描述符
	int a_fd;																定义连接服务器描述符
	pid_t pid;																定义进程描述符
	struct sockaddr_in s_addr;												定义配置网络信息结构体												
	struct sockaddr_in c_addr;												定义输出客户端网络信息结构体
	struct Buffer msg;														定义网络传输数据结构体包含在"public.h"库中
	int c_len;																定义输出客户端网络信息的长度
	int mark = 0;															定义客户端连接的数量
	int n_read = 0;															定义从客户端读取到的数据量
	//1.socket
	s_fd = socket(AF_INET,SOCK_STREAM,0);									建立socket套接字IPV4 TCP 
	if(s_fd == -1)															判断是否成功创建套接字
	{
		puts("Socket creat fail");
		exit(-1);
	}
	s_addr.sin_family = AF_INET;											配置网络为IPV4的绑定信息
	s_addr.sin_port   = htons(atoi(argv[2]));								配置网络绑定的端口号为输入参数三
	inet_aton(argv[1],&s_addr.sin_addr);									配置网络绑定的IP地址为输入的参数二
	//2.bind
	//int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
	bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));		绑定刚才配置的网络信息
	//3.listen
	listen(s_fd,10);														设置服务器为监听状态,设置监听排队数量最大值10
	c_len = sizeof(struct sockaddr_in);										计算输出客户端的信息大小	
	while(1)
	{
		//4.accept
		a_fd = accept(s_fd,(struct sockaddr *)&c_addr,&c_len);				等待客户端连接,连接成功返回连接服务器描述符
		if(a_fd == -1)														判断客户端是否成功连接 
		{
			puts("Connect fail");
			perror("Why");
			exit(-1);
		}
		mark++;																每当有一个客户端连接就加一
		pid = getpid();														获取父进程描述符
		if(fork()==0)														创建子进程并进入子进程
		{
			puts("---------------------------------------------------------------------");优化输出
			printf("Connect %d usr\n",mark);								输出连接服务器的客户端的数量
			while(1)																
			{
				n_read = read(a_fd,&msg,sizeof(msg));						接收客户端传输的信息
				if(n_read == 0)												判断客户端是否有信息发送过来
				{
					printf("client out\n");
					break;
				}
				else if(n_read > 0)											有信息发送过来
				{	
					puts("---------------------------------------------------------------------");优化输出   
					printf("get msg num %d\n",n_read);						输出发送过来的数据量
					msg_handler(msg,a_fd,pid);								解析客户端发送信息,将网络连接描述符,传输数据结构体,父进程的进程描述传给信息处理函数
					puts("---------------------------------------------------------------------");优化输出   
				}
			}
		}
	}
	
	close(s_fd);															关闭socket套接字
	close(a_fd);															关闭网络连接

	return 0;
}

3.2 客户端代码解析

3.2.1 主函数代码解析
int main(int argc,char **argv)
{
	int c_fd;																		定义网络描述符
	int f_fd;																		定义文件描述符
	int n_read;																		定义从服务器读取到的数据量
	struct sockaddr_in c_addr;														定义配置网络信息结构体
	struct Buffer msg;																定义网络传输数据结构体包含在"public.h"库中
	
	//1.socket
	c_fd = socket(AF_INET,SOCK_STREAM,0);											建立socket套接字IPV4 TCP 
	if(c_fd == -1)                                                                  判断是否成功创建套接字
	{
		puts("Socket fail");
		perror("Why");
		exit(-1);
	}
	//2.connect
	c_addr.sin_family = AF_INET;													配置网络为IPV4的绑定信息			
	c_addr.sin_port   = htons(atoi(argv[2]));										配置网络绑定的端口号为输入参数三
	inet_aton(argv[1],&c_addr.sin_addr);											配置网络绑定的IP地址为输入的参数二
	if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr_in)) == -1)	连接服务器,并判断是否连接成功
	{
		perror("connect");
		exit(-1);
	}
	while(1)
	{
		//3.write
		if(fork()==0)																建立子进程,并进入子进程
		{
			while(1)
			{
				memset(msg.cmd,'\0',sizeof(msg.cmd));								清空发送指令缓冲区
				gets(msg.cmd);														获取指令到发送指令缓存器
				printf(">");														输出优化
				msg_handler(msg,c_fd);												处理发送的指令
			}
		}
		while(1)
		{
			n_read = read(c_fd,&msg,sizeof(msg));									接收服务器传回的数据
			if(n_read == 0)															判断是否成功接收到数据
			{
				printf("server is out,quit\n----------------------------------------------------\n");输出优化
				exit(-1);
			}	
			printf("\n%s\n",msg.data);												输出接收到服务器传回的输出数据
			printf("--------------------------------------------------------------------------\n");输出优化
			if(msg.mark == 1)														当msg.mark为1
			{
				puts("Successful get file");										输出成功获取到服务器文件
				printf("file name: %s\n",msg.data);									输出获取到的文件文件名
				f_fd = open(msg.data,O_RDWR|O_CREAT,0600);							打开或创建该文件
				if(f_fd == -1)														判断是否成功创建该文件
				{
					perror("fail why");
				}
				write(f_fd,msg.filedata,strlen(msg.filedata));						向该文件写入服务器传回的文件内容
				close(f_fd);														关闭该文件
			}
		}
	}
	
	
	//4.read
	close(c_fd);																	关闭socket套接字

	return 0;
}
3.2.2 信息处理函数代码解析
void msg_handler(struct Buffer msg,int cc_fd)                                   信息处理函数										
{
	int fd;																		定义文件描述符 
	char *file;																	定义文件名变量
	char fileBuf[1024];															定义文件内容变量
	char BF[128];																定义指令备份变量
	char *dir;																	定义cd路径变量

	switch(get_cmd(msg.cmd))													解析发送的指令并执行相关操作
	{
		case LS:																当命令为ls,pwd,cd时执行以下语句
		case PWD:
		case CD:
			write(cc_fd,&msg,sizeof(msg));										直接向服务器发送数据msg
			break;
		case GET:																当命令为get时执行以下语句
			puts("----------------------------------------------------");		输出优化
			printf("in get\n");													提示进入get模式
			write(cc_fd,&msg,sizeof(msg));										直接向服务器发送数据msg
                        break;
		case PUT:																当命令为put时执行以下语句
			puts("----------------------------------------------------");		输出优化
			puts("in put");														提示进入put模式
			memset(BF,'\0',128);												清空指令备份变量
			strcpy(BF,msg.cmd);													备份指令
			file = getDir(msg.cmd);												解析指令,并输出文件名
			fd = open(file,O_RDWR);												打开该文件
			read(fd,fileBuf,1024);												读取文件内容到fileBuf中
			strcpy(msg.filedata,fileBuf);										将fileBuf中的内容拷贝到msg.filedata中
                        strcpy(msg.data,file);									将文件名拷贝到msg.data中
			strcpy(msg.cmd,BF);													将备份好的指令拷贝回msg.cmd中
			memset(BF,'\0',128);												清空指令备份变量
			write(cc_fd,&msg,sizeof(msg));										直接向服务器发送数据msg
			备份指令的原因:因为解析指令会将指令拆开,导致服务器无法解析
			break;
		case CDD:																当命令为cdd时执行以下语句
			puts("----------------------------------------------------");		输出优化
			puts("in cdd");														提示进入cdd模式
			dir = getDir(msg.cmd);												解析cdd文件路径
			printf("dir: %s\n",dir);											输出cdd文件路径
			chdir(dir);															改变当前工作路径
			break;
		case LSS:																当命令为lss时执行以下语句
			puts("----------------------------------------------------");		输出优化
			puts("in lss");														提示进入lss模式
			system("ls");														直接使用system函数执行ls命令
			break;
		case PWDD:																当命令为pwdd时执行以下语句
			puts("----------------------------------------------------");		输出优化
			puts("in pwdd");													提示进入pwdd模式
			system("pwd");														直接使用system函数执行pwd命令
			break;	
		case QUIT:																当命令为quit时执行以下语句
			write(cc_fd,&msg,sizeof(msg));										直接向服务器发送数据msg
			exit(-1);															退出子进程
			break;	
	}
}
3.2.3 获取命令函数代码解析
int get_cmd(char *cmd)															 获取命令函数
{
	if(!strcmp(cmd,"ls"))	return LS;								             获取到命令ls返回LS宏						
	if(!strcmp(cmd,"pwd"))	return PWD;								             获取到命令pwd返回PWD宏
	if(!strcmp(cmd,"quit"))	return QUIT;							             获取到命令quit返回QUIT宏
	if(strstr(cmd,"cd") != NULL)	return CD;						             获取到命令cd返回CD宏
    if(strstr(cmd,"get") != NULL)	return GET;						             获取到命令get返回GET宏
    if(strstr(cmd,"input") != NULL)	return PUT;						             获取到命令put返回PUT宏								
	if(strstr(cmd,"lss") != NULL)   return LSS;									 获取到命令lss返回LSS宏
	if(strstr(cmd,"pwdd") != NULL)  return PWDD;		                         获取到命令pwdd返回PWDD宏
	if(strstr(cmd,"dk") != NULL)    return CDD;									 获取到命令cdd返回CDD宏
	
	return 0;																	 其他情况返回0
}
3.2.4 cd路径,文件名解析函数代码解析
char *getDir(char *smdr)														 cd路径,文件名解析函数
{
	char *p = NULL;
	
	p = strtok(smdr," ");											             采用strtok函数分割字符串即可
	p = strtok(NULL," ");
	
	return p;
}
3.2.5 客户端完整代码解析
#include <stdio.h>
#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
//#include <linux/in.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include "public.h"
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>


int get_cmd(char *cmd)															 获取命令函数
{
	if(!strcmp(cmd,"ls"))	return LS;								             获取到命令ls返回LS宏						
	if(!strcmp(cmd,"pwd"))	return PWD;								             获取到命令pwd返回PWD宏
	if(!strcmp(cmd,"quit"))	return QUIT;							             获取到命令quit返回QUIT宏
	if(strstr(cmd,"cd") != NULL)	return CD;						             获取到命令cd返回CD宏
    if(strstr(cmd,"get") != NULL)	return GET;						             获取到命令get返回GET宏
    if(strstr(cmd,"input") != NULL)	return PUT;						             获取到命令put返回PUT宏								
	if(strstr(cmd,"lss") != NULL)   return LSS;									 获取到命令lss返回LSS宏
	if(strstr(cmd,"pwdd") != NULL)  return PWDD;		                         获取到命令pwdd返回PWDD宏
	if(strstr(cmd,"dk") != NULL)    return CDD;									 获取到命令cdd返回CDD宏
	
	return 0;																	 其他情况返回0
}
	
char *getDir(char *smdr)														 cd路径,文件名解析函数
{
	char *p = NULL;
	
	p = strtok(smdr," ");											             采用strtok函数分割字符串即可
	p = strtok(NULL," ");
	
	return p;
}

void msg_handler(struct Buffer msg,int cc_fd)                                   信息处理函数										
{
	int fd;																		定义文件描述符 
	char *file;																	定义文件名变量
	char fileBuf[1024];															定义文件内容变量
	char BF[128];																定义指令备份变量
	char *dir;																	定义cd路径变量

	switch(get_cmd(msg.cmd))													解析发送的指令并执行相关操作
	{
		case LS:																当命令为ls,pwd,cd时执行以下语句
		case PWD:
		case CD:
			write(cc_fd,&msg,sizeof(msg));										直接向服务器发送数据msg
			break;
		case GET:																当命令为get时执行以下语句
			puts("----------------------------------------------------");		输出优化
			printf("in get\n");													提示进入get模式
			write(cc_fd,&msg,sizeof(msg));										直接向服务器发送数据msg
                        break;
		case PUT:																当命令为put时执行以下语句
			puts("----------------------------------------------------");		输出优化
			puts("in put");														提示进入put模式
			memset(BF,'\0',128);												清空指令备份变量
			strcpy(BF,msg.cmd);													备份指令
			file = getDir(msg.cmd);												解析指令,并输出文件名
			fd = open(file,O_RDWR);												打开该文件
			read(fd,fileBuf,1024);												读取文件内容到fileBuf中
			strcpy(msg.filedata,fileBuf);										将fileBuf中的内容拷贝到msg.filedata中
                        strcpy(msg.data,file);									将文件名拷贝到msg.data中
			strcpy(msg.cmd,BF);													将备份好的指令拷贝回msg.cmd中
			memset(BF,'\0',128);												清空指令备份变量
			write(cc_fd,&msg,sizeof(msg));										直接向服务器发送数据msg
			备份指令的原因:因为解析指令会将指令拆开,导致服务器无法解析
			break;
		case CDD:																当命令为cdd时执行以下语句
			puts("----------------------------------------------------");		输出优化
			puts("in cdd");														提示进入cdd模式
			dir = getDir(msg.cmd);												解析cdd文件路径
			printf("dir: %s\n",dir);											输出cdd文件路径
			chdir(dir);															改变当前工作路径
			break;
		case LSS:																当命令为lss时执行以下语句
			puts("----------------------------------------------------");		输出优化
			puts("in lss");														提示进入lss模式
			system("ls");														直接使用system函数执行ls命令
			break;
		case PWDD:																当命令为pwdd时执行以下语句
			puts("----------------------------------------------------");		输出优化
			puts("in pwdd");													提示进入pwdd模式
			system("pwd");														直接使用system函数执行pwd命令
			break;	
		case QUIT:																当命令为quit时执行以下语句
			write(cc_fd,&msg,sizeof(msg));										直接向服务器发送数据msg
			exit(-1);															退出子进程
			break;	
	}
}

int main(int argc,char **argv)
{
	int c_fd;																		定义网络描述符
	int f_fd;																		定义文件描述符
	int n_read;																		定义从服务器读取到的数据量
	struct sockaddr_in c_addr;														定义配置网络信息结构体
	struct Buffer msg;																定义网络传输数据结构体包含在"public.h"库中
	
	//1.socket
	c_fd = socket(AF_INET,SOCK_STREAM,0);											建立socket套接字IPV4 TCP 
	if(c_fd == -1)                                                                  判断是否成功创建套接字
	{
		puts("Socket fail");
		perror("Why");
		exit(-1);
	}
	//2.connect
	c_addr.sin_family = AF_INET;													配置网络为IPV4的绑定信息			
	c_addr.sin_port   = htons(atoi(argv[2]));										配置网络绑定的端口号为输入参数三
	inet_aton(argv[1],&c_addr.sin_addr);											配置网络绑定的IP地址为输入的参数二
	if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr_in)) == -1)	连接服务器,并判断是否连接成功
	{
		perror("connect");
		exit(-1);
	}
	while(1)
	{
		//3.write
		if(fork()==0)																建立子进程,并进入子进程
		{
			while(1)
			{
				memset(msg.cmd,'\0',sizeof(msg.cmd));								清空发送指令缓冲区
				gets(msg.cmd);														获取指令到发送指令缓存器
				printf(">");														输出优化
				msg_handler(msg,c_fd);												处理发送的指令
			}
		}
		while(1)
		{
			n_read = read(c_fd,&msg,sizeof(msg));									接收服务器传回的数据
			if(n_read == 0)															判断是否成功接收到数据
			{
				printf("server is out,quit\n----------------------------------------------------\n");输出优化
				exit(-1);
			}	
			printf("\n%s\n",msg.data);												输出接收到服务器传回的输出数据
			printf("--------------------------------------------------------------------------\n");输出优化
			if(msg.mark == 1)														当msg.mark为1
			{
				puts("Successful get file");										输出成功获取到服务器文件
				printf("file name: %s\n",msg.data);									输出获取到的文件文件名
				f_fd = open(msg.data,O_RDWR|O_CREAT,0600);							打开或创建该文件
				if(f_fd == -1)														判断是否成功创建该文件
				{
					perror("fail why");
				}
				write(f_fd,msg.filedata,strlen(msg.filedata));						向该文件写入服务器传回的文件内容
				close(f_fd);														关闭该文件
			}
		}
	}
	
	
	//4.read
	close(c_fd);																	关闭socket套接字

	return 0;
}

3.3 "public.h"文件代码

#define LS   1
#define PWD  2
#define CD   3
#define GET  4
#define PUT  5
#define CDD  6
#define LSS  7
#define PWDD 8
#define QUIT 9	

struct Buffer
{
	int mark;
	char cmd[128];		指令
	char data[1024];	文件名
	char filedata[1024];文件内容
};

四、 程序运行结果

  请看视频

<iframe allowfullscreen="true" data-mediaembed="csdn" frameborder="0" id="ysHe8IFu-1725884502637" src="https://live.csdn.net/v/embed/423240"></iframe>

Linux系统编程【网盘项目】

结束语

  非常感谢您的耐心阅读!在您即将离开之际,如果您觉得内容有所收获或启发,不妨动动手指,点个赞再走,这将是对我莫大的鼓励和支持。衷心感谢您的点赞与关注,期待未来能继续为您带来更多有价值的内容!谢谢您!

标签:cmd,return,puts,int,网盘,编程,fd,Linux,msg
From: https://blog.csdn.net/CallmeBrotherMa/article/details/142067321

相关文章

  • Linux系统上安装Docker的详细教程
    感谢浪浪云支持发布浪浪云活动链接:https://langlangy.cn/?i8afa52文章目录1.在Ubuntu/Debian系统上安装Docker1.1更新软件包1.2安装依赖包1.3添加DockerGPG密钥1.4添加Docker仓库1.5安装Docker引擎1.6启动并验证Docker2.在CentOS/RHEL系统上安装Docker2.1......
  • 【实验楼】Linux系统管理-实验一:初识命令行
    Linux系统管理-实验一:初识命令行尝试简单命令请在命令行中显示当前所处的目录的名字。pwd请在命令行中显示当前主机名。hostname请在命令行中显示当前所使用的用户的名称。whoami尝试命令的选项请下达在15分钟内模拟关机的命令。shutdown-k15shutdown命令:https:/......
  • windows和Linux常用路径
    Linux/home普通用户在此目录下/etc 程序的配置文件/etc/resolv,conf  存放dns信息/etc/passwd文件内有用户的所有基本信息,密码是*储存在shadow里/etc/shadow存放密码/etc/group存放的组信息/tmp 存放临时文件/user/local/bin本地命令/car/spool/mail存......
  • Linux下io模型
    目录一. 阻塞式IO:最常见、效率低、不耗费cpuudp丢包​编辑tcp粘包tcp拆包二.非阻塞io:轮询、耗费CPU,可以处理多路IO概念设置非阻塞的方式1.通过函数自带参数设置2.通过设置文件描述符的属性,把对应属性设置为非阻塞三. 信号驱动IO/异步IO:异步通知方式,需要底层驱动......
  • python编程二维码里放视频
    动植物标本制作大赛  需要制作一个关于植物标本的二维码 存放采集植物的视频 笑了 pipinstallqrcode pipinstallopencv-python-ihttps://pypi.tuna.tsinghua.edu.cn/simple  新建文件贴入代码如下:importqrcodeimportcv2#视频链接video_url="h......
  • Java并发编程15
    1、创建线程的有哪些方式继承Thread类创建线程类通过Runnable接口创建线程类通过Callable和Future创建线程通过线程池创建2、创建线程的三种方式的对比1、采用实现Runnable、Callable接口的方式创建多线程。**优势是:**线程类只是实现了Runnable接口或Calla......
  • Linux上rpm安装MySQL8
    1.下载安装包下载链接https://downloads.mysql.com/archives/community/或者在MySQL官网根据提示一步一步点进去选择合适的版本2.上传至服务器,解压tar-xvfmysql-8.0.33-1.el7.x86_64.rpm-bundle.tar3.安装参考官方文档https://dev.mysql.com/doc/refman/8.0/en......
  • WSL(Windows Subsystem for Linux)密码忘记了怎么办
    首先以管理员身份打开powershell输入wsl.exe--userroot(root账户)输入passwdroot接着输入新密码再确认一遍就OK了修改成功(普通账户)输入 passwd(username)修改成功 ......
  • windows和Linux上安装nvm及相关配置
    Windows安装:1、详情参考:https://blog.csdn.net/goods_yao/article/details/137854626本文详细介绍了在Windows系统中使用nvm(NodeVersionManager)管理Node.js版本的过程,包括卸载Node.js、nvm的安装与配置、修改npm镜像源、环境变量设置及常见问题解决。 Linux(centos7.6)安装:0、机......
  • 对于linux文件权限的思考
    ​ 一个文件或目录可以从权限和其所属讲起。1.从用户的创建开始​ 一个用户从创建开始就有了所属用户组,这是因为每个用户必须属于一个主组,通常在用户创建时系统会默认为其创建一个同名的主组(后续可由超级用户(root)通过修改用户的账户设置来更改主组)。​ 那么由该用户创建的文......