基于TCP协议的共享文件夹(Linux)

一、实现功能

 help    功能目录
 pwd     我在哪
 ls      目录
 cd      就是cd
 mkdir   创建文件夹
 rmdir   删除文件夹
 rm      删除文件
 get     下载
 put     上传

二、操作系统

Ubuntu(64-bit)

三、代码

1.服务器 server.c

#include"server.h"                                     

pthread_rwlock_t lock;
int epfd;
Client gcls[MAX_CLIENTS+1] = {};        //事件表  fd  path  账号
int size = 0;
struct epoll_event events[MAX_CLIENTS+1] = {};  //就绪事件表
int is=0;

int init_server(const char *ip,unsigned short int port);
void *accept_client(void *id);
int recv_data(int fd);
void *sign_in(void *id);
void select_fd(int fd);
void zoule(void);
int cmp_num(const void *a,const void *b);
void sig_exit();

int main(int argc,char *argv[]){
    pLogFile=stdout;       //log日志输出流指向标准输出
    if(argc < 3){
        printf("%s ip port\n",argv[0]);
        return -1;
    }
    if(signal(SIGINT,sig_exit)==SIG_ERR)
        LOG_TRACE("退出信号处理失败\n");
    int ret=pthread_rwlock_init(&lock,NULL);  //初始化线程锁

    atexit(zoule);                            //退出前执行
    list_cus=list_init(CSIZE);                //定义 一个双向循环链表用于存储账号
    load_cus();                               //载入账号  密码
    load_num();                               //载入未注册账号
    strcpy(localip,argv[1]);                  //保存IP和端口  全局变量
    localport=atoi(argv[2]);
    int fd = init_server(argv[1],atoi(argv[2]));//初始化服务器
    select_fd(fd);                            //连接客户端
    return 0;    
}
int init_server(const char *ip,unsigned short int port){
    int fd = socket(AF_INET,SOCK_STREAM,0);                //套接字
    assert(fd != -1);
    struct sockaddr_in addr = {};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = inet_addr(ip);
    socklen_t len = sizeof(addr);
    int ret = bind(fd,(const struct sockaddr*)&addr,len);  //绑定端口
    assert(ret != -1);
    ret = listen(fd,MAX_CLIENTS);                          //监听
    assert(ret != -1);
    return fd;
}

void select_fd(int fd){
    epfd = epoll_create(MAX_CLIENTS);
    if(epfd == -1){
        perror("epoll_create");
        return;    
    }
    struct epoll_event event = {};
    event.events = EPOLLIN;              //  可读事件
    event.data.fd = fd;                  //数据(主线程fd)
    int ret = epoll_ctl(epfd,EPOLL_CTL_ADD,fd,&event);
    if(ret == -1){
        perror("epoll_ctl");
        return ;
    }

    while(true){
        usleep(1000);                    //这里应该用线程池
        ret = epoll_wait(epfd,events,MAX_CLIENTS+1,-1);
        if(ret == -1){
            perror("epoll_wait");
            break;
        }           //就绪事件数量     监听数量
        LOG_TRACE("events_size=%d  wait_ret=%d\n",size,ret);
        int i;
            pthread_t id;
        for(i=0;i<ret;i++){
            is = i;         //就绪事件 fd
                LOG_TRACE("events[is].data.fd =%d\n",events[i].data.fd );
            if(events[i].data.fd == fd){         //有客户端连接
               int rret = pthread_create(&id,NULL,accept_client,(void *)fd);
                           //这里应该用线程池
               assert(rret == 0);    
            }else{                               //有数据接收
                if(events[i].events & EPOLLIN){
                   pthread_t id;
                   int rret = pthread_create(&id,NULL,sign_in,(void*)events[i].data.fd);                                   //子线程去处理数据
                   assert(rret == 0);
                }
            }
        }
    }
}

void *sign_in(void *id){
    int fd=(int)id;
    int ret = recv_data(fd);            //处理数据
    if(ret == 0){                   //客户端异常   删除事件
        struct epoll_event ev = {};
        ev.events = EPOLLIN|EPOLLET|EPOLLONESHOT;    
        ev.data.fd = fd;
        ret = epoll_ctl(epfd,EPOLL_CTL_DEL,events[is].data.fd,&ev);  
        if(ret == -1){
            perror("epoll_ctl");    
        }
    }

}

void zoule(void){    //退出前保存数据
     save_cus();    
     save_num();
}

int cmp_num(const void *a,const void *b){     //比较函数
    const CUS* node=b;
    return strcmp((char *)a,node->id);

}

void sig_exit(){                              //收到信号   退出程序
     exit(0);
}

void *accept_client(void *id){
    int fd=(int)id;
    struct sockaddr_in addr = {};
    socklen_t len = sizeof(addr);
    int cfd = accept(fd,(struct sockaddr*)&addr,&len);            //有客户端连接
    if(cfd != -1){
        Client cls = {};
        cls.fd = cfd;
        cls.addr = addr;
        strcpy(cls.id,"");     //未绑定账号
        gcls[size] = cls;
        ++size;
        struct epoll_event event = {};
        event.events = EPOLLIN;
        event.data.fd = cfd;
        pthread_rwlock_wrlock(&lock);
        int ret = epoll_ctl(epfd,EPOLL_CTL_ADD,cfd,&event);   //客户端套接字加入事件表
        if(ret == -1){
            perror("epoll_ctl");    
        }
        pthread_rwlock_unlock(&lock);
        LOG_TRACE("有一个客户端登入了服务器\n");
    }
}

