ftp服务器搭建类似云盘代码(带注释详解代码)

使用说明

运行操作

  1. 运行服务端

    ./server 本机IP地址 端口号(使用ifconfig查看本机IP地址)

  2. 运行客户端
    ./client IP地址 相同端口号

指令说明

  • ls —— 查看服务端当下目录
  • lls —— 查看客户端当下目录
  • pwd —— 查看服务端当前路径
  • quit —— 客户端退出连接
  • cd name —— 令服务器进入到name路径下下
  • get name —— 从服务器上下载name文件
  • put name —— 将客户端name文件上传到服务器

头文件define.h

#define LS 0
#define GET 1
#define PWD 2
#define CD 3
#define IFGO 4
#define LCD 5
#define LLS 6
#define PUT 7
#define QUIT 8
#define DOFILE 9

struct Msg		//数据传递中转变量
{
        int type;
        char cmd[1024];
        char secondBuf[1024];
};
~   

服务器server.c

#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include"define.h"
#include <sys/stat.h>
#include <fcntl.h>

void delchar(char *dir,char change[10])		//将指针字符串dir后\n删除后放到数组change中
{
        sprintf(change,"%s",dir);
        int size = strlen(dir);
        change[size-1] = '\0';
}

char *getDesDir(char *cmsg)			//获取某些命令后的参数如指令"cd .."中的".."
{
        char *p;
        p = strtok(cmsg," ");
        p = strtok(NULL," ");
        return p;
}

int get_cmd_type(char *cmd)			//接收客户端传来的数据后通过对比确定命令是什么
{
        if(!strcmp("ls\n",cmd)) return LS;
        if(!strcmp("quit\n",cmd)) return QUIT;
        if(!strcmp("pwd\n",cmd)) return PWD;
        if(strstr(cmd,"cd") != NULL) return CD;
        if(strstr(cmd,"get") != NULL) return GET;
        if(strstr(cmd,"put") != NULL) return PUT;
}

void msg_handler(struct Msg msg, int fd)	//根据客户端传来的命令做出对应反应
{
        char dataBuf[1024] = {0};
        char *file = NULL;
        
        int fdfile;
        int ret = get_cmd_type(msg.cmd);	//获取命令对应的数字
        
        switch(ret){				//根据数字执行命令
        
                case LS:
                case PWD:
                         msg.type = 0;
                         FILE *fp = popen(msg.cmd,"r");		//直接使用传来的命令
                         
                         fread(msg.cmd,sizeof(msg.cmd),1,fp);	//将获取的数据读到msg.cmd中
                         write(fd,&msg,sizeof(msg));		//将数据发回客户端
                        
                         break;
                case CD:
                        msg.type = 1;
                        char *dir = getDesDir(msg.cmd);		//分离指令后的参数
                        char CD_Change[10];
                        			
                        delchar(dir,CD_Change);			//删除命令后\n(由于使用fgets获取字符串会自动加\n)
                        
                        chdir(CD_Change);			//进入到目标的路径下
                       
                        break;
                case GET:
                        file = getDesDir(msg.cmd);		//分离出要获取的文件名
                        char GET_Change[10];
                        delchar(file,GET_Change);		//删除\n
                        
                        if(access(GET_Change,F_OK) == -1){		//判断是否存在输入文件名
                                strcpy(msg.cmd,"No this file!");
                                write(fd,&msg,sizeof(msg));
                        }else{
                                msg.type = DOFILE;
                                fdfile = open(GET_Change,O_RDWR);	//打开要下载的文件
                                read(fdfile,dataBuf,sizeof(dataBuf));	//将文件信息读到dataBuf中
                                close(fdfile);
                                
                                strcpy(msg.cmd,dataBuf);		//将文件数据复制给msg.cmd
                                write(fd,&msg,sizeof(msg));		//传回客户端
                        }
                        
                        break;
                case PUT:
                        file = getDesDir(msg.cmd);			//分离出要上传的文件名
                        char PUT_Change[10];
                        
                        delchar(file,PUT_Change);			//删除\n
                        
                        fdfile = open(PUT_Change,O_RDWR|O_CREAT,0600);		//创建并打开该名文件
                        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 c_fd;
        int n_read;
        int clen = sizeof(struct sockaddr_in);
        
        char readBuf[128];
        struct Msg msg;
        
        struct sockaddr_in s_addr;
        struct sockaddr_in c_addr;
        
        memset(&s_addr,0,sizeof(struct sockaddr_in));
        memset(&c_addr,0,sizeof(struct sockaddr_in));
        
        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);
        
        bind(s_fd,(struct sockaddr *)&s_addr/,sizeof(struct sockaddr_in));	//绑定数据
        
        listen(s_fd,10);		//监听客户端
        
  	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(readBuf,0,sizeof(readBuf));		//清空readBuf
                                
                                n_read = read(c_fd,&msg,sizeof(msg));		//接受客户端发送的指令(没有则阻塞)
                                
                                if(n_read == 0)			//判断
                                {
                                        perror("client out\n");
                                        break;
                                }else if(n_read > 0){
					msg_handler(msg,c_fd);		//将指令传入msg_handler函数进行判断
                                }
                        }
                }
        }
        
        close(c_fd);
        close(s_fd);
        return 0;
}

