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
字节,保留最后一个字节放 \0
。buffer[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登录和命令交互功能。通过进一步扩展数据连接功能,可以完成更复杂的文件传输操作。