int recv_data(int fd){
    int index = 0;
    pthread_rwlock_rdlock(&lock);
    for(;index<size;index++){
        if(gcls[index].fd == fd){                        //在事件表中找到该fd
            break;    
        }    
    }
    pthread_rwlock_unlock(&lock);

    int ord=0;
    int ret = 0;
    if(strcmp(gcls[index].id,"")==0){                        //未绑定账号,去登陆或者注册
        ret = recv(fd,&ord,4,0);
        nixu(&ord,sizeof(ord));
        LOG_TRACE("线程未绑定\n");
        if(ret==-1){
             LOG_TRACE("%m\n");
             return 0;
        }
        if(ord==1){                                     //注册
             CUS elem={};             
             ret=recv(fd,&elem,sizeof(elem),0);
             if(ret==-1){
                 LOG_TRACE("%m\n");
                 return 0;
             }
             pthread_rwlock_wrlock(&lock);
             strcpy(elem.id,num);
             ret=send(fd,num,8,0);
             if(ret==-1){
                 LOG_TRACE("%m\n");
                 return 0;
             }
             add(num,"1");
             LOG_TRACE("\n账户:%s  密码:%s\n",elem.id,elem.pass);
             end_insert(list_cus,&elem);
             pthread_rwlock_unlock(&lock);

          }else if(ord==2){                                 //登录
                         SIGN ke;
             ret=recv(fd,&ke,sizeof(ke),0);
             if(ret==-1){
                 LOG_TRACE("%m\n");
                 return 0;
             }
             LOG_TRACE("收到登陆数据\n");
             pthread_rwlock_rdlock(&lock);
             struct Node *node=find_elem(list_cus,ke.id,cmp_num);       
             pthread_rwlock_unlock(&lock);
                         if(node!=NULL){
                             CUS *cnode=node->elem;
                             if(strcmp(cnode->pass,ke.pass)!=0){
                                  node=NULL; 
                                  LOG_TRACE("账号密码不匹配\n");
                             }
                         }            
             if(node!=NULL){
                 CUS *cnode=node->elem;
                 ret=send(fd,cnode,sizeof(CUS),0);
                 if(ret==-1){
                  LOG_TRACE("%m\n");
                  return 0;
                 }
                 LOG_TRACE(">>>>>>登陆账户%s\n",cnode->id);
                 strcpy(gcls[index].id,cnode->id);  //fd绑定已登录id
                 strcpy(gcls[index].path,"");       //初始化path
             }else{
                 CUS cnode={};
                 strcpy(cnode.id,"0");
                 ret=send(fd,&cnode,sizeof(CUS),0);
                 if(ret==-1){
                     LOG_TRACE("%m\n");
                     return 0;
                 }
                 LOG_TRACE("登陆失败\n");        
                 strcpy(gcls[index].id,"");          //清空fd绑定的id
                 strcpy(gcls[index].path,"");        //清空fd绑定的path
                }
          }else{
                 int index = 0;
            pthread_rwlock_wrlock(&lock);
            for(;index<size;index++){
                if(gcls[index].fd == fd){
                    break;    
                }    
            }
            gcls[index]=gcls[size-1];
            --size;
            pthread_rwlock_unlock(&lock);    
            struct epoll_event ev = {};
            ev.events = EPOLLIN;
            ev.data.fd = fd;
            ret = epoll_ctl(epfd,EPOLL_CTL_DEL,events[is].data.fd,&ev);     
                                   //把事件从事件表里删除
            if(ret == -1){
                perror("epoll_ctl");    
            }
            LOG_TRACE("有一个客户端登出了服务器!!!\n");
            return 1;
          }                                 
    }else{                               //已登录进程,获得绑定id和path
        pthread_rwlock_rdlock(&lock);
        struct Node *node=find_elem(list_cus,gcls[index].id,cmp_num); 
        pthread_rwlock_unlock(&lock);
            int run=1;
            while(run){
                INS ans;       
        ret = recv(fd,&ans,sizeof(INS),0);          //接受命令参数
        if(ret<=0){     //客户端异常退出   清空id  path
            run=0;
                    strcpy(gcls[index].id,"");              
                    strcpy(gcls[index].path,"");
                    break;
        }
        nixu(&ans.nn,4);                       //转网络字节序
                if(strcmp(ans.ins[0],"quit")!=0){
                 LOG_TRACE("非quit指令,进行命令处理\n");
             deal(fd,ans.nn,ans.ins,gcls[index].path);    //命令处理
            }else{     //quit指令  退出
                 LOG_TRACE("账户退出\n");
                     run=0;
                     strcpy(gcls[index].id,"");
                     strcpy(gcls[index].path,"");
                     break;
                }
            }
    }
    return 1;
}

2.客户端 client.c

#include "client.h"

char path[40];
char signin[8];
void show_new();
void newcus(int fd);
void menu();
void show_sign();
void show_file();
void tuichu(int fd);
void sign_in(int fd);
void tuia(int fd);
int connect_server(const char *ip,unsigned short int port);

int main(int argc,char *argv[]){
    if(argc < 3){
        LOG_FATAL("%s ip port\n",argv[0]);
        return -1;
    }
    pLogFile=stdout;
    strcpy(localip,argv[1]);    //保存ip
    int fd = connect_server(argv[1],atoi(argv[2]));   //连接服务器
        int ord; 
    int run=1;
    while(run){
            menu();   
            scanf("%d",&ord);
            switch(ord){
                case 1:
                newcus(fd);                           //注册
            break;
        case 2:
            sign_in(fd);                          //登录
            break;
            default:
            tuia(fd);                             //退出
                    run=0;
            break;
        }
        }
    close(fd);
    return 0;    
}

int connect_server(const char *ip,unsigned short int port){      //连接服务器
    int fd = socket(AF_INET,SOCK_STREAM,0);
    assert(fd != -1);
    struct sockaddr_in addr = {};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = inet_addr(ip);
    socklen_t len = sizeof(addr);
    int ret = connect(fd,(const struct sockaddr*)&addr,len);
    assert(ret != -1);
    return fd;
}

void show_new(){
    printf("*****请输入账号密码*****\n");
    printf("密码\n");
}

void newcus(int fd){
    int ord=1;
    nixu(&ord,sizeof(ord));       //转换网络字节序
    int ret=send(fd,&ord,sizeof(ord),0);    
    if(ret==-1){
    LOG_TRACE("%m\n");
    return;
    }
    CUS node={};
    show_new();
    strcpy(node.id,"0");
    scanf("%s",node.pass);
    ret=send(fd,&node,sizeof(node),0);
    if(ret==-1){ 
    LOG_TRACE("%m\n");
    return;            
    }
    char msg[8]={};
    ret=recv(fd,msg,8,0);
    if(ret==-1){
    LOG_TRACE("%m\n");
    return;
    }
    printf(">>>账户:%s\n",msg);    
    printf("已成功注册,请重新登录!!\n");
}

void menu(){
    printf("*****请输入功能*****\n");
    printf("1.注册\n");
    printf("2.登录\n");
    printf("0.退出\n");
}

void show_sign(){
    printf("*****请输入账号密码*****\n");
    printf("*** 账号 ");
    printf("密码 ***\n");
}

void show_file(){
    printf("%s:~/%s $",signin,path);    //模拟终端输入  账户:路径/ 指令
    fflush(stdout);
}

