Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Протокол FTP (File Transfer Protocol)
FTP — один из самых старых и всё ещё используемых протоколов для передачи файлов. Хотя во многом устаревший, знание FTP важно для backend-разработчика, работающего с legacy системами.
Что такое FTP?
FTP (File Transfer Protocol) — это протокол прикладного уровня (Layer 7 OSI) для передачи файлов между компьютерами в сети. Он работает на TCP/IP и использует два отдельных соединения: одно для команд, другое для данных.
Основная идея: клиент подключается к FTP серверу, аутентифицируется (или входит как anonymous), затем может загружать, скачивать, удалять, переименовывать файлы.
Архитектура: два соединения
Это ключевое отличие FTP от HTTP:
Control connection (Port 21)
- Используется для команд: USER, PASS, LIST, RETR, STOR, DELETE, etc.
- Постоянное, остаётся открытым во время сессии
- Текстовый протокол (ASCII команды и ответы)
Data connection (Port 20 по умолчанию)
- Открывается отдельно для каждой операции с файлами
- Передаёт содержимое файлов
- После операции закрывается
Клиент Сервер
| |
|---> Connect to 21 -------->|
|<----- 220 Welcome ---------| Control
|
|---> USER anonymous ------->|
|<----- 331 Password --------|
|
|---> PASS user@example.com -|
|<----- 230 Login OK --------|
|
|---> PASV (Passive mode) -->|
|<----- 227 Entering Passive -|
|
| (Новое соединение на Data port)
|
|---> LIST ----------> ------->| Data
|<----- (файлы) <-------------|
|<----- 226 Transfer OK ------| Control
Режимы работы
1. Active Mode (PORT)
Клиент Сервер
(IP: 192.168.1.100) (IP: 10.0.0.1)
Клиент сообщает серверу:
"Подключайтесь ко мне на мой port N для данных"
Сервер инициирует подключение обратно к клиенту
Проблема: проходит через firewall'ы сложно, потому что сервер инициирует входящее соединение.
2. Passive Mode (PASV) — современный стандарт
Клиент Сервер
Клиент спрашивает:
"На каком порте я должен подключиться для данных?"
Сервер отвечает:
"Слушаю на port M"
Клиент инициирует оба соединения
Лучше, потому что клиент контролирует оба соединения.
FTP команды
Базовые команды:
USER <username> - Ввод пользователя
PASS <password> - Ввод пароля
PWD - Текущая директория
CWD <path> - Смена директории
LIST [path] - Список файлов (подробный)
MLSD [path] - Список файлов (машинный формат)
RETR <file> - Скачать файл
STOR <file> - Загрузить файл
APPE <file> - Дописать к файлу
DELE <file> - Удалить файл
MKD <dirname> - Создать директорию
RMD <dirname> - Удалить директорию
RENAME <old> <new> - Переименовать
QUIT - Завершить сессию
PASV - Passive mode
PORT <host,port> - Active mode
TYPE <A|I> - ASCII или Binary
Пример диалога
220 (vsFTPd 2.0.1) ready
USER admin
331 Please specify the password.
PASS secret123
230 Login successful.
PWD
257 "/home/admin"
LIST
150 Here comes the directory listing.
drwxr-xr-x 2 admin admin 4096 Dec 10 10:00 downloads
-rw-r--r-- 1 admin admin 1024000 Dec 10 15:30 file.txt
drwxr-xr-x 2 admin admin 4096 Dec 09 12:00 documents
226 Directory send OK.
RETR file.txt
150 Opening BINARY mode data connection
226 Transfer complete.
FTP в C/C++
libcurl — самая удобная библиотека
#include <curl/curl.h>
#include <iostream>
int main() {
CURL *curl = curl_easy_init();
if (!curl) return 1;
// Скачать файл по FTP
curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/file.txt");
curl_easy_setopt(curl, CURLOPT_USERPWD, "admin:password");
// Passive mode (recommended)
curl_easy_setopt(curl, CURLOPT_FTP_USE_EPSV, 1L);
FILE *fp = fopen("downloaded_file.txt", "wb");
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK) {
std::cerr << "Error: " << curl_easy_strerror(res) << std::endl;
}
fclose(fp);
curl_easy_cleanup(curl);
return 0;
}
Загрузка файла на FTP сервер
CURL *curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/uploads/");
curl_easy_setopt(curl, CURLOPT_USERPWD, "user:pass");
FILE *fp = fopen("myfile.txt", "rb");
struct stat file_info;
stat("myfile.txt", &file_info);
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
curl_easy_setopt(curl, CURLOPT_READDATA, fp);
curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)file_info.st_size);
// Имя файла на сервере будет составлено из URL
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "APPE /uploads/myfile.txt");
curl_easy_perform(curl);
fclose(fp);
curl_easy_cleanup(curl);
Низкоуровневая реализация (raw sockets)
#include <socket.h>
#include <cstring>
#include <iostream>
int main() {
int ctrl_fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(21);
inet_pton(AF_INET, "192.168.1.100", &addr.sin_addr);
connect(ctrl_fd, (struct sockaddr*)&addr, sizeof(addr));
// Читаем приветствие
char buffer[1024];
read(ctrl_fd, buffer, sizeof(buffer));
std::cout << buffer; // 220 FTP Server Ready
// Отправляем команду USER
const char *cmd = "USER admin\r\n";
write(ctrl_fd, cmd, strlen(cmd));
read(ctrl_fd, buffer, sizeof(buffer));
std::cout << buffer; // 331 Password required
// Отправляем пароль
cmd = "PASS secret123\r\n";
write(ctrl_fd, cmd, strlen(cmd));
read(ctrl_fd, buffer, sizeof(buffer));
std::cout << buffer; // 230 Login successful
close(ctrl_fd);
return 0;
}
Проблемы и ограничения FTP
1. Security issues
- Пароль передаётся в открытом виде (не зашифрован)
- Нет аутентификации сервера
- Man-in-the-middle атаки возможны
Решение: SFTP (SSH File Transfer Protocol) или FTPS (FTP over SSL/TLS)
2. NAT и Firewall
- Active mode не работает за NAT
- Passive mode требует range портов открытых на сервере
3. Производительность
- Для каждого файла — новое соединение
- Неэффективно для передачи множества файлов
Решение: HTTP/2, S3 API, rsync, etc.
4. Stateful протокол
- Сложнее масштабировать (нельзя распределить между несколькими серверами)
- Требует хранения состояния соединений
SFTP — современная альтернатива
// SFTP (подсистема SSH) — должен использоваться вместо FTP
// Зашифрован, безопаснее
curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com/file.txt");
curl_easy_setopt(curl, CURLOPT_SSH_PUBLIC_KEYFILE, "/home/user/.ssh/id_rsa.pub");
curl_easy_setopt(curl, CURLOPT_SSH_PRIVATE_KEYFILE, "/home/user/.ssh/id_rsa");
Когда всё ещё используется FTP?
- Legacy системы — старые сервера, которые обновлять слишком дорого
- Anonymous file sharing — если нужен свободный доступ к файлам
- Внутренние сети — когда security не критичен
- Embedded системы — без SSH, использует FTP как временное решение
Но в новых проектах следует избегать FTP в пользу SFTP, HTTP, S3, rsync.
Вывод
FTP — это исторический протокол, который всё ещё встречается в production. Основные моменты:
- Два соединения: control (port 21) и data
- Passive и Active режимы
- Текстовые команды (USER, PASS, RETR, STOR, LIST, etc.)
- libcurl делает работу с FTP простой
- Уязвим — используй SFTP вместо FTP в новых системах
Понимание FTP важно для работы с legacy системами и интеграции с различными платформами.