Как контролируется надежность соединения в TCP?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Механизмы контроля надёжности соединения в TCP
Основная идея
TCP (Transmission Control Protocol) обеспечивает надёжную доставку данных благодаря комплексу механизмов, которые гарантируют:
- Все пакеты доходят до адресата
- В правильном порядке
- Без дублирования
- Без повреждения данных
1. Порядковые номера (Sequence Numbers)
Каждый байт данных в TCP имеет уникальный порядковый номер:
// TCP заголовок
struct tcp_header {
uint16_t src_port;
uint16_t dst_port;
uint32_t seq_number; // Порядковый номер этого пакета
uint32_t ack_number; // Подтверждение получения данных
uint8_t flags; // SYN, ACK, FIN, RST и т.д.
uint16_t window_size; // Размер окна приёмника
// ...
};
Функция: если пакет приходит не в порядке, TCP может переупорядочить данные или запросить повторную отправку
2. Подтверждение получения (ACK - Acknowledgment)
Приёмник отправляет обратно подтверждение:
Отправитель Приёмник
--------- SEQ=1000 ----->
DATA: 1000 байт
<-------- ACK=2000 -------
Получено до порядкового номера 2000
Механизм:
- Приёмник отправляет ACK с номером, равным SEQ+длина_данных
- Если отправитель не получает ACK за определённое время, переотправляет данные
- Используется Retransmission Timeout (RTO), который адаптивно вычисляется
3. Контрольная сумма (Checksum)
Каждый TCP пакет содержит контрольную сумму:
// Вычисление контрольной суммы
uint16_t tcp_checksum(tcp_header* hdr, void* data, int len) {
uint32_t sum = 0;
// Суммируем все 16-битные слова
uint16_t* words = (uint16_t*)hdr;
for (int i = 0; i < sizeof(*hdr) / 2; i++) {
sum += words[i];
}
words = (uint16_t*)data;
for (int i = 0; i < len / 2; i++) {
sum += words[i];
}
// Переполнение переносится в младшие биты
sum = (sum & 0xFFFF) + (sum >> 16);
sum = (sum & 0xFFFF) + (sum >> 16);
return ~sum;
}
Если контрольная сумма не совпадает: пакет считается повреждённым и отбрасывается
4. Скользящее окно (Sliding Window)
ТCP использует окно размером в несколько КБ:
Отправитель может отправить до N байт
без ожидания ACK на каждый пакет
[Отправлено] [Ожидание ACK] [Может быть отправлено]
|-----------|---|------------|-----|
0 100 200 900 1200
(размер окна приёмника = 1200 - 200 = 1000 байт)
Преимущества:
- Увеличивает пропускную способность
- Уменьшает задержку (не ждём ACK на каждый пакет)
- Динамический размер окна для адаптации к сети
5. Повторная отправка пакетов (Retransmission)
Если ACK не пришёл за время RTO:
// Псевдокод
while (packet_not_acked) {
send_packet();
wait_for_ack(rto_timeout);
if (!ack_received) {
rto *= 2; // Экспоненциальная задержка
// Повторить отправку
} else {
rto = recalculate_rto(); // Пересчитать RTO
break;
}
}
RTO вычисляется на основе:
- Round-Trip Time (RTT) — время в оба конца
- Вариативность RTT
- Обычно: RTO = RTT + 4 * Deviation
6. Обнаружение потерь пакетов
Три способа обнаружить потерю:
a) Timeout (Timeout-based retransmission)
Просто ждём ACK, и если не пришёл — переотправляем
b) Duplicate ACKs (Fast Retransmit)
Получены пакеты: SEQ 1000, 2000, потеря, 4000
Приёмник отправляет три раза ACK на 2000
"ещё не получил пакет с SEQ 2000"
Отправитель видит 3+ одинаковых ACK
и сразу переотправляет без ожидания timeout
c) SACK (Selective Acknowledgment)
Приёмник отправляет информацию о том,
какие блоки он УСПЕШНО получил
и какие потеряны
Отправитель может переотправить только потеряные
7. Управление потоком (Flow Control)
Приёмник может сказать отправителю: «Медленнее!»
// В TCP заголовке
Window = 65535; // Приёмник может принять столько байт
Если буфер приёмника переполняется, он отправляет Window = 0, и отправитель ждёт
8. Контроль перегрузки (Congestion Control)
ТCP адаптируется к нагрузке в сети:
- Slow Start: экспоненциальное увеличение скорости передачи
- Congestion Avoidance: линейное увеличение
- Fast Recovery: быстрое восстановление после потери
Алгоритмы: Reno, Cubic, BIC
Пример: гарантия доставки в коде
// Создание TCP сокета
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
connect(sock, ...);
// TCP гарантирует, что данные доходят
// даже если отправим несколько раз
send(sock, data, len, 0); // Переотправит при необходимости
// На приёмке — получим все данные в порядке
char buffer[1024];
recv(sock, buffer, sizeof(buffer), 0);
// Данные в buffer гарантированно в правильном порядке
Итого
Надёжность TCP обеспечивается комбинацией:
- Порядковых номеров и ACK
- Контрольных сумм
- Механизма повторной отправки
- Скользящего окна
- Обнаружения потерь (timeout, fast retransmit, SACK)
- Управления потоком и перегрузкой
Это делает TCP идеальным для приложений, где критична надёжность (HTTP, SMTP, SSH)