void sign_in(int fd){
    int ord=2;
    nixu(&ord,sizeof(ord));
    int ret=send(fd,&ord,sizeof(ord),0);
    if(ret==-1){
    LOG_TRACE("%m\n");
    return;
    }
    show_sign();
    SIGN snode={};
    printf("输入账户:\n");
    printf(">>>");
    fflush(stdout);
    scanf("%s",snode.id);
    while(getchar()!='\n');
    printf("输入密码:\n");
    printf(">>>");
    fflush(stdout);
    //scanf("%s",snode.pass);
    get_pass(snode.pass,12,true);                           //输入密码不回显
    LOG_TRACE("登录数据读取成功!\n");
    ret=send(fd,&snode,sizeof(snode),0);
    if(ret==-1){
    LOG_TRACE("%m\n");
    return;
    }
    LOG_TRACE("账户密码发送成功\n");
    CUS node={}; 
    ret=recv(fd,&node,sizeof(CUS),0);                       //接收登录结果
    if(ret==-1){
    LOG_TRACE("%m\n");
    return;
    }
    LOG_TRACE("查找节点已返回\n");
    CUS *knode=&node;
    if(strcmp(knode->id,"0")!=0){
    LOG_TRACE("登陆成功,进入业务界面\n");
    printf("*****请输入指令*****\n");
    strcpy(signin,knode->id);
    strcpy(path,"");
    int run=1;
    while(run){
        show_file();
        INS ans={};
        ans.nn = 0;
            char message_order[100];
            gets(message_order);//读入命令行
        ans.nn=message_tool(ans.ins,message_order);//转换成结构体
        nixu(&ans.nn,4);
        send(fd,&ans,sizeof(INS),0);               //命令参数发送给服务器
        nixu(&ans.nn,4);
        if(strcmp(ans.ins[0],"quit")==0){          //quit指令退出
            run=0;
            LOG_TRACE("quit正常退出登录!\n");
            strcpy(path,"");
        }else if(ans.ins[0][0]=='!'){              //!指令   系统指令调用
            char *p=message_order+1;
            system(p);
        }else{
            insdeal(fd,ans.nn,ans.ins,path);       //进行指令处理
        }
        }
        return;        
    }else{         
    printf("账户或密码不正确!\n");
    printf("ID or password is false!!!\n");
    printf("请重新登录!!!\n");
    return;
    }    
}

void tuichu(int fd){                        //账户退出
    int ord=6;
    nixu(&ord,sizeof(ord));
    int ret=send(fd,&ord,sizeof(ord),0);
    if(ret==-1){
    LOG_TRACE("%m\n");
    return;
    }           
}

void tuia(int fd){                        //客户端退出
    int ord=0;
    nixu(&ord,sizeof(ord));
    int ret=send(fd,&ord,sizeof(ord),0);
    if(ret==-1){
    LOG_TRACE("%m\n");
    return;
    }
    LOG_TRACE("退出信号:%d\n",ord);
    if(ret==-1){
    LOG_TRACE("%m\n");
    return;
    }
    printf("已退出\n");
}

3.服务器指令处理deal.c

#include "get.h"
#include"deal.h"
#include"log.h"
#include<string.h>
#include<assert.h>
#include <errno.h>
#include <assert.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <signal.h>
#include <stdbool.h>
#include <sys/sendfile.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

char localip[20];                          //ip  用于连接数据通道
unsigned short int localport;              //端口

void deal(int fd,int gc,char gv[5][20],char path[40]){
     int i=0;
     char nowpath[40]="./sfile/";
     strcat(nowpath,path);                          //账户当前路径
     if(strcmp(gv[0],"ls")==0){                     //     ls
         char messturn[1024]={};
         int ret=lsdir(nowpath,messturn);           //ls输出到messturn
         strcat(messturn,"\0");
         puts(messturn);
         if(ret==-1)
             LOG_TRACE("lsdir error!\n");
         send(fd,messturn,strlen(messturn)+1,0); 
     }else if(strcmp(gv[0],"pwd")==0){             //pwd
          char jiadepath[40];
          strcpy(jiadepath,"~/");
          strcat(jiadepath,path);
          send(fd,jiadepath,40,0);
     }else if(strcmp(gv[0],"tree")==0){           //   tree
         char messturn[1024]={};
         int ret=tree(nowpath,messturn);
         strcat(messturn,"\0");
         send(fd,messturn,strlen(messturn)+1,0); 
         puts(messturn);
         if(ret==-1)
             LOG_TRACE("tree error!\n");
     }else if(strcmp(gv[0],"cd")==0){             //   cd   
         char testpath[40];
         strcpy(testpath,nowpath);
         strcat(testpath,gv[1]);
         LOG_TRACE("当前收到的路径:%s\n",testpath);
         if(strcmp(gv[1],"~")==0){
             strcpy(path,"");
             send(fd,path,40,0);//收到~ 返回空路径
         }else{
             if(access(testpath,F_OK)==0){
                 LOG_TRACE("路径合理,寻找..和~ 简化路径\n");
                 strcat(path,gv[1]);
                 strcat(path,"/");
                 char *p=path;
                 int len=strlen(path)-1;
                 int i=0,j=0;
                 while(len>=0){
                     if(p[len]=='.'&&p[len-1]=='.'){
                         i=len-3;
                         j=len+2;
                         while(i>=0&&p[i]!='/'){
                               i--;
                         }
                         if(i<0){
                             strcpy(path,"");
                         }else{
                             i++;                         
                             while(p[j]!='\0'){
                                 p[i++]=p[j++];
                             }
                             p[i]='\0';   
                         }
                         len-=4;             
                     }else{
                         --len;
                     }
                 }
                 send(fd,path,40,0);///成功发回当前位置             
             }else{
                 LOG_TRACE("收到的路径不合理,返回error\n");
                 char messturn[20]="path error";
                 send(fd,messturn,strlen(messturn)+1,0);//失败返回路径不存在          
             }
         }   
     }else if(strcmp(gv[0],"mkdir")==0){                       //    mkdir
         char mkfilepath[40];
         strcpy(mkfilepath,nowpath);
         strcat(mkfilepath,gv[1]);
         if(mkdir(mkfilepath,0777)==0){
             char messturn[20]="success";
             send(fd,messturn,strlen(messturn)+1,0);
             LOG_TRACE("文件夹 %s 创建 成功!!! \n",mkfilepath);
         }else{
             char messturn[20]="path error";
             send(fd,messturn,strlen(messturn)+1,0);
             LOG_TRACE("文件夹 %s 创建 失败??? \n",mkfilepath);
         }
     }else if(strcmp(gv[0],"rmdir")==0){                           //    rmdir
         char rmfilepath[40];
         strcpy(rmfilepath,nowpath);
         strcat(rmfilepath,gv[1]);
         if(rmdir(rmfilepath)==0){
             char messturn[20]="success";
             send(fd,messturn,strlen(messturn)+1,0);
             LOG_TRACE("文件夹 %s 删除成功!!! \n",rmfilepath);
         }else{
             char messturn[20]="path error";
             send(fd,messturn,strlen(messturn)+1,0);
             LOG_TRACE("文件夹 %s 删除失败??? \n",rmfilepath);
         }       
     }else if(strcmp(gv[0],"get")==0){                           //   get
         char testpath[40];
         strcpy(testpath,nowpath);
         strcat(testpath,gv[1]);
         LOG_TRACE("当前收到的文件:%s\n",testpath);
         int openfd;
         openfd=open(testpath,O_RDONLY);                        //打开成功,文件存在
         if(openfd>0){
             struct stat stat_buf;
             fstat(openfd,&stat_buf);                           //获得文件大小
          localport++;
             send(fd,&localport,2,0);                           //数据通道的端口发送给客户端
             LOG_TRACE("收到的文件合理,返回合理\n");
         char messturn[20]="path success";
         send(fd,messturn,20,0);                            //成功返回路径存在 
             int nfd = socket(AF_INET,SOCK_STREAM,0);           //创建套接字 这里应该封装一下
         assert(nfd != -1);
         struct sockaddr_in addr = {};
         addr.sin_family = AF_INET;
         addr.sin_port = htons(localport);
         addr.sin_addr.s_addr = inet_addr(localip);
         socklen_t len = sizeof(addr);
         int ret = bind(nfd,(const struct sockaddr*)&addr,len);       //绑定端口
             assert(ret != -1);
         ret = listen(nfd,10);                                        //监听
         assert(ret != -1);
         LOG_TRACE("线程服务器已开启\n");         
         LOG_TRACE("ip:%s   port:%hu \n",localip,localport);
         int cfd = accept(nfd,(struct sockaddr*)&addr,&len);          //接受客户端
         send(cfd,&stat_buf.st_size,sizeof(stat_buf.st_size),0);      //发送文件大小         
         sendfile(cfd,openfd,NULL,stat_buf.st_size);                 //sendfile零拷贝读写
             strcpy(messturn,"sendsuccess");
             LOG_TRACE("%s\n",messturn);
         close(openfd);
         close(cfd);
         close(nfd);     
     }else{
         LOG_TRACE("收到的文件不合理,返回error\n");
         char messturn[20]="path error";
         send(fd,messturn,20,0);
     }              
     }else if(strcmp(gv[0],"put")==0){
         localport++;
         send(fd,&localport,2,0);                                        //发送数据通道的端口
         char *p=gv[1]+strlen(gv[1])-1;
         while(p!=&gv[1][0]&&*p!='/') --p;                         
         if(*p=='/')
         ++p;
         char testpath[40]={};
         strcpy(testpath,nowpath);
         strcat(testpath,p);                                             //获得文件名
         LOG_TRACE("当前收到的文件:%s\n",testpath);
         int openfd;
         char messturn[20]={};
     recv(fd,messturn,20,0);
     if(strcmp(messturn,"path success")==0){
            openfd=open(testpath,O_WRONLY|O_CREAT|O_EXCL,0644);      
                                     //创建文件 已存在则失败
        if(openfd>0){
            LOG_TRACE("成功创建文件\n");
            char messturn[20]="open success";
                send(fd,messturn,20,0);
            LOG_TRACE("收到的文件合理,返回合理\n");
            int nfd = socket(AF_INET,SOCK_STREAM,0);            //创建套接字
            assert(nfd != -1);                                  //这里应该封装一下
            struct sockaddr_in addr = {};
            addr.sin_family = AF_INET;
            addr.sin_port = htons(localport);
            addr.sin_addr.s_addr = inet_addr(localip);
            socklen_t len = sizeof(addr);
            int ret = bind(nfd,(const struct sockaddr*)&addr,len);   //绑定端口
            assert(ret != -1);
            ret = listen(nfd,10);                                    //监听
                assert(ret != -1);
            LOG_TRACE("线程服务器已开启\n");         
            LOG_TRACE("ip:%s   port:%hu \n",localip,localport);         
            int cfd = accept(nfd,(struct sockaddr*)&addr,&len);      //接收客户端
            size_t st_size=0;
            recv(cfd,&st_size,sizeof(size_t),0);                     //接受文件大小
            char data[1024]={};
            while(st_size>0){
                    size_t recv_size=recv(cfd,data,1024,0);
                st_size-=recv_size;
                write(openfd,data,recv_size);
            }                                                        //接收文件
            puts("get success");           
            close(openfd);
            close(cfd);
                close(nfd);
         }else{
                LOG_TRACE("收到的文件名已存在\n");
                char messturn[20]="Already exists";
                send(fd,messturn,20,0);          
         }  
       }
    }else if(strcmp(gv[0],"rm")==0){                             //    rmdir
         char rmfilepath[40];
         strcpy(rmfilepath,nowpath);
         strcat(rmfilepath,gv[1]);
         if(remove(rmfilepath)==0){
             char messturn[20]="success";
             send(fd,messturn,strlen(messturn)+1,0);
             LOG_TRACE("文件 %s 删除成功!!! \n",rmfilepath);
         }else{
             char messturn[20]="path error";
             send(fd,messturn,strlen(messturn)+1,0);
             LOG_TRACE("文件 %s 删除失败??? \n",rmfilepath);
         } 
    }
}

