C语言编程题实现一个简易的FTP客户端

C语言编程题,实现一个简易的FTP客户端,可以学习网络编程中的套接字(socket)通信、FTP协议的基本操作。FTP协议的核心是基于客户端-服务器模型,通过TCP连接进行文件传输。FTP客户端通常包含两条TCP连接:控制连接和数据连接。控制连接用于发送命令,数据连接用于传输文件内容。

1、头文件包含和宏定义

stdio.h:提供输入输出相关的函数,例如 printf()fgets()

stdlib.h:提供标准库函数,如 exit()

string.h:用于字符串操作,如 strcpy()strlen()strcmp()

unistd.h:提供POSIX操作系统接口,如 read()write()close()

arpa/inet.h:用于网络编程,提供网络地址转换和套接字操作函数,如 inet_addr()

SERVER_PORT:FTP服务器的默认端口号是21,客户端将使用这个端口号连接到服务器。

BUFFER_SIZE:定义缓冲区大小为1024字节,主要用于存储从服务器接收的数据和用户输入的命令。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define SERVER_PORT 21
#define BUFFER_SIZE 1024

int main() {
  printf("Hello, World!");
  return 0;
}

2、读取服务器响应的函数

read_response()该函数从服务器读取响应数据并打印到控制台,read(sockfd, buffer, BUFFER_SIZE - 1)从套接字 sockfd 读取服务器发来的数据,最多读取 BUFFER_SIZE - 1 字节,保留最后一个字节放 \0buffer[n] = '\0'是确保缓冲区以 \0 结束,防止后续打印时溢出。如果读取失败或没有数据,输出错误信息。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define SERVER_PORT 21
#define BUFFER_SIZE 1024

// 读取服务器响应
void read_response(int sockfd) {
    char buffer[BUFFER_SIZE];
    int n = read(sockfd, buffer, BUFFER_SIZE - 1);
    if (n > 0) {
        buffer[n] = '\0';  // 以空字符结尾
        printf("%s", buffer);
    } else {
        printf("读取响应时出错\n");
    }
}

3、发送FTP命令到服务器的函数

send_command()用于向FTP服务器发送命令write(sockfd, cmd, strlen(cmd))将命令发送到服务器,命令是 cmd。write(sockfd, "\r\n", 2)根据FTP协议,所有命令必须以 \r\n 结尾,因此这里发送命令结束符。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define SERVER_PORT 21
#define BUFFER_SIZE 1024

// 读取服务器响应
void read_response(int sockfd) {
    char buffer[BUFFER_SIZE];
    int n = read(sockfd, buffer, BUFFER_SIZE - 1);
    if (n > 0) {
        buffer[n] = '\0';  // 以空字符结尾
        printf("%s", buffer);
    } else {
        printf("读取响应时出错\n");
    }
}

// 发送FTP命令到服务器
void send_command(int sockfd, const char* cmd) {
    write(sockfd, cmd, strlen(cmd));
    write(sockfd, "\r\n", 2);  // 发送FTP命令结尾的 \r\n
}

4、主函数

sockfd客户端的套接字,用于与服务器通信。server_addr用于存储服务器的IP地址和端口号信息。buffer缓冲区,用于存储用户输入的命令和服务器的响应。socket()创建一个TCP套接字,参数 AF_INET 表示IPv4协议,SOCK_STREAM 表示使用TCP协议。如果套接字创建失败,使用 perror() 打印错误信息,并通过 exit(EXIT_FAILURE) 退出程序。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define SERVER_PORT 21
#define BUFFER_SIZE 1024

// 读取服务器响应
void read_response(int sockfd) {
    char buffer[BUFFER_SIZE];
    int n = read(sockfd, buffer, BUFFER_SIZE - 1);
    if (n > 0) {
        buffer[n] = '\0';  // 以空字符结尾
        printf("%s", buffer);
    } else {
        printf("读取响应时出错\n");
    }
}

// 发送FTP命令到服务器
void send_command(int sockfd, const char* cmd) {
    write(sockfd, cmd, strlen(cmd));
    write(sockfd, "\r\n", 2);  // 发送FTP命令结尾的 \r\n
}

int main() {
    int sockfd;
    struct sockaddr_in server_addr;
    char buffer[BUFFER_SIZE];

    // 创建套接字
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        perror("无法创建套接字");
        exit(EXIT_FAILURE);
    }

    // 设置服务器地址
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(SERVER_PORT);
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");  // 本地服务器,替换成实际FTP服务器的IP地址

    // 连接FTP服务器
    if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        perror("无法连接到FTP服务器");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    // 读取初始响应(欢迎信息)
    read_response(sockfd);

    // 登录:发送用户名和密码
    printf("发送用户名: ");
    fgets(buffer, BUFFER_SIZE, stdin);
    buffer[strcspn(buffer, "\n")] = '\0';  // 移除换行符
    char user_command[BUFFER_SIZE];
    snprintf(user_command, sizeof(user_command), "USER %s", buffer);
    send_command(sockfd, user_command);
    read_response(sockfd);

    printf("发送密码: ");
    fgets(buffer, BUFFER_SIZE, stdin);
    buffer[strcspn(buffer, "\n")] = '\0';  // 移除换行符
    char pass_command[BUFFER_SIZE];
    snprintf(pass_command, sizeof(pass_command), "PASS %s", buffer);
    send_command(sockfd, pass_command);
    read_response(sockfd);

    // 交互:发送其他FTP命令
    while (1) {
        printf("ftp> ");
        fgets(buffer, BUFFER_SIZE, stdin);
        buffer[strcspn(buffer, "\n")] = '\0';  // 移除换行符

        if (strcmp(buffer, "quit") == 0) {
            break;
        }

        send_command(sockfd, buffer);  // 发送命令
        read_response(sockfd);         // 读取服务器的响应
    }

    // 关闭连接
    close(sockfd);
    return 0;
}

5、编译运行

1)编译代码

gcc -o ftp_client ftp_client.c

2)运行客户端

./ftp_client

3)在终端输入FTP命令

USER your-username
PASS your-password
LIST
QUIT

该简易FTP客户端实现了基本的FTP登录和命令交互功能。通过进一步扩展数据连接功能,可以完成更复杂的文件传输操作。

推荐阅读
cjavapy编程之路首页