【學習筆記】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];// 初始化libcurlcurl_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 = ""; // 服務器IPconst 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]; // 刪除文件命令// 初始化libcurlcurl_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;
}