4.客户端指令处理insdeal.c

#include"insdeal.h"
#include"log.h"
#include "get.h"
#include<string.h>
#include<assert.h>
#include <errno.h>
#include <assert.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <signal.h>
#include <sys/sendfile.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

char localip[20];                          //保存IP

void insdeal(int fd,int gc,char gv[5][20],char path[40]){
     if(strcmp(gv[0],"ls")==0||strcmp(gv[0],"tree")==0){         //     ls    tree
         char messturn[1024]={};
         recv(fd,messturn,1024,0);
         printf("~/");
         puts(path);
         puts(messturn);
     }else if(strcmp(gv[0],"pwd")==0){                     //pwd
          char jiadepath[40];
          recv(fd,jiadepath,40,0); 
          puts(jiadepath);   
     }else if(strcmp(gv[0],"help")==0){                   //help
         printf("可选指令:\npwd   ls  tree  mkdir  rmdir  rm  cd  get  put  quit\n");             
     }else if(strcmp(gv[0],"cd")==0){                     //cd
         recv(fd,path,40,0);
         if(strcmp(path,"path error")==0)
              puts(path);
     }else if(strcmp(gv[0],"mkdir")==0){                  //mkdir
         char messturn[20]={};
         recv(fd,messturn,20,0);
         if(strcmp(messturn,"path error")==0)
             puts(messturn);
     }else if(strcmp(gv[0],"rmdir")==0){                  //rmdir
         char messturn[20]={};
         recv(fd,messturn,20,0);
         if(strcmp(messturn,"path error")==0)
             puts(messturn); 
     }else if(strcmp(gv[0],"rm")==0){                     //rm
         char messturn[20]={};
         recv(fd,messturn,20,0);
         if(strcmp(messturn,"path error")==0)
             puts(messturn);                       
     }else if(strcmp(gv[0],"get")==0){                    //get
         unsigned short int localport=0;
         recv(fd,&localport,2,0);                         //接受数据通道端口
         char messturn[20]={};
         recv(fd,messturn,20,0);
         if(strcmp(messturn,"path success")==0){         //文件存在
         char nowpath[40]="./cfile/";
             strcat(nowpath,gv[1]);
         int openfd;
         openfd=open(nowpath,O_WRONLY|O_CREAT,0664);   //创建文件  已存在就覆盖
         if(openfd<=0){
                 printf("open error\n");
         return;
         } 
         int nfd = socket(AF_INET,SOCK_STREAM,0);      //创建套接字   这里应该封装
         assert(nfd != -1);
         struct sockaddr_in addr = {};
         addr.sin_family = AF_INET;
         addr.sin_port = htons(localport);
         addr.sin_addr.s_addr = inet_addr(localip);
         socklen_t len = sizeof(addr);        
         LOG_TRACE("ip:%s   port:%hu \n",localip,localport);
         int ret = connect(nfd,(const struct sockaddr*)&addr,len);   //连接服务器
         assert(ret != -1);
         size_t st_size=0;
             recv(nfd,&st_size,sizeof(size_t),0);
         char data[1024]={};
         while(st_size>0){
                size_t recv_size=recv(nfd,data,1024,0);
            st_size-=recv_size;
            write(openfd,data,recv_size);
         }                              //接收文件
         puts("get success");
             close(openfd);
         close(nfd);
         }else{
         puts("NO such file!");
              return;
          }
    }else if(strcmp(gv[0],"put")==0){
         unsigned short int localport=0;
         recv(fd,&localport,2,0);                                     //接受数据通道端口
         char testpath[40]="./cfile/";
         strcat(testpath,gv[1]);
         int openfd;
         openfd=open(testpath,O_RDONLY);                            //文件存在
         if(open>0){
             char messturn[20]="path success";
         send(fd,messturn,20,0);          
         struct stat stat_buf;
         fstat(openfd,&stat_buf);
         recv(fd,messturn,20,0);
         if(strcmp(messturn,"Already exists")==0){         //服务器已存在该文件名
                 printf("Already exists");
                 return;    
         }         
             int nfd = socket(AF_INET,SOCK_STREAM,0);          //创建套接字  这里应该封装
         assert(nfd != -1);
         struct sockaddr_in addr = {};
         addr.sin_family = AF_INET;
         addr.sin_port = htons(localport);
         addr.sin_addr.s_addr = inet_addr(localip);
         socklen_t len = sizeof(addr);        
         LOG_TRACE("ip:%s   port:%hu \n",localip,localport);
         int ret = connect(nfd,(const struct sockaddr*)&addr,len);      //连接服务器
            assert(ret != -1);    
            send(nfd,&stat_buf.st_size,sizeof(stat_buf.st_size),0); //发送文件大小 
            sendfile(nfd,openfd,NULL,stat_buf.st_size);                //发送文件
            strcpy(messturn,"sendsuccess");
            LOG_TRACE("%s\n",messturn);   
            close(openfd);
            close(nfd);
        }else{
            char messturn[20]="path error";
        send(fd,messturn,20,0);
            puts(messturn);      
        }
     }            
}

