zoukankan      html  css  js  c++  java
  • C语言实现FTP服务器

    公共部分代码

    /*
    common.h
    */
    #ifndef COMMON_H
    #define COMMON_H
    
    #include <arpa/inet.h>
    #include <ctype.h>
    #include <dirent.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <netdb.h>        
    #include <netinet/in.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/wait.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <unistd.h>
    
    #define DEBUG                1
    #define MAXSIZE             512     
    #define CLIENT_PORT_ID        30020
    
    struct command 
    {
        char arg[255];
        char code[5];
    };
    
    int socket_create(int port);
    
    int socket_accept(int sock_listen);
    
    int socket_connect(int port, char *host);
    
    int recv_data(int sockfd, char* buf, int bufsize);
    
    int send_response(int sockfd, int rc);
    
    void trimstr(char *str, int n);
    
    void read_input(char* buffer, int size);
    
    #endif
    /*
    common.c
    */
    #include "common.h"
    
    /**
     * 创建监听套接字
     * 错误返回 -1,正确返回套接字描述符
     */
    int socket_create(int port)
    {
        int sockfd;
        int yes = 1;
        struct sockaddr_in sock_addr;
    
        // 创建套接字
        if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) 
        {
            perror("socket() error"); 
            return -1; 
        }
    
        // 设置本地套接字地址
        sock_addr.sin_family = AF_INET;
        sock_addr.sin_port = htons(port);
        sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);        
    
        if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) 
        {
            close(sockfd);
            perror("setsockopt() error");
            return -1; 
        }
    
        // 绑定本地套接字地址到套接字
        if (bind(sockfd, (struct sockaddr *) &sock_addr, sizeof(sock_addr)) < 0) 
        {
            close(sockfd);
            perror("bind() error"); 
            return -1; 
        }
       
        // 将套接字设置为监听状态
        if (listen(sockfd, 5) < 0) 
        {
            close(sockfd);
            perror("listen() error");
            return -1;
        }              
        return sockfd;
    }
    
    /**
     * 套接字接受请求
     * 错误返回 -1,正确返回新的连接套接字
     */
    int socket_accept(int sock_listen)
    {
        int sockfd;
        struct sockaddr_in client_addr;
        socklen_t len = sizeof(client_addr);
        sockfd = accept(sock_listen, (struct sockaddr *) &client_addr, &len); // 等待连接
        
        if (sockfd < 0)
        {
            perror("accept() error"); 
            return -1; 
        }
        return sockfd;
    }
    
    /**
     * 连接远端主机
     *  成功返回套接字描述符,失败返回 -1
    */
    int socket_connect(int port, char*host)
    {
        int sockfd;                      
        struct sockaddr_in dest_addr;
    
        /* 创建套接字 */
        if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        { 
                perror("error creating socket");
                return -1;
        }
    
        /* 设置协议地址 */
        memset(&dest_addr, 0, sizeof(dest_addr));
        dest_addr.sin_family = AF_INET;
        dest_addr.sin_port = htons(port);
        dest_addr.sin_addr.s_addr = inet_addr(host);
    
        /* 在套接字上创建连接 */
        if(connect(sockfd, (struct sockaddr *)&dest_addr, sizeof(dest_addr)) < 0 )
        {
            perror("error connecting to server");
            return -1;
        }    
        return sockfd;
    }
    
    /**
     * 接收数据
     * 错误返回 -1,正确返回接收的字节数 
     */
    int recv_data(int sockfd, char* buf, int bufsize)
    {
        size_t num_bytes;
        memset(buf, 0, bufsize);
    
        /* 调用 recv 函数读取套接字数据 */
        num_bytes = recv(sockfd, buf, bufsize, 0);
        if (num_bytes < 0) 
            return -1;
    
        return num_bytes;
    }
    
    /**
     * 去除字符串中的空格和换行符
     */
    void trimstr(char *str, int n)
    {
        int i;
        for (i = 0; i < n; i++) 
        {
            if (isspace(str[i])) str[i] = 0;
            if (str[i] == '
    ') str[i] = 0;
        }
    }
    
    /**
     * 发送响应码到 sockfd
     * 错误返回 -1,正确返回 0
     */
    int send_response(int sockfd, int rc)
    {
        int conv = htonl(rc);
        if (send(sockfd, &conv, sizeof conv, 0) < 0 ) 
        {
            perror("error sending...
    ");
            return -1;
        }
        return 0;
    }
    
    /** 
     * 从命令行中读取输入
     */
    void read_input(char* buffer, int size)
    {
        char *nl = NULL;
        memset(buffer, 0, size);
    
        if ( fgets(buffer, size, stdin) != NULL ) 
        {
            nl = strchr(buffer, '
    ');
            if (nl) 
                *nl = ''; // 出现换行符,则将该位置部位''(字符串结尾)
        }
    }

    客户端代码:

    /*
    ftclient.h
    */
    #ifndef FTCLIENT_H
    #define FTCLIENT_H
    
    #include "../common/common.h"
    
    int read_reply();
    
    void print_reply(int rc);
    
    int ftclient_read_command(char* buf, int size, struct command *cstruct);
    
    int ftclient_get(int data_sock, int sock_control, char* arg);
    
    int ftclient_open_conn(int sock_con);
    
    int ftclient_list(int sock_data, int sock_con);
    
    int ftclient_send_cmd(struct command *cmd);
    
    void ftclient_login();
    
    #endif
    /*
    ftclient.c
    */
    #include "ftclient.h"
        
    int sock_control; 
    
    /**
     * 接收服务器响应
     * 错误返回 -1,正确返回状态码
     */
    int read_reply()
    {
        int retcode = 0;
        if (recv(sock_control, &retcode, sizeof retcode, 0) < 0) 
        {
            perror("client: error reading message from server
    ");
            return -1;
        }    
        return ntohl(retcode);
    }
    
    /**
     * 打印响应信息
     */
    void print_reply(int rc) 
    {
        switch (rc)
        {
            case 220:
                printf("220 Welcome, server ready.
    ");
                break;
            case 221:
                printf("221 Goodbye!
    ");
                break;
            case 226:
                printf("226 Closing data connection. Requested file action successful.
    ");
                break;
            case 550:
                printf("550 Requested action not taken. File unavailable.
    ");
                break;
        }
    }
    
    /**
     * 解析命令行到结构体
     */ 
    int ftclient_read_command(char* buf, int size, struct command *cstruct)
    {
        memset(cstruct->code, 0, sizeof(cstruct->code));
        memset(cstruct->arg, 0, sizeof(cstruct->arg));
        
        printf("ftclient> ");    // 输入提示符    
        fflush(stdout);     
        read_input(buf, size); // 等待用户输入命令
        char *arg = NULL;
        arg = strtok (buf," ");
        arg = strtok (NULL, " ");
    
        if (arg != NULL)
            strncpy(cstruct->arg, arg, strlen(arg));
    
        if (strcmp(buf, "list") == 0) 
            strcpy(cstruct->code, "LIST");
    
        else if (strcmp(buf, "get") == 0)
            strcpy(cstruct->code, "RETR");
    
        else if (strcmp(buf, "quit") == 0) 
            strcpy(cstruct->code, "QUIT");
        
        else 
            return -1; // 不合法
    
        memset(buf, 0, 400);
        strcpy(buf, cstruct->code);  // 存储命令到 buf 开始处
    
        /* 如果命令带有参数,追加到 buf */
        if (arg != NULL) 
        {
            strcat(buf, " ");
            strncat(buf, cstruct->arg, strlen(cstruct->arg));
        }
        return 0;
    }
    
    /**
     * 实现 get <filename> 命令行
     */
    int ftclient_get(int data_sock, int sock_control, char* arg)
    {
        char data[MAXSIZE];
        int size;
        FILE* fd = fopen(arg, "w"); // 创建并打开名字为 arg 的文件
    
        /* 将服务器传来的数据(文件内容)写入本地建立的文件 */
        while ((size = recv(data_sock, data, MAXSIZE, 0)) > 0) 
            fwrite(data, 1, size, fd); 
    
        if (size < 0) 
            perror("error
    ");
    
        fclose(fd);
        return 0;
    }
    
    /**
     * 打开数据连接
     */
    int ftclient_open_conn(int sock_con)
    {
        int sock_listen = socket_create(CLIENT_PORT_ID);
    
        /* 在控制连接上发起一个 ACK 确认 */
        int ack = 1;
        if ((send(sock_con, (char*) &ack, sizeof(ack), 0)) < 0) 
        {
            printf("client: ack write error :%d
    ", errno);
            exit(1);
        }        
    
        int sock_conn = socket_accept(sock_listen);
        close(sock_listen);
        return sock_conn;
    }
    
    /** 
     * 实现 list 命令
     */
    int ftclient_list(int sock_data, int sock_con)
    {
        size_t num_recvd;            
        char buf[MAXSIZE];            
        int tmp = 0;
    
        /* 等待服务器启动的信息 */ 
        if (recv(sock_con, &tmp, sizeof tmp, 0) < 0) 
        {
            perror("client: error reading message from server
    ");
            return -1;
        }
        
        memset(buf, 0, sizeof(buf));
    
        /* 接收服务器传来的数据 */
        while ((num_recvd = recv(sock_data, buf, MAXSIZE, 0)) > 0) 
        {
            printf("%s", buf);
            memset(buf, 0, sizeof(buf));
        }
        
        if (num_recvd < 0) 
            perror("error");
        
        /* 等待服务器完成的消息 */ 
        if (recv(sock_con, &tmp, sizeof tmp, 0) < 0) 
        {
            perror("client: error reading message from server
    ");
            return -1;
        }
        return 0;
    }
    
    /**
     * 输入含有命令(code)和参数(arg)的 command(cmd) 结构
     * 连接 code + arg,并放进一个字符串,然后发送给服务器
     */
    int ftclient_send_cmd(struct command *cmd)
    {
        char buffer[MAXSIZE];
        int rc;
    
        sprintf(buffer, "%s %s", cmd->code, cmd->arg);
        
        /* 发送命令字符串到服务器 */ 
        rc = send(sock_control, buffer, (int)strlen(buffer), 0);    
        if (rc < 0) 
        {
            perror("Error sending command to server");
            return -1;
        }
        
        return 0;
    }
    
    /**
     * 获取登录信息
     * 发送到服务器认证
     */
    void ftclient_login()
    {
        struct command cmd;
        char user[256];
        memset(user, 0, 256);
    
        /* 获取用户名 */ 
        printf("Name: ");    
        fflush(stdout);         
        read_input(user, 256);
    
        /* 发送用户名到服务器 */ 
        strcpy(cmd.code, "USER");
        strcpy(cmd.arg, user);
        ftclient_send_cmd(&cmd);
        
        /* 等待应答码 331 */
        int wait;
        recv(sock_control, &wait, sizeof wait, 0);
    
        /* 获得密码 */
        fflush(stdout);    
        char *pass = getpass("Password: ");    
    
        /* 发送密码到服务器 */ 
        strcpy(cmd.code, "PASS");
        strcpy(cmd.arg, pass);
        ftclient_send_cmd(&cmd);
        
        /* 等待响应 */ 
        int retcode = read_reply();
        switch (retcode) 
        {
            case 430:
                printf("Invalid username/password.
    ");
                exit(0);
            case 230:
                printf("Successful login.
    ");
                break;
            default:
                perror("error reading message from server");
                exit(1);        
                break;
        }
    }
    
    /* 主函数入口 */
    int main(int argc, char* argv[]) 
    {        
        int data_sock, retcode, s;
        char buffer[MAXSIZE];
        struct command cmd;    
        struct addrinfo hints, *res, *rp;
    
        /* 命令行参数合法性检测 */
        if (argc != 3)
        {
            printf("usage: ./ftclient hostname port
    ");
            exit(0);
        }
    
        char *host = argv[1]; //所要连接的服务器主机名
        char *port = argv[2]; //所要链接到服务器程序端口号
    
        /* 获得和服务器名匹配的地址 */
        memset(&hints, 0, sizeof(struct addrinfo));
        hints.ai_family = AF_UNSPEC;
        hints.ai_socktype = SOCK_STREAM;
        s = getaddrinfo(host, port, &hints, &res);
        if (s != 0) 
        {
            printf("getaddrinfo() error %s", gai_strerror(s));
            exit(1);
        }
        
        /* 找到对应的服务器地址并连接 */ 
        for (rp = res; rp != NULL; rp = rp->ai_next) 
        {
            sock_control = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); // 创建控制套接字
    
            if (sock_control < 0)
                continue;
    
            if(connect(sock_control, res->ai_addr, res->ai_addrlen)==0)   // 和服务器连接
                break;
            
            else 
            {
                perror("connecting stream socket");
                exit(1);
            }
            close(sock_control);
        }
        freeaddrinfo(rp);
    
    
        /* 连接成功,打印信息 */
        printf("Connected to %s.
    ", host);
        print_reply(read_reply()); 
        
    
        /* 获取用户的名字和密码 */
        ftclient_login();
    
        while (1) 
        { // 循环,直到用户输入 quit
    
            /* 得到用户输入的命令 */ 
            if ( ftclient_read_command(buffer, sizeof buffer, &cmd) < 0)
            {
                printf("Invalid command
    ");
                continue;    // 跳过本次循环,处理下一个命令
            }
    
            /* 发送命令到服务器 */ 
            if (send(sock_control, buffer, (int)strlen(buffer), 0) < 0 )
            {
                close(sock_control);
                exit(1);
            }
    
            retcode = read_reply();    //读取服务器响应(服务器是否可以支持该命令?)
    
            if (retcode == 221)  // 退出命令
            {
                print_reply(221);        
                break;
            }
            
            if (retcode == 502) 
                printf("%d Invalid command.
    ", retcode);// 不合法的输入,显示错误信息
    
            else 
            {            
                // 命令合法 (RC = 200),处理命令
            
                /* 打开数据连接 */
                if ((data_sock = ftclient_open_conn(sock_control)) < 0) 
                {
                    perror("Error opening socket for data connection");
                    exit(1);
                }            
                
                /* 执行命令 */
                if (strcmp(cmd.code, "LIST") == 0) 
                    ftclient_list(data_sock, sock_control);
                
                else if (strcmp(cmd.code, "RETR") == 0) 
                {
                    if (read_reply() == 550) // 等待回复
                    {
                        print_reply(550);        
                        close(data_sock);
                        continue; 
                    }
                    ftclient_get(data_sock, sock_control, cmd.arg);
                    print_reply(read_reply()); 
                }
                close(data_sock);
            }
    
        } // 循环得到更多的用户输入
    
        close(sock_control); // 关闭套接字控制连接
        return 0;  
    }

    makefile文件

    CC := gcc
    CFLAGS := -Wall -g -Os
    
    SHDIR := ../common
    
    OBJS = ftclient.o $(SHDIR)/common.o
    
    all: ftclient
    
    ftclient: $(OBJS)
        @$(CC) -o ftclient $(CFLAGS) $(OBJS)
    
    $(OBJS) : %.o: %.c 
        @$(CC) -c $(CFLAGS) $< -o $@
    
    .PHONY:
    clean:
        @rm -f *.o ftclient
        @rm -f ../common/*.o
        @echo Done cleaning

    服务端代码:

    /*
    ftserve.h
    */
    #ifndef FTSERVE_H
    #define FTSERVE_H
    
    #include "../common/common.h"
    
    void ftserve_retr(int sock_control, int sock_data, char* filename);
    
    int ftserve_list(int sock_data, int sock_control);
    
    int ftserve_start_data_conn(int sock_control);
    
    int ftserve_check_user(char*user, char*pass);
    
    int ftserve_login(int sock_control);
    
    int ftserve_recv_cmd(int sock_control, char*cmd, char*arg);
    
    void ftserve_process(int sock_control);
    
    #endif
    /*
    ftserve.c
    */
    
    #include "ftserve.h"
    
    /* 主函数入口 */
    int main(int argc, char *argv[])
    {    
        int sock_listen, sock_control, port, pid;
    
        /* 命令行合法性检测 */
        if (argc != 2)
        {
            printf("usage: ./ftserve port
    ");
            exit(0);
        }
    
        /* 将命令行传进来的服务器端口号(字符串)转换为整数 */
        port = atoi(argv[1]);
    
        /* 创建监听套接字 */
        if ((sock_listen = socket_create(port)) < 0 )
        {
            perror("Error creating socket");
            exit(1);
        }        
        
        /* 循环接受不同的客户机请求 */
        while(1) 
        {    
            /* 监听套接字接受连接请求,得到控制套接字,用于传递控制信息 */
            if ((sock_control = socket_accept(sock_listen))    < 0 )
                break;            
            
            /* 创建子进程处理用户请求 */
            if ((pid = fork()) < 0) 
                perror("Error forking child process");
        
            /* 子进程调用 ftserve_process 函数与客户端交互 */
            else if (pid == 0)
            { 
                close(sock_listen);  // 子进程关闭父进程的监听套接字
                ftserve_process(sock_control);        
                close(sock_control); //用户请求处理完毕,关闭该套接字
                exit(0);
            }
                
            close(sock_control); // 父进程关闭子进程的控制套接字
        }
    
        close(sock_listen);    
    
        return 0;
    }
    
    /**
     * 通过数据套接字发送特定的文件
     * 控制信息交互通过控制套接字
     * 处理无效的或者不存在的文件名
     */
    void ftserve_retr(int sock_control, int sock_data, char* filename)
    {    
        FILE* fd = NULL;
        char data[MAXSIZE];
        size_t num_read;                                    
        fd = fopen(filename, "r"); // 打开文件
    
        if (!fd)
            send_response(sock_control, 550); // 发送错误码 (550 Requested action not taken)
        
        else
        {    
            send_response(sock_control, 150); // 发送 okay (150 File status okay)
            do 
            {
                num_read = fread(data, 1, MAXSIZE, fd); // 读文件内容
                if (num_read < 0) 
                    printf("error in fread()
    ");
    
                if (send(sock_data, data, num_read, 0) < 0) // 发送数据(文件内容)
                    perror("error sending file
    ");
    
            }
            while (num_read > 0);                                                    
                
            send_response(sock_control, 226); // 发送消息:226: closing conn, file transfer successful
    
            fclose(fd);
        }
    }
    
    /**
     * 响应请求:发送当前所在目录的目录项列表
     * 关闭数据连接
     * 错误返回 -1,正确返回 0
     */
    int ftserve_list(int sock_data, int sock_control)
    {
        char data[MAXSIZE];
        size_t num_read;                                    
        FILE* fd;
    
        int rs = system("ls -l | tail -n+2 > tmp.txt"); //利用系统调用函数 system 执行命令,并重定向到 tmp.txt 文件
        if ( rs < 0)
        {
            exit(1);
        }
        
        fd = fopen("tmp.txt", "r");    
        if (!fd) 
            exit(1); 
        
        /* 定位到文件的开始处 */
        fseek(fd, SEEK_SET, 0);
    
        send_response(sock_control, 1); 
    
        memset(data, 0, MAXSIZE);
    
        /* 通过数据连接,发送tmp.txt 文件的内容 */
        while ((num_read = fread(data, 1, MAXSIZE, fd)) > 0) 
        {
            if (send(sock_data, data, num_read, 0) < 0) 
                perror("err");
        
            memset(data, 0, MAXSIZE);
        }
    
        fclose(fd);
    
        send_response(sock_control, 226);    // 发送应答码 226(关闭数据连接,请求的文件操作成功)
    
        return 0;    
    }
    
    /**
     * 创建到客户机的一条数据连接
     * 成功返回数据连接的套接字
     * 失败返回 -1
     */
    int ftserve_start_data_conn(int sock_control)
    {
        char buf[1024];    
        int wait, sock_data;
    
        if (recv(sock_control, &wait, sizeof wait, 0) < 0 ) 
        {
            perror("Error while waiting");
            return -1;
        }
    
        
        struct sockaddr_in client_addr;
        socklen_t len = sizeof client_addr;
        getpeername(sock_control, (struct sockaddr*)&client_addr, &len); // 获得与控制套接字关联的外部地址(客户端地址)
        inet_ntop(AF_INET, &client_addr.sin_addr, buf, sizeof(buf));
    
        /* 创建到客户机的数据连接 */
        if ((sock_data = socket_connect(CLIENT_PORT_ID, buf)) < 0)
            return -1;
    
        return sock_data;        
    }
    
    /**
     * 用户资格认证
     * 认证成功返回 1,否则返回 0 
     */
    int ftserve_check_user(char*user, char*pass)
    {
        char username[MAXSIZE];
        char password[MAXSIZE];
        char *pch;
        char buf[MAXSIZE];
        char *line = NULL;
        size_t num_read;                                    
        size_t len = 0;
        FILE* fd;
        int auth = 0;
        
        fd = fopen(".auth", "r"); //打开认证文件(记录用户名和密码)
        if (fd == NULL) 
        {
            perror("file not found");
            exit(1);
        }    
    
        /* 读取".auth" 文件中的用户名和密码,验证用户身份的合法性 */
        while ((num_read = getline(&line, &len, fd)) != -1) 
        {
            memset(buf, 0, MAXSIZE);
            strcpy(buf, line);
            
            pch = strtok (buf," ");
            strcpy(username, pch);
    
            if (pch != NULL)
            {
                pch = strtok (NULL, " ");
                strcpy(password, pch);
            }
    
            /* 去除字符串中的空格和换行符 */
            trimstr(password, (int)strlen(password));
    
            if ((strcmp(user,username)==0) && (strcmp(pass,password)==0)) 
            {
                auth = 1; // 匹配成功,标志变量 auth = 1,并返回
                break;
            }        
        }
        free(line);    
        fclose(fd);    
        return auth;
    }
    
    /* 用户登录*/
    int ftserve_login(int sock_control)
    {    
        char buf[MAXSIZE];
        char user[MAXSIZE];
        char pass[MAXSIZE];    
        memset(user, 0, MAXSIZE);
        memset(pass, 0, MAXSIZE);
        memset(buf, 0, MAXSIZE);
        
        /* 获得客户端传来的用户名 */
        if ( (recv_data(sock_control, buf, sizeof(buf)) ) == -1) 
        {
            perror("recv error
    "); 
            exit(1);
        }    
    
        int i = 5;
        int n = 0;
        while (buf[i] != 0) //buf[0-4]="USER"
            user[n++] = buf[i++];
        
        /* 用户名正确,通知用户输入密码 */
        send_response(sock_control, 331);                    
        
        /* 获得客户端传来的密码 */
        memset(buf, 0, MAXSIZE);
        if ( (recv_data(sock_control, buf, sizeof(buf)) ) == -1) 
        {
            perror("recv error
    "); 
            exit(1);
        }
        
        i = 5;
        n = 0;
        while (buf[i] != 0) // buf[0 - 4] = "PASS"
            pass[n++] = buf[i++];
        
        return (ftserve_check_user(user, pass)); // 用户名和密码验证,并返回
    }
    
    /* 接收客户端的命令并响应,返回响应码 */
    int ftserve_recv_cmd(int sock_control, char*cmd, char*arg)
    {    
        int rc = 200;
        char buffer[MAXSIZE];
        
        memset(buffer, 0, MAXSIZE);
        memset(cmd, 0, 5);
        memset(arg, 0, MAXSIZE);
            
        /* 接受客户端的命令 */
        if ((recv_data(sock_control, buffer, sizeof(buffer)) ) == -1) 
        {
            perror("recv error
    "); 
            return -1;
        }
        
        /* 解析出用户的命令和参数 */
        strncpy(cmd, buffer, 4);
        char *tmp = buffer + 5;
        strcpy(arg, tmp);
        
        if (strcmp(cmd, "QUIT")==0) 
            rc = 221;
    
        else if ((strcmp(cmd, "USER") == 0) || (strcmp(cmd, "PASS") == 0) || (strcmp(cmd, "LIST") == 0) || (strcmp(cmd, "RETR") == 0))
            rc = 200;
    
        else 
            rc = 502; // 无效的命令
    
        send_response(sock_control, rc);    
        return rc;
    }
    
    /* 处理客户端请求 */
    void ftserve_process(int sock_control)
    {
        int sock_data;
        char cmd[5];
        char arg[MAXSIZE];
    
        send_response(sock_control, 220); // 发送欢迎应答码
    
        /* 用户认证 */
        if (ftserve_login(sock_control) == 1)  // 认证成功
            send_response(sock_control, 230);
        else 
        {
            send_response(sock_control, 430);    // 认证失败
            exit(0);
        }    
        
        /* 处理用户的请求 */
        while (1) 
        {
            /* 接收命令,并解析,获得命令和参数 */
            int rc = ftserve_recv_cmd(sock_control, cmd, arg);
            
            if ((rc < 0) || (rc == 221))  // 用户输入命令 "QUIT"
                break;
            
            if (rc == 200 ) 
            {
                /* 创建和客户端的数据连接 */
                if ((sock_data = ftserve_start_data_conn(sock_control)) < 0) 
                {
                    close(sock_control);
                    exit(1); 
                }
    
                /* 执行指令 */
                if (strcmp(cmd, "LIST")==0) 
                    ftserve_list(sock_data, sock_control);
                
                else if (strcmp(cmd, "RETR")==0) 
                    ftserve_retr(sock_control, sock_data, arg);
    
                close(sock_data);// 关闭连接
            } 
        }
    }

    里面还有一个保存密码账户文件.auth,这里就不列出。服务端的makefile和客户端makefile一样,只需要修改一下程序名及相关依赖名即可。

  • 相关阅读:
    P2351 [SDOI2012]吊灯
    洛谷P1450 [HAOI2008]硬币购物 背包+容斥
    P5110 块速递推-光速幂、斐波那契数列通项
    AT2304 Cleaning
    CSP-S 2020
    CF487E Tourists
    P4334 [COI2007] Policija
    动态逆序对专练
    CF437D The Child and Zoo
    CF1032G Chattering
  • 原文地址:https://www.cnblogs.com/wanghao-boke/p/11930651.html
Copyright © 2011-2022 走看看