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

近期面试有个机试题是写个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软件就实现了,不过有太多的缺陷和问题,等以后修改了再更新

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值