5.服务器调用的lsdir()、tree() get.c

#include "get.h"
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>

int lsdir(const char *path,char messturn[1024]){     //输出到数组
    struct stat st = {};
    int ret = stat(path,&st);
    if(ret == -1){
        printf("%m\n");
        return -1;
    }
    if(S_ISDIR(st.st_mode)){//是目录
        DIR *dir = opendir(path);//打开目录
        if(dir == NULL){
            printf("open %s failed! %m\n",path);
            return -1;
        }
        struct dirent *pd = NULL;
        int i = 0;
        while((pd = readdir(dir)) != NULL){//读取目录中条目
            strcat(messturn,pd->d_name);

            ++i;
            if(i%2==0){
                strcat(messturn,"\n");
            }else{
                int namelen=strlen(pd->d_name);
                for(i=0;i<28-namelen;i++){
                   strcat(messturn," ");
                }

            }
        }
        strcat(messturn,"\n");
        closedir(dir);
    }else{
        printf("%s not a dirent!\n",path);
        return -1;
    }
}

int tree_a(const char *path,int deep,char messturn[1024]){
    int i;
    for(i=0;i<deep;i++){
        strcat(messturn," ");
    }
    if(deep > 0){
        const char *s = path+strlen(path)-1;
        while(*s != '/'){
            --s;    
        }
        strcat(messturn,s);
        strcat(messturn,"\n");
    }else{
        strcat(messturn,"\n");
    }
    DIR *dir = opendir(path);
    if(dir == NULL)
        return -1;
    struct dirent *pd = NULL;
    while((pd = readdir(dir))!=NULL){
        if(pd->d_type == DT_DIR){//目录
            if(strcmp(pd->d_name,".")==0||strcmp(pd->d_name,"..")==0){
                continue;    
            }
            char npath[256] = {};
            strcpy(npath,path);
            strcat(npath,"/");
            strcat(npath,pd->d_name);
            tree_a(npath,deep+4,messturn);       //是文件夹  递归
        }else{//普通文件
            for(i=0;i<deep+4;i++){
               strcat(messturn," ");
            }
            strcat(messturn,pd->d_name);
            strcat(messturn,"\n");
        }
    }
}

int tree(char gv[],char messturn[1024]){
    struct stat st = {};
    if(stat(gv,&st)==-1){
        perror("stat:");    
        return -1;
    }
    if(S_ISDIR(st.st_mode)){                               //是否是文件夹
        tree_a(gv,0,messturn);
    }else{
        printf("%s not dirent!\n",gv);    
    }
    return 0;    
}

6.服务器载入/保存数据 file.c

#include"file.h"
#include"doublelist.h"
#include"v.h"
#include"tool.h"
#include"log.h"

int load_cus(){
    int fd=open("./data/custom.txt",O_RDONLY);
    if(fd!=-1){    
        //LOG_TRACE("载入:custom.txt open成功\n");
        int listsize;
        int ret=read(fd,&listsize,sizeof(listsize));
        LOG_TRACE("载入:链表大小:%d载入成功\n",listsize);
        if(ret!=-1){
            int i=0;
            for(;i<listsize;i++){
                struct custom pp;
                read(fd,&pp,CUSIZE);
                int ret=end_insert(list_cus,&pp);
                if(ret==-1){
                    LOG_TRACE("载入:加载插入链表失败\n");
                    return -1;
                }
                LOG_TRACE("账户:%s  密码:%s 读取成功\n",pp.id,pp.pass);
            }
        }
        close(fd);
    }
}



int save_cus(){
    int fd=open("./data/custom.txt",O_WRONLY|O_CREAT,0664);
    //LOG_TRACE("保存:custom.txt open成功\n");
        if(fd==-1){
            LOG_TRACE("%m\n");
            return -1;
        }
    int listsize;
    listsize=list_cus->size;
    int ret=write(fd,&listsize,sizeof(listsize));
    LOG_TRACE("保存:链表大小:%d保存成功\n",listsize);
    if(ret==-1){
        printf("%m\n");
        return -1;
    }
    struct Node* node=list_cus->head->next;
    for(;node!=list_cus->head;node=node->next){
        CUS *pp=node->elem;
        write(fd,pp,CUSIZE);
        LOG_TRACE("%s  %s 写入成功\n",pp->id,pp->pass);
    }
    destory(list_cus);
    close(fd);
}

int load_num(){
    int fd=open("./data/number.txt",O_RDONLY);
    if(fd!=-1){
        //LOG_TRACE("载入:number.txt open成功\n");
        int    ret=read(fd,num,8);
        if(ret!=-1){
            LOG_TRACE("载入:num[8]:%s载入成功!\n",num);
            close(fd); 
        }
    }       
}

