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登录和命令交互功能。通过进一步扩展数据连接功能,可以完成更复杂的文件传输操作。