客户端client

#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include"define.h"
#include <sys/stat.h>
#include <fcntl.h>

void delchar(char *dir,char change[10])			//将指针字符串dir后\n删除后放到数组change中
{
        sprintf(change,"%s",dir);
        int size = strlen(dir);
        change[size-1] = '\0';
}

char *getdir(char *cmd)					//获取某些命令后的参数如指令"cd .."中的".."
{
        char *p;
        p = strtok(cmd," ");
        p = strtok(NULL," ");
        return p;
}

int get_cmd_type(char *cmd)				//接收客户端传来的数据后通过对比确定命令是什么
{
        if(strstr(cmd,"lcd") != NULL) return LCD;
        if(!strncmp("ls\n",cmd,sizeof(cmd))) return LS;
        if(!strncmp("quit\n",cmd,sizeof(cmd))) return QUIT;
        if(!strncmp("pwd\n",cmd,sizeof(cmd))) return LS;
        if(!strncmp("lls\n",cmd,sizeof(cmd))) return LLS;
        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=0;
        int filefd;
        
        ret = get_cmd_type(msg.cmd);				//获取命令对应的数字
        
        switch(ret){						//根据数字执行对于命令
                case CD:
                case LS:
                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.cmd);			
                         dir = getdir(buf);			//分离命令中文件名
                         
			 char PutFileName[10];
                         delchar(dir,PutFileName);		//删除\n
                         
                         if(access(PutFileName,F_OK) == -1){	//判断文件是否存在
   z                             printf("%s not exsit\n",dir);
                         }else{
                                filefd = open(PutFileName,O_RDWR);			//打开文件
                                read(filefd,msg.secondBuf,sizeof(msg.secondBuf));	//读取文件数据
                                close(filefd);
                                write(fd,&msg,sizeof(msg));				//将文件数据发给服务端
                         }
                         break;
                case LLS:
                	 system("ls");		//直接执行ls指令
                         break;
                case LCD:
                         dir = getdir(msg.cmd);		//分离文件名
                         chdir(dir);			//进入所在路径
                         break;
                case QUIT:
                          write(fd,&msg,sizeof(msg));	
                          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.cmd);
                char filename[10];
                delchar(p,filename);
         w       
                newfilefd = open(filename,O_RDWR|O_CREAT,0600);		//将服务端下载好的数据建同名文件
                write(newfilefd,msgget.cmd,strlen(msgget.cmd));		//将数据录入进去
                
                putchar('>');
                fflush(stdout);
                close(newfilefd);
        }
        else{
                printf("------------------------------------------\n");
                printf("%s\n",msgget.cmd);
		printf("------------------------------------------\n");
                putchar('>');
                fflush(stdout);
        }
}

int main(int argc,char **argv)
{
        int c_fd;
        int n_read;
        char readBuf[128];
        
        struct Msg msg;
        struct sockaddr_in c_addr;
        
        memset(&c_addr,0,sizeof(struct sockaddr_in));
        
        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);
        
        if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr)) == -1){	//连接服务端并判断是否成功
                perror("connect");
                exit(-1);
                }
        printf("connect...\n");
        int mark = 0;
        
        while(1)
        {
                memset(msg.cmd,0,sizeof(msg.cmd));
                
                if(mark == 0)   printf(">");			//为了美观>的处理
                
                fgets(msg.cmd,sizeof(msg.cmd),stdin);		//获取命令
                if(strlen(msg.cmd) == 0){
                        if(mark == 1){
                                printf(">");
                        }
                        continue;
                }
                mark == 1;
                
                int ret = cmd_handler(msg,c_fd);		//根据指令做出的相关操作
                
                if(ret >= CD)					//对于CD PWD等指令无需后续步骤
                {
                        putchar('>');
                        fflush(stdout);
                        continue;
                }
                if(ret == -1)					//判断输入指令是否存在
                {
                        printf("command not\n");
                        printf(">");
                        fflush(stdout);
                        continue;
                }
                
                handler_server_message(c_fd,msg);		//打印所得到的数据
        }
        close(c_fd);
        return 0;
}

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值