• 【文件传输】查找等相关命令


    1.查看:通过客户端查看服务器端都有哪些文件?
    (删除,重命名)
    2.下载 :(显示下载百分比)断点续传
    3.上传
    客户端发送命令信号,服务器进行执行,并回复客户端。
    将命令的名字作为协议。

    查找

    实现方式:

    1. 通过自己实现获取当前目录下有哪些文件,然后组装,发给客户端。(当客户端发送对应得查看命令)
      比如 利用扫描目录(opendir/readdir)设计ls得过程。
    2. 直接调用系统已有得命令,比如ls 获取当前目录下得文件。(灵活性很高)直接通过fork+exec(),立即生成可执行程序。通过修改进程的实体部分,就可以扩展系统中ps/ls没有的功能。
      不需要改服务器的代码,来更迭版本。

    第二种方式实现原理:

    先创建管道(用于父子进程间通信,传递数据(ls后显示的结果)),再fork产生子进程,在子进程中,用管道的写端覆盖标准输出(将管道的写端使用dup覆盖标准输出 )(标准输出的数据,客户端得不到)
    , 在把子进程替换成要执行的命令,当客户端发送这个命令,管道就会写入数据,ji紧接着父进程,从管道中读取数据,发送给客户端。(多个子进程就可以执行多个命令)
    举个栗子:因为比如,客户端发送的命令是ls -l,我要使用系统已经有的ls,但是系统的ls,会直接标准输出(标准输出的数据,客户端得不到),所以需要使用管道的写端把标准输出覆盖掉,(管道的写端在子进程中),就相当于把ls的获取的数据写入管道中,让父进程来读取就可以了,(需要建立socket连接)再发给客户端,从而也就用客户端发来的命令,获取要查看的数据。

    特殊:

    rm删除数据后,是没有数据写入管道中的,因此没有数据,我们必须给客户端一个数据。有数据,反馈客户端还有多少数据。
    实现
    文件:
    服务器端:请添加图片描述
    makefile:(文件编译工具,自己去写)
    my_conf:(配置文件):设置ip和端口
    ser.c:获取连接套接字,完成客户端和服务器端的链接。并启动线程。
    socket.c:获取配置文件中的ip和端口,创建套接字,设置端口,获取监听队列上的监听套接字,返回给ser.c
    thread.c:创建一个线程函数,通过对客户端发来的命令进行解析,对客户端进行回复。

      if(cmd == NULL)
              {
                     send(c,CMD_ERR,strlen(CMD_ERR),0);
                      continue;
              }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    (将管道的写端使用dup覆盖标准输出 )

    对客户端发来命令的处理步骤:

    • 解析命令以及参数
    • 参数检查
    • 判断是不是命令 --fork +exec
    • get == 代表下载 – 自己实现函数 downfile()
    • up == 代表上传 – recv
    //解析命令
    char * get_cmd(char buff[],char* myargv[])
    {
        if ( buff == NULL || myargv == NULL )
        {
            return NULL;
        }
    
        char * s = strtok(buff," ");
        int i = 0;
        while( s != NULL )
        {
            myargv[i++] = s;
            s = strtok(NULL," ");
        }
    
        return myargv[0];
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    服务器端

    socket.h

    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    
    int socket_init();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    thread.h

    #include
    #include
    #include
    #include
    #include
    #include
    void start_thread(int c);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    ser.c

    #include "socket.h"
    #include "thread.h"
    
    int main()
    {
      int sockfd = socket_init();  //获取监听队列
      if(sockfd == -1)
      {
              printf("create socket err\n");
              exit(0);
    
      }
      struct sockaddr_in caddr;
      while(1)
      {
              int len = sizeof(caddr);
              int c =  accept(sockfd,(struct sockaddr*)&caddr,&len);
              if(c < 0)
              {
                    continue;
              } 
              printf("accept c =%d\n",c);
              //启动线程
              start_thread(c);
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    socket.c

    #include  "socket.h"
    
    #define   IPS     "ipstr="
    #define   PORT    "port="
    #define   LISMAX  "lismax="
    struct sock_info
    {
        char ips[32];//用来存放从配置文件中获取的ip地址,端口,以及listen能获取的监听套接子的个数
        short port;
        short lismax; 
    };
    int read_conf(struct sock_info *pa)//设置配置文件ip port lismax
    {
        if(pa == NULL)
        {
            return -1;
        }
      FILE *fp = fopen("my.conf","r");//只读方式打开
      if(fp == NULL)
      {
              printf("my.conf not exist\n");
              return -1;
      }
      char buff[128] = {0};
      int index = 0;
      while(fgets(buff,128,fp) != NULL)//打开my_conf,如果不为空,获取文件中数据
      {    
            index++;
            if(strncmp(buff,"#",1)==0)
            {
                    continue;
            }
            if(strncmp(buff,"\n",1)==0)
            {
                    continue;
            }
             buff[strlen(buff)-1] = '\0';
            //判断ip
            if(strncmp(buff,IPS,strlen(IPS)) == 0)
            {
                       strcpy(pa->ips,buff+strlen(IPS));
            }
            //判断端口
            else if(strncmp(buff,PORT,strlen(PORT))==0)
            {
                    pa->port = atoi(buff+strlen(PORT)); 
             }
    
             else if(strncmp(buff,LISMAX,strlen(LISMAX)) == 0)
             {
             pa->lismax = atoi(buff+strlen(LISMAX));
             }
             else
             {
                    printf("未识别的配置%d行:%s\n",index,buff);
                    }
      }
      fclose(fp);
    }
    
    
    int socket_init()
    {
        struct sock_info a;
       if(read_conf(&a) == -1)   //读取配置文件失败
       {
          printf("read conf err");
          return -1;
       }
    
      printf("ip:%s\n", a.ips);
      printf("port :%d\n",a.port);
      printf("lismax : %d\n",a.lismax);
    
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(sockfd == -1)
    {
            printf("create sockfd failed\n");
            return sockfd;
    }
    struct sockaddr_in saddr;
    memset(&saddr,0,sizeof(saddr));
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(a.port);;
    saddr.sin_addr.s_addr = inet_addr(a.ips);
    int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
    if(res == -1)
    {
            return -1;
    }
    res = listen(sockfd,a.lismax);
    if(res == -1)
    {
            return -1;
    }
    printf("res=%d\n",res);
    return sockfd;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98

    thread.c

    #include "thread.h"
    #include
    #define ARG_MAX 10
    #define CMD_ERR "arg err"
    #define PIPE_ERR "err pipe"
    #define FORK_ERR "err fork"
    #define OK "ok#"
    char *get_cmd(char buff[],char* myargv[])
    {
            if(buff == NULL||myargv == NULL)
            {
                    return NULL;
            }
            char *s = NULL;//每次返回的子段
            char *p = NULL;//记录当前分割字符串的位置
    
            int i = 0;
            s =  strtok_r(buff," ",&p);
            while(s!=NULL)
            {
                    myargv[i++] = s;
            s = strtok_r(NULL," ",&p);
            }
            return myargv[0];//返回待处理的命令
    }
    
    void * work_thread(void *arg)
    {
            int c = (int)arg;
            while(1)
            {
                     char buff[128] = {0};
                     int n = recv(c,buff,127,0);
                     if(n<=0)
                     {
                             break;
                     }
                     //解析命令以及参数
                     char *myargv[ARG_MAX] = {0};
                     char *cmd = get_cmd(buff,myargv);
                     //参数检查
                     if(cmd == NULL)
                     {
                             send(c,CMD_ERR,strlen(CMD_ERR),0);
                             continue;
    
                     }
                     //判断是不是命令  ---fork+exec
                     //get  ==代表下载  ---自己实现函数  downfile()
                     //up == 代表是上传   recvfile()
                     if(strcmp(cmd,"get")==0)
                     {
                          // send_file(c,myargv[1]);
    
                     }
                     else if(strcmp(cmd,"up") == 0)
                     {
    
                     }
                     else
                     {
                         //创建无名管道
                         int pipefd[2];
                         if(pipe(pipefd) == -1)
                         {
                                 send(c,PIPE_ERR,strlen(PIPE_ERR),0);
                                 continue;
                         }
                         pid_t pid= fork();
                         if(pid == -1)
                         {
                            send(c,FORK_ERR,strlen(FORK_ERR),0);
                            continue;
                         }
                         //fork  -- child替换标准输出
                         if(pid == 0)
                         {
                                 close(pipefd[0]);
                                 dup2(pipefd[1],1);  //管道写端覆盖标准输出
                                 dup2(pipefd[1],2);   //管道写端覆盖标准错误输出
    
                                 execvp(cmd,myargv);  
                                 perror("exec err");
                                 close(pipefd[1]);
                                 exit(0);
                         }
                         //fork -//下载 -parent read管道
                         close(pipefd[1]);
                         wait(NULL);
                         char read_buff[1024] = {OK};
                         read(pipefd[0],read_buff+strlen(OK),1021);
                         close(pipefd[0]);
                         send(c,read_buff,strlen(read_buff),0);
    
                     }
                
                    //printf("buff=%s\n",buff);
                    // send(c,"ok",2,0); //测试收发数据正常
            }
            printf("client close\n");
            close(c);
    }
    void start_thread(int c)
    {
        //创建一个线程函数
        pthread_t id;
        pthread_create(&id,NULL,work_thread,(void*)c);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108

    my_conf

    #设置配置文件
    
    #ip地址
    
    ipstr=127.0.0.1
    port=6000
    lismax=5
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    make

    all: ser
    
    ser: ser.o socket.o thread.o
    	gcc -o ser ser.o socket.o thread.o -lpthread
    ser.o : ser.c
    	gcc -c ser.c
    
    socket.o : socket.c
    	gcc -c socket.c
    
    thread.o:thread.c
    	gcc -c thread.c -Wpointer-to-int-cast
    
    clean:
    	rm -rf *.o ser
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    客户端

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #define  OK  "ok#"
    char * get_cmd(char buff[],char* myargv[])
    {
        if ( buff == NULL || myargv == NULL )
        {
            return NULL;
        }
    
        char * s = strtok(buff," ");
        int i = 0;
        while( s != NULL )
        {
            myargv[i++] = s;
            s = strtok(NULL," ");
        }
    
        return myargv[0];
    }
    
    
    int main()
    {
        int sockfd = socket(AF_INET,SOCK_STREAM,0);
        if( sockfd == -1 )
        {
            exit(0);
        }
    
        struct sockaddr_in saddr;
        memset(&saddr,0,sizeof(saddr));
        saddr.sin_family = AF_INET;
        saddr.sin_port = htons(6000);
        saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    
        int res = connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
        if ( res == -1 )
        {
            close(sockfd);
            exit(0);
        }
    
        while( 1 )
        {
            printf("connect>>");
            fflush(stdout);
    
            char buff[128] = {0};
            fgets(buff,128,stdin);
    
            buff[strlen(buff)-1] = 0;
            char cmd_buff[128] = {0};
            strcpy(cmd_buff,buff);//备份键盘输入的命令
            //解析命令 参数 ,异常检查
            char* myargv[10] = {0};
            char * cmd = get_cmd(buff,myargv);
            if ( cmd == NULL )
            {
                continue;
            }
            else if ( strcmp(cmd,"exit") == 0 )//exit 客户端要退出
            {
                break;
            }
            else if ( strcmp(cmd,"get") == 0 )
            {
            //get  下载
                recv_file(sockfd,cmd_buff,myargv[1]);
            }
            else if ( strcmp(cmd,"up") == 0 )
            {
            //up   上传
    
            }
            else
            {
            //执行通用命令
                send(sockfd,cmd_buff,strlen(cmd_buff),0);
                char read_buff[1024] = {0};
                //读取服务器返回的结果
                int num = recv(sockfd,read_buff,1023,0);
                if ( num <= 0 )
                {
                    printf("ser close or err\n");
                    break;
                }
    
                if ( strncmp(read_buff,OK,strlen(OK)) == 0 )
                {
                    printf("%s\n",read_buff+strlen(OK));
                }
                else
                {
                    printf("%s\n",read_buff);
                }
            }     
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
  • 相关阅读:
    电商场景下 ES 搜索引擎的稳定性治理实践
    网络安全之Windows提权(上篇)(高级进阶)
    synchronized锁的四种状态及优化存储
    k8s day08
    神经网络变换器参数辩识,神经网络转移函数
    server和client之间进行Socket通信,进行数据切片
    三分钟了解var const let 区别
    DzzOffice集成功能最丰富的开源PHP+MySQL办公系统套件
    基于多尺度集成极限学习机回归(Matlab代码实现)
    UIAutomator2常用类之UiObject2
  • 原文地址:https://blog.csdn.net/weixin_52958292/article/details/126325649