int save_num(){
    int fd=open("./data/number.txt",O_WRONLY|O_CREAT,0664);
        if(fd==-1){
            LOG_TRACE("%m\n");
            return -1;
        }
    LOG_TRACE("保存:number.txt open成功\n");    
    int len=strlen(num)+1;
    int ret=write(fd,num,len);
    LOG_TRACE("num[8]:%s保存成功\n",num);
    if(ret==-1){
        LOG_TRACE("%m\n");
        return -1;
    }
    close(fd);
}

7.小工具 tool.c

#include"tool.h"

char* get_pass(char* pass,size_t len,bool flag){       //输入密码不回显
     fflush(stdin);
     size_t index = 0;
     while(index < len)
     {
          char key = getch();
          if(127== key){
               if(index > 0){
                    index--;
                    if(flag) printf("\b \b");
               }
               continue;
          }
          if('\n' == key) break;
          pass[index++] = key;
          if(flag) printf("*");
     }
     pass[index] = '\0';
     printf("\n");
     return pass;
}

int message_tool(char mess[5][20],char ord[100]){     //将命令行拆分成字符串组
     int i=0,j=0;
     char *p=ord;
     while(*p!='\0'){
         if(*p==' '){
            mess[i][j]='\0';
            j=0;
            ++i;
         }else{
            mess[i][j]=*p;
            ++j;
         }
         ++p;
     }
     mess[i][j]='\0';
     return i+1;
}

void add(char *a,char *b){                //字符串数字 a=a+b  
        int len1=strlen(a);
    int len2=strlen(b);
    int ll=len1>len2?(len1+1):(len2+1);
    char cc[ll];
    int i=0; 
    int flag=0;
    len1--;len2--;
    while(len1>=0||len2>=0){
            if(len1>=0&&len2>=0){
               char cur=a[len1]+b[len2]+flag-'0';
               if(cur>'9'){
                  cc[i++]=cur-10;
                  flag=1;
           }else{
           cc[i++]=cur;
           flag=0;
           }
           len1--;len2--; 
        }else if(len1>=0){
            char cur=a[len1]+flag;
        if(cur>'9'){
            cc[i++]='0';
            flag=1;
            }else{
                cc[i++]=cur;
            flag=0;
        }
        len1--;
        }else if(len2>=0){
            char cur=b[len2]+flag;
            if(cur>'9'){
                cc[i++]='0';
                flag=1;
            }else{
                cc[i++]=cur;
                flag=0;
            }
            len2--;
        }
    }
    if(flag==1){
        cc[i]='1';
    }else{
        i--;
        }
        int j=0;
    while(i>=0){
            a[j++]=cc[i--];
    }
        a[j]='\0';
}

void ddd(char *a,char *b){               //字符串数字 a=a-b
        int len1=strlen(a);
    int len2=strlen(b);
    int ll=len1+1;
    char cc[ll];
    int i=0; 
    int flag=0;
    len1--;len2--;
    while(len1>=0){
            if(len1>=0&&len2>=0){
               char cur=a[len1]-b[len2]+'0'-flag;
               if(cur<'0'){
                  cc[i++]=cur+10;
                  flag=1;
           }else{
           cc[i++]=cur;
           flag=0;
           }
           len1--;len2--; 
           }else if(len1>=0){
            char cur=a[len1]-flag;
                if(cur<'0'){
                cc[i++]='9';
            flag=1;
            }else{
            cc[i++]=cur;
            flag=0;
            }
                len1--;
       }
        }    
    if(cc[--i]=='0'){
        --i;
    }
        int j=0;
    while(i>=0){
        a[j++]=cc[i--];
    }
    a[j]='\0';
}

int vs(char *a,char *b){          //字符串数字  a-b
    int len1=strlen(a);
    int len2=strlen(b);
    if(len1-len2!=0)
     return len1-len2;
    while(*a==*b&&*a!='\0'&&*b!='\0'){
        ++a;++b;
    }
    return *a-*b;
}

void nixu(void *p,int len){           //字节序转换  好像不需要  有函数可以直接调用
    char a;
    char *pp=(char *)p;
    int i=0;
    while(i<len-1&&len-1>=0){
         a=pp[i];
         pp[i]=pp[len-1];
         pp[len-1]=a;
         ++i;
         --len;
    }    
}

8.变量初始化 结构体定义 v.c v.h (下次可不能取这种“导见打”的文件名了)

v.c

#include"v.h"

Doublelist list_cus=NULL;
char num[8]="2106001";

v.h

#ifndef _V_H_
#define _V_H_

#include"doublelist.h"
#include <sys/epoll.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

typedef struct custom{
        char id[8];
        char pass[12];
}CUS;

typedef struct ins{
        int nn;
        char ins[5][20];
}INS;

typedef struct sign{
        char id[8];
        char pass[12];
}SIGN;

typedef struct Client{
    int fd;
    struct sockaddr_in addr;
    char id[8];
    char path[40];
}Client;

#define NO_LEN 8
#define MAX_CLIENTS 100
#define MSG_LEN 1024
#define CUSIZE sizeof(struct custom)
extern Doublelist list_cus;
extern char num[8];

#endif

9.双向循环链表 doublelist.c doublielist.h 其实(绝)大部分功能都用不到

doublelist.c

#include"doublelist.h"

 //创建循环双链表,头节点head 
