欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

自己实现一个简单的ftp软件

程序员文章站 2022-04-24 14:57:29
...

近期面试有个机试题是写个ftp软件,自己写完不想就扔了,就放到这里大家参考一下,也帮我优化优化,没什么太难的也就不需要什么注释了

消息格式:

cmd | size | data

服务端:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <dirent.h>
#include <stdlib.h>

#define COMPARE(a, b, c) (strcmp(a, c) b 0) 
#define HEAD_SIZE 4

char *packet(int size, const char *data);

int main(int argc, const char *argv[])
{
    int sockfd, acceptfd;
    struct sockaddr_in myaddr;
    memset(&myaddr, 0, sizeof(myaddr));
    socklen_t addrlen = sizeof(struct sockaddr_in);

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) return -1; 

    myaddr.sin_family = AF_INET;
    myaddr.sin_port = htons(6060);
    myaddr.sin_addr.s_addr = inet_addr("192.168.255.128");

    int optval = 1;
    socklen_t optlen = sizeof(optval);
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, optlen); //设置端口重用

    if (bind(sockfd, (struct sockaddr *)&myaddr, addrlen) == -1) {
        printf("bind faild\n");
        return -1;
    }
    if (listen(sockfd, 10) == -1) {
        printf("listen faild\n");
        return -1;
    }
    if ((acceptfd=accept(sockfd, (struct sockaddr *)&myaddr, &addrlen)) == -1) {
        printf("acceptfd faild\n");
        return -1;
    }

    ssize_t recvlen, sendlen;
    char buf[256];
    DIR *dirfd;
    while (1) { //注意服务端使用的消息格式是size|data
        recv(acceptfd, buf, 4, 0); //先接收开始的四个字节cmd
        if (COMPARE(buf, ==, "get")) {
            memset(buf, 0, 0);
            recv(acceptfd, buf, 4, 0);
            int size = *(int *)buf;
            recv(acceptfd, buf, size, 0);
            printf("%s\n", buf);
            FILE *fp = fopen(buf, "rb");
            if (fp == NULL) {
                printf("file open failed\n");
                break;
            }
            memset(buf,  0, 0); //使用buf前先清空一下,防止出现其它不想要的字符
            size_t readlen = fread(buf, 1, sizeof(buf), fp);
            char *tmp = packet(readlen, buf);
            send(acceptfd, tmp, HEAD_SIZE+readlen, 0);
            free(tmp);
            fclose(fp);
        } else if (COMPARE(buf, ==, "ls")) {
            printf("%s\n", buf);
            if ((dirfd = opendir("./")) == NULL) {
                char *tmp = packet(8, "no file");
                send(sockfd, tmp, HEAD_SIZE + 8, 0);
                free(tmp);
                printf("file open failed\n");
            } else {
                struct dirent *pdirent;
                while ((pdirent = readdir(dirfd)) != NULL) {
                    if (pdirent->d_name[0] == '.')
                        continue;
                    char *tmp = packet(strlen(pdirent->d_name)+1, pdirent->d_name);
                    sendlen = send(acceptfd, tmp, HEAD_SIZE + strlen(pdirent->d_name)+1, 0);
                    if (sendlen == 0) break;
                    free(tmp);
                }
                char *tmp = packet(4, "ok");
                send(acceptfd, tmp, HEAD_SIZE + 3, 0);
            }
        } else if (COMPARE(buf, ==, "put")) {
            printf("%s\n", buf);
            recv(acceptfd, buf, 4, 0);
            int size = *(int *)buf;
            memset(buf, 0, 0);
            size_t recvlen = recv(acceptfd, buf, size, 0);
            FILE *fp = fopen("./update.txt", "wb");
            if (fp == NULL) {
                printf("file open failed\n");
                break;
            }
            fwrite(buf, 1, recvlen, fp);
            strcpy(buf, "ok");
            send(acceptfd, buf, 3, 0);
            fclose(fp);
        }
    }

    close(sockfd);
    close(acceptfd);
    return 0;
}

