【Linux系统编程】FTP网盘项目代码加注释

该项目展示了Linux环境下客户端和服务端通过网络进行目录操作、文件上传下载的交互实现。服务端接收客户端请求,解析命令并执行相应操作,如ls、cd、get、put等,并将结果反馈给客户端。客户端则发送命令并接收服务端的响应,支持本地命令执行和文件操作。整个系统使用了socket编程,实现了简单的文件管理系统。
摘要由CSDN通过智能技术生成

这是一个Linux网络编程的综合项目,实现了客户端向服务端请求查看目录,请求进入指定目录,向服务端上传文件,从服务端获取文件,退出客户端等操作,实现了客户端和服务端的简单交互,这是学习过程中的源码和注释,方便自己查看,一起拿来分享。

服务端代码:

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

char *getDesDir(char *cmsg) 	//将命令中的文件名提取出来
{
        char *p;
        p = strtok(cmsg," ");
        p = strtok(NULL," ");
        return p;
}

int get_cmd_type(char *cmd) 	//解析命令返回宏定义
{
        if(!strcmp("ls",cmd))           return LS;
        if(!strcmp("quit",cmd))         return PWD;
        if(!strcmp("pwd",cmd))          return QUIT;
        if(strstr(cmd,"cd") != NULL)    return CD;
        if(strstr(cmd,"get") != NULL)   return GET;
        if(strstr(cmd,"put") != NULL)   return PUT;

        return 100;
}

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);	//将输出结果读取入msg.data
                        write(fd,&msg,sizeof(msg));		//将结构体内容发送给客户端
                        break;
                case CD:
                        msg.type = 1;
                        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));		//将文件读入dataBuf
                                close(fdfile);		//关闭文件

                                strcpy(msg.data,dataBuf);		//将文件内的内容拷贝入msg.data
                                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));		//将客户端想要上传的文件内容写入服务端新创建的文件中去
                        close(fdfile);		//关闭文件流
                        break;
                case QUIT:
                        printf("client quit!\n");
                        exit(-1);		//退出处理该客户端进程
        }
}

int main(int argc,char **argv)
{
        int s_fd;
        int n_read;
        int c_fd;
        char readBuf[128];

        struct sockaddr_in c_addr;
        struct sockaddr_in s_addr;
        struct Msg msg;

        if(argc != 3){
                printf("param is not good\n");
        }

        memset(&s_addr,0,sizeof(struct sockaddr_in));		//清空socket信息结构体
        memset(&c_addr,0,sizeof(struct sockaddr_in));

        //1. socket
        s_fd = socket(AF_INET, SOCK_STREAM, 0);
        if(s_fd == -1){
                perror("socket");
                exit(-1);
        }

        s_addr.sin_family = AF_INET;
        s_addr.sin_port = htons(atoi(argv[2]));
        inet_aton(argv[1],&s_addr.sin_addr);

        //2.bind
        bind(s_fd, (struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
        
		 //3.listen
        listen(s_fd, 10);
        //4.accept
        int clen = sizeof(struct sockaddr_in);

        while(1){		//不断监听获取新客户端连接
                c_fd = accept(s_fd, (struct sockaddr *)&c_addr, &clen);
                if(c_fd == -1){
                        perror("accept");
                }

                printf("get connect: %s\n",inet_ntoa(c_addr.sin_addr));

                if(fork() == 0){		//创建新进程处理客户端的交互
                        while(1){
                                memset(msg.data,0,sizeof(msg.data));
                                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);		//处理结构体信息
                                }
                        }
                }
        }
        close(c_fd);		//关闭客户端
        close(s_fd);		//关闭服务端
        return 0;
}


客户端代码:

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

char * getdir(char *cmd)		//获取命令中的文件名
{
        char *p;

        p = strtok(cmd, " " );
        p = strtok(NULL, " ");

        return p;
}

int get_cmd_type(char *cmd)		//将命令转化为宏定义
{
        if(strstr(cmd,"lcd"))   return LCD;


        if(!strcmp("quit",cmd))   return QUIT;
         if(!strcmp("ls",cmd))    return LS;
        if(!strcmp("lls",cmd))   return LLS;
        if(!strcmp("pwd",cmd))   return LS;

        if(strstr(cmd,"cd"))    return CD;
        if(strstr(cmd,"get"))   return GET;
        if(strstr(cmd,"put"))   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 not exist\n",dir);
                }else{
                        filefd = open(dir,O_RDWR);		//打开想要上传至服务端的文件
                        read(filefd,msg.secondBuf,sizeof(msg.secondBuf));		//读取文件内容到msg.secondBuf
                        close(filefd);		//关闭文件

                        write(fd,&msg,sizeof(msg));		//将结构体发送至服务端
                }
                        break;
                case LLS:
                        system("ls");		//执行客户端自己的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 msgget;
        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){		//匹配GET文件操作
                char *p = getdir(msg.data);		//提取要获取的文件名
                newfilefd = open(p,O_RDWR|O_CREAT,0600);		//创建打开新文件
                write(newfilefd,msgget.data,strlen(msgget.data));		//将文件内容写入新文件
                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;
         if(argc != 3){
                printf("param is not good\n");
        }

        memset(&c_addr,0,sizeof(struct sockaddr_in));		//清空socket信息结构体

        //1. socket
        c_fd = socket(AF_INET, SOCK_STREAM, 0);
        if(c_fd == -1){
                perror("socket");
                exit(-1);
        }


        c_addr.sin_family = AF_INET;
        c_addr.sin_port = htons(atoi(argv[2]));
        inet_aton(argv[1],&c_addr.sin_addr);

        //2.connect
        if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr)) == -1){
                perror("connect");
                exit(-1);
        }
        printf("connect..");

		 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("\n");
                        fflush(stdout);
                        continue;
                }
                handler_server_message(c_fd, msg);		//处理服务端信息
        }

        return 0;
}
                


头文件代码:(config.h)

#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];
};


运行结果:

在这里插入图片描述

在这里插入图片描述

本次学习分享就到这里。

每天都要看到进步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT阳晨。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值