Doublelist list_init(int elemsize){
    Doublelist list=(Doublelist)malloc(sizeof(struct Doublelist)); 
    if(list==NULL)
        return NULL;
    list->head=(struct Node*)malloc(NODE);    
    if(list->head==NULL){
        free(list);
        return NULL;
    }
    list->head->next=list->head;
    list->head->prev=list->head;
    list->elemsize=elemsize;
    list->size=0; 
    return list;
}
//判断循环双链表是否为空 
bool is_empty(Doublelist list){
    return list->size==0;
}
//循环双链表元素个数 
int num_element(Doublelist list){
    return list->size;
}
static struct Node* front_find(Doublelist list,size_t pos){
    if(list==list->head&&list->head==list->head)
          return NULL; 
    struct Node* node=list->head;
    while(pos-->0&&node->next!=list->head){
        node=node->next;
    }
    return node;
}
static struct Node* back_find(Doublelist list,size_t pos){
    if(list==list->head&&list->head==list->head)
          return NULL; 
    struct Node* node=list->head;
    while(pos-->0&&node->prev!=list->head){
        node=node->prev;
    }
    return node;
}
//从前往后,在指定位置pos,插入元素 elem 
int front_insert(Doublelist list,size_t pos,void *pelem){
    struct Node* node=(struct Node*)malloc(NODE);
    if(node==NULL)
        return -1;
    struct Node* prev=front_find(list,pos);
    if(prev==NULL)
        return-2;    
    node->elem=(void *)malloc(list->elemsize);
    if(node->elem==NULL){
        free(node);
        return -1;
    } 
    memcpy(node->elem,pelem,list->elemsize);
    node->next=prev->next;
    node->next->prev=node;
    node->prev=prev;
    prev->next=node;
    list->size++;
    return 0;
}
//从后往前,在指定位置pos,插入元素 elem 
int back_insert(Doublelist list,size_t pos,void *pelem){

    struct Node* next=back_find(list,pos);
    if(next==list->head)
        return-2;    
    struct Node* node=(struct Node*)malloc(NODE);
    if(node==NULL)
        return -1;    
    node->elem=(void *)malloc(list->elemsize);
    if(node->elem==NULL){
        free(node);
        return -1;
    }         
    memcpy(node->elem,pelem,list->elemsize);
    node->prev=next->prev;
    node->prev->next=node;
    node->next=next;
    next->prev=node;
    list->size++;
    return 0;        
}
//在开头加入一个元素 elem 
int first_insert(Doublelist list,void *pelem){
    struct Node* node=(struct Node*)malloc(NODE);
    if(node==NULL)
        return -1;    
    node->elem=(void *)malloc(list->elemsize);
    if(node->elem==NULL){
        free(node);
        return -1;
    }         
    memcpy(node->elem,pelem,list->elemsize);
    node->next=list->head->next;
    node->next->prev=node;
    node->prev=list->head;
    list->head->next=node;    
    list->size++;        
    return 0;
}
//在末尾加入一个元素 elem 
int end_insert(Doublelist list,void *pelem){
    struct Node* node=(struct Node*)malloc(NODE);
    if(node==NULL)
        return -1;    
    node->elem=(void *)malloc(list->elemsize);
    if(node->elem==NULL){
        free(node);
        return -1;
    }         
    memcpy(node->elem,pelem,list->elemsize);
    node->prev=list->head->prev;
    node->prev->next=node;
    node->next=list->head;
    list->head->prev=node;    
    list->size++;    
    return 0;    
}
//从前往后,删除指定位置pos 的元素elem
int front_dele(Doublelist list,size_t pos,void *pelem){
    struct Node* prev=front_find(list,pos);
    if(prev==list->head)
        return-2; 
    struct Node* node=prev->next;   
    memcpy(pelem,prev->next->elem,list->elemsize);
    free(prev->next->elem);
    prev->next=prev->next->next;
    prev->next->prev=prev;
    free(node);
    list->size--;
    return 0;    
}
//从后往前,删除指定位置pos 的元素elem
int back_dele(Doublelist list,size_t pos,void *pelem){
    struct Node* back=back_find(list,pos);
    if(back==list->head)
        return-2; 
    struct Node* node=back->prev;   
    memcpy(pelem,node->elem,list->elemsize);
    free(node->elem);
    back->prev=node->prev;
    back->prev->next=back;
    free(node);
    list->size--;
    return 0;      
}
//删除首元素 elem
int first_dele(Doublelist list,void *pelem){
    if(list->head==list->head||list->head->next==list->head)
        return -1;
    memcpy(pelem,list->head->next->elem,list->elemsize);
    free(list->head->next->elem);
    list->head->next=list->head->next->next;
    free(list->head->next->prev);
    list->head->next->prev=list->head;
    list->size--;
    return 0;
}
//删除末尾元素 elem
int end_dele(Doublelist list,void *pelem){
    if(list->head==list->head||list->head->prev==list->head)
        return -1;
    memcpy(pelem,list->head->prev->elem,list->elemsize);
    free(list->head->prev->elem);
    list->head->prev=list->head->prev->prev;
    free(list->head->prev->next);
    list->head->prev->next=list->head;
    list->size--;
    return 0;
}
//从前往后,获取指定位置pos 的元素elem
int front_get(Doublelist list,size_t pos,void* pelem){
    struct Node* node=front_find(list,pos);
    if(node==list->head)
       return 1;
    memcpy(pelem,node->next->elem,list->elemsize);
    return 0;
}
//从后往前,获取指定位置pos 的元素elem
int back_get(Doublelist list,size_t pos,void *pelem){
    struct Node* node=back_find(list,pos);
    if(node==list->head)
       return 1;
    memcpy(pelem,node->prev->elem,list->elemsize);
    return 0;    
}
//获取第一个元素
int first_get(Doublelist list,void *pelem){
    if(list->head==list->head||list->head->next==list->head)
       return -1;
    memcpy(pelem,list->head->next->elem,list->elemsize);
    return 0;
}
//获得最后一个元素
int  end_get(Doublelist list,void *pelem){
    if(list->head==list->head||list->head->prev==list->head)
      return -1;
    memcpy(pelem,list->head->prev->elem,list->elemsize);
    return 0;    
}
//根据值elem来查找   返回-1/NULL表示没有该值  否则返回位置 
struct Node* find_elem(Doublelist list,void *pelem,int (*cmp)(const void *,const void *)){
    struct Node* node=list->head->next;
    int i=0;
    while(node!=list->head){
        if(cmp(pelem,node->elem)==0)
            return node;
        i++;    
         node=node->next;
    }
    return NULL;
}
int find_elem_num(Doublelist list,void* pelem,int (*cmp)(const void *,const void *)){
        struct Node* node=list->head->next;
    int i=0;
    while(node!=list->head){
        if(cmp(pelem,node->elem)==0)
            return i;
        i++;    
         node=node->next;
    }
    return -1;        
}
int find_nelem(Doublelist list,void* pelem,int n,int (*cmp)(const void *,const void *)){
    struct Node* node=list->head->next;
    int i=0;
    while(n>0&&node!=list->head){
        if(cmp(pelem,node->elem)==0)
             n--;
        i++;    
         node=node->next;
    }
    if(n>0)
       return -1;
    else
       return i;
}
//遍历 
void travel(Doublelist list,int flag,void (*tra)(const void *)){
    if(list==NULL||list->head==NULL)
        return;
    struct Node* node=list->head->next;
    if(flag==0){
        while(node!=list->head){
            tra(node->elem);
            node=node->next;
        }
    }else{
        while(node!=list->head){
            tra(node->elem);
            node=node->prev;
        }
    }    
}
//清除所有元素 
void clear(Doublelist list){
    if(list->head==NULL||list->head->next==NULL)
        return;
    struct Node* node=list->head->next; 
    struct Node* next;
    while(node!=list->head){
    next=node->next;
    free(node->elem);
    free(node);
    node=next;
    }
    list->head->next=list->head;
    list->size=0;
    return;  
}
//销毁循环双链表
void destory(Doublelist list){
    clear(list);
    free(list->head);
    free(list);
    return;
} 

doublelist.h

#ifndef _DOUBLELIST_H_
#define _DOUBLELIST_H_

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<string.h>

#define NODE sizeof(struct Node) 

struct Node{
    void* elem;
    struct Node *prev;
    struct Node *next;
};

typedef struct Doublelist{
    struct Node* head;
    int elemsize;
    size_t size;
}*Doublelist; 

 //创建循环双链表,头节点head 
Doublelist list_init(int elemsize);

//判断循环双链表是否为空 
bool is_empty(Doublelist list);

//循环双链表元素个数 
int num_element(Doublelist list);

//从前往后,在指定位置pos,插入元素 elem 
int front_insert(Doublelist list,size_t pos,void *pelem);
//从后往前,在指定位置pos,插入元素 elem 
int back_insert(Doublelist list,size_t pos,void *pelem);
//在开头加入一个元素 elem 
int first_insert(Doublelist list,void *pelem);
//在末尾加入一个元素 elem 
int end_insert(Doublelist list,void *pelem);