char *packet(int size, const char *data) {
    char *ret = malloc(sizeof(int) + size);

    *(int *)ret = size;
    memcpy(ret + HEAD_SIZE, data, size);

    return ret;
}

客户端:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>

#define COMPARE(a, b, c) (strcmp(a, c) b 0)
#define HEAD_SIZE 8

char *packet(const char *cmd, int size, const char *data);

int main(int argc, const char *argv[])
{
    int sockfd;
    struct sockaddr_in myaddr;
    memset(&myaddr, 0, sizeof(myaddr));
    socklen_t addrlen = sizeof(struct sockaddr_in);

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) return -1; 

    myaddr.sin_family = AF_INET;
    myaddr.sin_port = htons(6060);
    myaddr.sin_addr.s_addr = inet_addr("192.168.255.128");

    if (connect(sockfd, (struct sockaddr *)&myaddr, addrlen) == -1) {
        printf("connect faild\n");
        return -1;
    }

    ssize_t recvlen, sendlen;
    char buff[256];
    char send_buff[256];
    char recv_buff[256];
    char *token = NULL;
    char *delim = " ";
    while (1) {

        printf("ftp > ");

        fgets(buff, sizeof(buff), stdin);
        buff[strlen(buff) - 1] = 0;
        char *tmp = buff;
        if (*tmp == 0) continue;
        token = strtok(tmp, delim);
#if 1
        if (COMPARE(token, ==, "ls")) {
            char *send_data = packet("ls", 0, NULL);
            send(sockfd, send_data, HEAD_SIZE, 0);
            free(send_data);
            while (1) {
                recvlen = recv(sockfd, recv_buff, 4, 0);
                if (recvlen <= 0) break;
                int size = *(int *)recv_buff;
                memset(recv_buff, 0, 0);
                recv(sockfd, recv_buff, size, 0);
                if (COMPARE(recv_buff, ==, "ok")) break;
                printf("%s  ", recv_buff);
                fflush(stdout);
            }
            printf("\n");
        } else if (COMPARE(token, ==, "get")) {
            char *data = strtok(NULL, delim);
            char *send_data = packet("get", strlen(data) + 1, data);
            send(sockfd, send_data, HEAD_SIZE+strlen(data)+1, 0);
            free(send_data);

            recvlen = recv(sockfd, recv_buff, 4, 0);
            if (recvlen <= 0) break;
            int size = *(int *)recv_buff;
            memset(recv_buff, 0, 0);
            recvlen = recv(sockfd, recv_buff, size, 0);
            FILE *fp = fopen(data, "wb");
            size_t len = fwrite(recv_buff, 1, recvlen, fp);
            printf("file download\n");
            fclose(fp);
        } else if (COMPARE(token, ==, "put")) {
            char *data = strtok(NULL, delim);
            FILE *fp = fopen(data, "rb");
            if (fp == NULL) {
                printf("file open failed\n");
                continue;
            }
            size_t readlen = fread(send_buff, 1, sizeof(send_buff), fp);
            char *tmp = packet("put", readlen, send_buff);
            send(sockfd, tmp, HEAD_SIZE+readlen, 0);
            free(tmp);
            fclose(fp);

            memset(recv_buff, 0, 0);
            recv(sockfd, recv_buff, 3, 0);
            if (COMPARE(recv_buff, ==, "ok")) 
                printf("put file finish\n");
        } else if (COMPARE(token, ==, "quit")) {
            close(sockfd);
            return 0;
        }
#endif
    }

    close(sockfd);
    return 0;
}

char *packet(const char *cmd, int size, const char *data) {
    char *ret = malloc(sizeof(char *) + sizeof(int) + size);

    memcpy(ret, cmd, 4);
    *(int *)(ret + 4) = size;
    if (size != 0) 
        memcpy(ret + HEAD_SIZE, data, size);

    return ret;
}

显示结果:
自己实现一个简单的ftp软件

一个简单的ftp软件就实现了,不过有太多的缺陷和问题,等以后修改了再更新

相关标签: ftp 软件