← Назад к вопросам

Что такое FTP протокол?

1.2 Junior🔥 251 комментариев
#Сети и протоколы

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Протокол 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?

  1. Legacy системы — старые сервера, которые обновлять слишком дорого
  2. Anonymous file sharing — если нужен свободный доступ к файлам
  3. Внутренние сети — когда security не критичен
  4. 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 системами и интеграции с различными платформами.

Что такое FTP протокол? | PrepBro