Как контролируется надежность соединения в TCP?

«Как контролируется надежность соединения в TCP?» — вопрос из категории Сети, который задают на 25% собеседований C/C++ Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

TCP обеспечивает надежную доставку данных через несколько ключевых механизмов:

  1. Последовательные номера и подтверждения (ACK): Каждый отправленный байт имеет номер. Получатель отправляет ACK-пакет с номером следующего ожидаемого байта, подтверждая получение.
  2. Таймауты и повторная передача: Если отправитель не получает ACK в течение заданного времени (RTO — Retransmission Timeout), пакет передается повторно.
  3. Контроль потока (Flow Control): Используется окно приема (receive window), чтобы отправитель не перегружал получателя данными.
  4. Контроль перегрузки (Congestion Control): Алгоритмы (например, CUBIC или Reno) динамически регулируют размер окна перегрузки (congestion window) на основе потерь пакетов и задержек, предотвращая перегрузку сети.

Практический пример на C++ (упрощенная логика ожидания ACK):

#include <sys/socket.h>
#include <unistd.h>
#include <chrono>

bool sendWithRetry(int socket_fd, const void* buffer, size_t length, int max_retries) {
    int retries = 0;
    while (retries < max_retries) {
        ssize_t bytes_sent = send(socket_fd, buffer, length, 0);
        if (bytes_sent == -1) {
            // Ошибка отправки
            return false;
        }
        // Здесь должна быть логика ожидания и проверки ACK (например, через select/poll)
        // Для примера — просто задержка.
        std::this_thread::sleep_for(std::chrono::milliseconds(200));
        // Если ACK получен (проверка не показана), выходим.
        bool ack_received = checkForAck(socket_fd); // Предполагаемая функция
        if (ack_received) {
            return true;
        }
        // ACK не пришел, повторяем отправку.
        retries++;
    }
    return false; // Все попытки исчерпаны
}