【学习笔记】FTP库函数学习
FTP基本指令步骤
1、初始化会话句柄:CURL *curl = curl_easy_init();
2、设置会话选项: 设置服务器地址,设置登录用户和密码
curl_easy_setopt(curl, CURLOPT_URL, ftp_server);
curl_easy_setopt(curl, CURLOPT_USERNAME, user);
curl_easy_setopt(curl, CURLOPT_PASSWORD, pass);
启用被动模式(兼容性更好)
curl_easy_setopt(curl, CURLOPT_FTP_USE_EPSV, 1L);
开启调试模式,查看详细交互
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
3、执行会话操作:CURLcode res = curl_easy_perform(curl);
注意:执行会话操作之前,可以将要执行的命令先放到命令序列中,先放先执行。命令序列:struct curl_slist *cmd_list = NULL
12 char cwd_cmd[256]; // 切换目录命令
13 char delete_cmd[256]; // 删除文件命令
24 // 构建切换目录命令(CWD)和删除命令(DELE)
25 snprintf(cwd_cmd, sizeof(cwd_cmd), "CWD %s", target_dir);
26 snprintf(delete_cmd, sizeof(delete_cmd), "DELE %s", filename);
40 // 添加命令序列:先切换目录,再删除文件
41 cmd_list = curl_slist_append(cmd_list, cwd_cmd); // 第一步:切换到目标目录
42 cmd_list = curl_slist_append(cmd_list, delete_cmd); // 第二步:删除文件
43 curl_easy_setopt(curl, CURLOPT_POSTQUOTE, cmd_list);
44
45 // 执行操作
46 res = curl_easy_perform(curl);
4、释放会话资源:curl_easy_cleanup(curl); // 释放资源,避免内存泄漏
注意:在大型项目中,curl_global_init
只需要调用一次 ,且应放在程序生命周期的早期(初始化阶段),配合 curl_global_cleanup
在程序退出时释放资源。
FTP基本指令&日志
服务器日志:
-virtual-machine:/var/log$ sudo tail -f /var/log/vsftpd.log
查看服务器是否开启:
sudo systemctl status vsftpd
重启服务器服务:
sudo systemctl restart vsftpd
重启之后可以查看日志:
sudo journalctl -u vsftpd.service # 查看vsftpd的详细日志
手动运行查看错误日志:
sudo /usr/sbin/vsftpd /etc/vsftpd.conf
防火墙对某个端口的处理:
-virtual-machine:/etc$ sudo ufw status | grep 59924
系统对某个端口的监听:
-virtual-machine:/etc$ sudo netstat -tunlp | grep 59924
开放端口:开放端口: sudo ufw allow 123/udp sudo ufw reload
##注意事项:
1、配置文件注意事项:/etc/vsftpd.conf文件中不可以有多余的空格,都则编译报错。
2、查看防火墙开放的端口,确保被动模式下服务器开的端口范围都是开放的:sudo ufw status
3、一般采用被动模式:客户端自己给一个端口去连接服务器,服务器支持被动模式,并且需要开放一定数量的端口来做交互。就是上面所说的防火墙开放的50000:50010端口。
工作原理
- 客户端连接到服务器的 21 端口(默认的控制连接端口)。
- 服务器返回状态码 220,表示服务已就绪。
- 客户端发送用户名(USER 命令),服务器返回 331,表示需要密码。
- 客户端发送密码(PASS 命令),服务器返回 230,表示登录成功。
FTP 支持两种模式传输文件:
- 主动模式:服务器主动连接到客户端的数据端口。
- 被动模式:客户端连接到服务器的数据端口。
测试
登录测试:
#include <stdio.h>
#include "curl.h"
// 回调函数:处理服务器返回的信息(如登录成功提示)
size_t ftp_response_callback(void *contents, size_t size, size_t nmemb, void *userp) {
size_t realsize = size * nmemb;
printf("服务器响应: %.*s\n", (int)realsize, (char *)contents);
return realsize;
}
// FTP登录函数
int ftp_login(const char *server_ip, const char *username, const char *password) {
CURL *curl;
CURLcode res;
char ftp_url[128];
// 初始化libcurl
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if (curl) {
// 构建FTP服务器URL(仅登录,不操作文件)
snprintf(ftp_url, sizeof(ftp_url), "ftp://%s/", server_ip);
// 设置FTP服务器地址
curl_easy_setopt(curl, CURLOPT_URL, ftp_url);
// 设置登录用户名和密码
curl_easy_setopt(curl, CURLOPT_USERNAME, username);
curl_easy_setopt(curl, CURLOPT_PASSWORD, password);
// 启用被动模式(EPSV 是现代被动模式,优先使用)
curl_easy_setopt(curl, CURLOPT_FTP_USE_EPSV, 1L);
// 设置服务器响应的回调函数(用于显示登录结果)
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, ftp_response_callback);
// 启用详细输出(可选,用于调试)
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
// 执行登录操作(本质是建立连接并验证身份)
printf("正在连接到FTP服务器: %s...\n", server_ip);
res = curl_easy_perform(curl);
// 检查登录结果
if (res != CURLE_OK) {
fprintf(stderr, "登录失败: %s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl);
curl_global_cleanup();
return 1;
} else {
printf("登录成功!已连接到FTP服务器: %s\n", server_ip);
}
// 清理资源
curl_easy_cleanup(curl);
}
curl_global_cleanup();
return 0;
}
int main() {
// 你的FTP服务器信息(与命令行登录一致)
const char *server_ip = ""; // 服务器IP
const char *username = ""; // 用户名
const char *password = ""; // 密码
// 执行FTP登录
if (ftp_login(server_ip, username, password) != 0) {
printf("FTP登录过程失败\n");
return 1;
}
return 0;
}
删除文件:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
// 登录FTP,切换到指定目录并删除文件
int ftp_cd_and_delete(const char *ftp_server, const char *target_dir,
const char *filename, const char *user, const char *pass) {
CURL *curl = NULL;
CURLcode res;
struct curl_slist *cmd_list = NULL;
char cwd_cmd[256]; // 切换目录命令
char delete_cmd[256]; // 删除文件命令
// 初始化libcurl
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if (!curl) {
fprintf(stderr, "初始化curl失败\n");
return 1;
}
// 构建切换目录命令(CWD)和删除命令(DELE)
snprintf(cwd_cmd, sizeof(cwd_cmd), "CWD %s", target_dir);
snprintf(delete_cmd, sizeof(delete_cmd), "DELE %s", filename);
printf("准备执行切换目录命令: %s\n", cwd_cmd);
printf("准备执行删除命令: %s\n", delete_cmd);
// 设置FTP服务器地址(根目录)
curl_easy_setopt(curl, CURLOPT_URL, ftp_server);
// 设置登录信息
curl_easy_setopt(curl, CURLOPT_USERNAME, user);
curl_easy_setopt(curl, CURLOPT_PASSWORD, pass);
// 启用被动模式(兼容性更好)
curl_easy_setopt(curl, CURLOPT_FTP_USE_EPSV, 1L);
// 开启调试模式,查看详细交互
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
// 添加命令序列:先切换目录,再删除文件
cmd_list = curl_slist_append(cmd_list, cwd_cmd); // 第一步:切换到目标目录
cmd_list = curl_slist_append(cmd_list, delete_cmd); // 第二步:删除文件
curl_easy_setopt(curl, CURLOPT_POSTQUOTE, cmd_list);
// 执行操作
res = curl_easy_perform(curl);
if (res != CURLE_OK) {
fprintf(stderr, "操作失败: %s\n", curl_easy_strerror(res));
curl_slist_free_all(cmd_list);
curl_easy_cleanup(curl);
curl_global_cleanup();
return 1;
}
// 清理资源
curl_slist_free_all(cmd_list);
curl_easy_cleanup(curl);
curl_global_cleanup();
return 0;
}
int main() {
// FTP服务器信息(请根据实际情况修改)
const char *ftp_server = ""; // 服务器根目录
const char *target_dir = ""; // 目标目录路径
const char *username = "";
const char *password = "";
const char *target_file = ""; // 要删除的文件名
// 步骤1:登录FTP,切换到目标目录,删除文件
printf("1. 正在登录FTP服务器...\n");
printf("2. 正在切换到目录: %s\n", target_dir);
printf("3. 正在删除文件: %s\n", target_file);
if (ftp_cd_and_delete(ftp_server, target_dir, target_file, username, password) != 0) {
fprintf(stderr, "删除操作失败,程序退出\n");
return 1;
} else {
printf("文件 %s 已成功删除\n", target_file);
}
return 0;
}
printf("3. 正在删除文件: %s\n", target_file);
if (ftp_cd_and_delete(ftp_server, target_dir, target_file, username, password) != 0) {
fprintf(stderr, "删除操作失败,程序退出\n");
return 1;
} else {
printf("文件 %s 已成功删除\n", target_file);
}
return 0;
}