//从前往后,删除指定位置pos 的元素elem
int front_dele(Doublelist list,size_t pos,void *pelem);
//从后往前,删除指定位置pos 的元素elem
int back_dele(Doublelist list,size_t pos,void *pelem); 
//删除首元素 elem
int first_dele(Doublelist list,void *pelem); 
//删除末尾元素 elem
int end_dele(Doublelist list,void *pelem); 

//从前往后,获取指定位置pos 的元素elem
int front_get(Doublelist list,size_t pos,void *pelem);
//从后往前,获取指定位置pos 的元素elem
int back_get(Doublelist list,size_t pos,void *pelem);
//获取第一个元素
int first_get(Doublelist list,void *pelem); 
//获得最后一个元素
int  end_get(Doublelist list,void *pelem);

//根据值elem来查找   返回-1表示没有该值  否则返回位置 
struct Node* find_elem(Doublelist list,void* pelem,int (*cmp)(const void *,const void *));
int find_elem_num(Doublelist list,void* pelem,int (*cmp)(const void *,const void *));

//查找第n个 elem   
int find_nelem(Doublelist list,void* pelem,int n,int (*cmp)(const void *,const void *)); 

//遍历 
void travel(Doublelist list,int flag,void (*tra)(const void *));

//清除所有元素 
void clear(Doublelist list);

//销毁循环双链表
void destory(Doublelist list); 

#endif

10.log日志打印 log.c log.h (导子哥教的东西要学会用)

log.c

#include "log.h" 

FILE *pLogFile =NULL;
char time_buf[TIME_BUF_LEN] = {};
char local_time_buf[TIME_BUF_LEN] = {};
char* time_to_str(time_t *t){
    memset(time_buf,0,TIME_BUF_LEN);
    struct tm *tm = localtime(t);
    sprintf(time_buf,"%4d-%02d-%02d %02d:%02d:%02d ",
        tm->tm_year+1900,tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec);
    return time_buf;
}

log.h

#ifndef _LOG_H__
#define _LOG_H__

#include <stdio.h>
#include <time.h>
#include <string.h>

enum LogLevel{TRACE=0,DEBUG,INFO,WARN,ERROR,FATAL};
#define LOG_LEVEL TRACE       //可更改日志级别
#define TIME_BUF_LEN  48

extern FILE* pLogFile;
extern char time_buf[TIME_BUF_LEN];
extern char local_time_buf[TIME_BUF_LEN];
char* time_to_str(const time_t *t);
static inline char* local_time_str(){
    time_t t = time(NULL);
    memset(local_time_buf,0,TIME_BUF_LEN);
    struct tm *tm = localtime(&t);
    sprintf(local_time_buf,"%4d-%02d-%02d %02d:%02d:%02d ",
        tm->tm_year+1900,tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec);
    return local_time_buf;
}
//不定长宏函数 
#define LOG_TRACE(fmt, args...) \
    if(LOG_LEVEL<=TRACE){ \
        fprintf(pLogFile,"%s [trace] %s:%d "fmt,\
        local_time_str(), __FILE__, __LINE__, ##args);\
    }
#define LOG_DEBUG(fmt, args...) \
    if(LOG_LEVEL<=DEBUG){\
        fprintf(pLogFile,"%s [debug] %s:%d "fmt,\
        local_time_str(), __FILE__, __LINE__, ##args);\
    }
#define LOG_INFO(fmt, args...) \
    if(LOG_LEVEL<=INFO){\
        time_t t = time(NULL);\
        fprintf(pLogFile,"%s [info  ] %s:%d "fmt,\
        local_time_str(), __FILE__, __LINE__, ##args);\
    }
#define LOG_WARN(fmt, args...) \
    if(LOG_LEVEL<=WARN){\
        fprintf(pLogFile,"%s [warn  ] %s:%d "fmt,\
        local_time_str(), __FILE__, __LINE__, ##args);\
    }
#define LOG_ERROR(fmt, args...) \
    if(LOG_LEVEL<=ERROR){\
        fprintf(pLogFile,"%s [error] %s:%d "fmt,\
        local_time_str(),__FILE__, __LINE__, ##args);\
    }
#define LOG_FATAL(fmt, args...)  \
    if(LOG_LEVEL<=FATAL){\
        fprintf(pLogFile,"%s [fatal] %s:%d "fmt,\
        local_time_str(), __FILE__, __LINE__, ##args);\
    }

#endif //_LOG_H__ 

11.最后是头文件

deal.h

#ifndef _DEAL_H_
#define _DEAL_H_

void deal(int fd,int gc,char gv[5][20],char path[40]);
extern char localip[20];
extern unsigned short int localport;

#endif

server.h 这个似乎好像大概完全没有必要

#ifndef _SERVER_H_
#define _SERVER_H_

#include"doublelist.h"
#include"v.h"
#include"tool.h"
#include"log.h"
#include"file.h"
#include"deal.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <signal.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdbool.h>
#include <sys/types.h>

#endif

insdeal.h

#ifndef _INSDEAL_H_
#define _INSDEAL_H_

void insdeal(int fd,int gc,char gv[5][20],char path[40]);
extern char localip[20];

#endif

client.h 这个也似乎好像大概完全没有必要

#ifndef _CUSTOM_H_
#define _CUSTOM_H_

#include"doublelist.h"
#include"v.h"
#include"tool.h"
#include"log.h"
#include"file.h"
#include"insdeal.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <signal.h>

#endif

get.h

#ifndef _GET_H_
#define _GET_H_

int lsdir(const char *path,char messturn[1024]);
int tree(char gv[],char messturn[1024]);

#endif

tool.h

#ifndef _TOOL_H_
#define _TOOL_H_

#include<stdio.h>
#include<string.h>
#include<stdbool.h>
#include<getch.h>

void add(char* a,char *b);
void ddd(char* a,char *b);
int vs(char *a,char *b);
void nixu(void *p,int len);
char* get_pass(char* pass,size_t len,bool flag);
int message_tool(char mess[5][20],char ord[100]);

#endif

file.h

#ifndef _FILE_H_
#define _FILE_H

#include<fcntl.h>

int load_cus(void);
int save_cus(void);
int load_num(void);
int save_num(void);

#endif

12.一个不成熟的总结

冗余很多,逻辑不够严谨,定个小目标,模拟ftp的客户端和服务器
by:璇玑

全部评论

相关推荐

mq2:我倒是觉得这种敞亮一点好。能接受就去不能就不去呗。 完了跟现在“正常”公司一样,hr说的天花乱坠,进去一看根本就是996核动力牛马,想走又没应届生身份了。岂不是更糟。
点赞 评论 收藏
分享
希望被捞的猫头鹰很理智:大概率待遇低怕硕士跑路
点赞 评论 收藏
分享
评论
1
2
分享

创作者周榜

更多
牛客网
牛客企业服务