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

Как TCP подтверждает доставку пакета?

1.7 Middle🔥 171 комментариев
#Сетевые протоколы и API

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

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

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

Механизм подтверждения доставки в TCP

TCP (Transmission Control Protocol) является надежным протоколом транспортного уровня, который гарантирует доставку данных получателю. Основу этого механизма составляет подтверждение (ACK — acknowledgement) и последовательные номера байтов. Вот как это работает детально:

Основные принципы

  1. Нумерация байтов: Каждый передаваемый байт данных имеет свой порядковый номер (sequence number). Отправитель указывает в заголовке TCP номер первого байта в сегменте.
  2. Подтверждения (ACK): Получатель отправляет подтверждение, указывая номер следующего ожидаемого байта. Например, ACK=1001 означает: «Я успешно получил все байты до 1000 и ожидаю байт с номером 1001».
  3. Дуплексная связь: Подтверждения могут отправляться вместе с данными в обратном направлении (piggybacking), что повышает эффективность.

Процесс подтверждения шаг за шагом

Отправитель (Клиент)              Получатель (Сервер)
       |                               |
       | --- Сегмент [SEQ=1, DATA] --> |
       |                               |
       | <-- ACK [ACK=101] ----------- |
       | (подтверждены байты 1-100)    |
       |                               |
       | --- Сегмент [SEQ=101, DATA] ->|
       |                               |
       | <-- ACK [ACK=201] ----------- |
  1. Передача сегмента: Отправитель отправляет сегмент данных с указанием начального номера последовательности (SEQ) и размера данных (например, 100 байт).
  2. Подтверждение приема: Получатель, успешно приняв данные, отправляет сегмент ACK, где поле ACK содержит номер следующего ожидаемого байта (в примере выше: 1 + 100 = 101).
  3. Таймауты и повторная передача: Если отправитель не получил ACK в течение заданного времени (RTO — Retransmission Timeout), он повторно отправляет тот же сегмент.

Ключевые механизмы надежности

1. Скользящее окно (Sliding Window)

// Упрощенная концепция скользящего окна в Go
type TCPReceiver struct {
    nextExpectedSeq uint32 // следующий ожидаемый номер байта
    windowSize      uint16 // размер окна приема
    buffer          []byte // буфер для хранения данных
}

func (r *TCPReceiver) processSegment(seqNum uint32, data []byte) []byte {
    // Проверяем, находится ли сегмент в пределах окна
    if seqNum >= r.nextExpectedSeq && seqNum < r.nextExpectedSeq+uint32(r.windowSize) {
        // Обработка данных и отправка ACK
        ack := r.nextExpectedSeq + uint32(len(data))
        return createAckSegment(ack)
    }
    return nil
}

2. Выборочные подтверждения (SACK — Selective ACK)

  • Позволяет подтверждать отдельные блоки данных при потере промежуточных сегментов
  • Уменьшает количество повторных передач в условиях частичной потери

3. Быстрая повторная передача (Fast Retransmit)

  • При получении трех дубликатов ACK для одного сегмента отправитель немедленно повторяет передачу, не дожидаясь таймаута
  • Эффективно при потере отдельных пакетов в сети

4. Избыточные ACK (Duplicate ACK)

Ситуация потери пакета:
Клиент отправляет пакеты: 1-100, 101-200, 201-300, 301-400
Сервер получает: 1-100, 201-300 (101-200 потерян)

Сервер отправляет:
ACK=101 (за 1-100)
ACK=101 (за 201-300 — дубликат, так как ожидается 101)
ACK=101 (третий дубликат) → запускает быструю повторную передачу

Особенности реализации

  • Отложенные подтверждения (Delayed ACK): Получатель может задержать отправку ACK до 500 мс в ожидании данных для обратной передачи или получения дополнительных сегментов.
  • Частичные ACK: Если подтверждается только часть отправленных данных, отправитель повторяет передачу начиная с первого неподтвержденного байта.
  • Измерение RTT: TCP динамически вычисляет время круговой задержки (Round-Trip Time) для адаптивной настройки таймаутов.

Практический пример обработки ACK

// Упрощенная реализация обработки подтверждений
type TCPSender struct {
    sendBuffer    map[uint32][]byte // буфер отправленных данных
    nextSeqNum    uint32            // следующий номер для отправки
    lastAckReceived uint32          // последнее полученное подтверждение
}

func (s *TCPSender) handleAck(ackNum uint32) {
    // Удаляем подтвержденные данные из буфера
    for seq := range s.sendBuffer {
        if seq < ackNum {
            delete(s.sendBuffer, seq)
        }
    }
    
    // Если есть неподтвержденные данные и превышен таймаут
    if len(s.sendBuffer) > 0 && time.Since(lastSendTime) > rto {
        s.retransmitOldestUnacked()
    }
}

Важные аспекты надежности

  • Управление перегрузкой: Помимо подтверждений доставки, TCP использует механизмы контроля перегрузки (алгоритмы Reno, CUBIC), которые регулируют размер окна передачи на основе полученных ACK.
  • Порядок доставки: TCP гарантирует порядок доставки данных — даже если пакеты приходят в неправильном порядке, получатель собирает их в правильной последовательности перед передачей приложению.
  • Установка и завершение соединения: Механизм подтверждения используется на всех этапах работы TCP, включая трехэтапное рукопожатие (SYN, SYN-ACK, ACK) и четырехэтапное завершение соединения.

Таким образом, подтверждение доставки в TCP — это комплексный механизм, сочетающий нумерацию байтов, подтверждения, таймауты и повторные передачи, который обеспечивает надежную доставку данных даже в условиях нестабильных сетевых соединений. Этот подход позволяет TCP адаптироваться к различным сетевым условиям, минимизируя задержки и максимизируя пропускную способность.