"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];文件内容
};
四、 程序运行结果
请看视频
Linux系统编程【网盘项目】
结束语
非常感谢您的耐心阅读!在您即将离开之际,如果您觉得内容有所收获或启发,不妨动动手指,点个赞再走,这将是对我莫大的鼓励和支持。衷心感谢您的点赞与关注,期待未来能继续为您带来更多有价值的内容!谢谢您!