← Назад к вопросам
Как TCP подтверждает доставку пакета?
1.7 Middle🔥 171 комментариев
#Сетевые протоколы и API
Комментарии (1)
🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Механизм подтверждения доставки в TCP
TCP (Transmission Control Protocol) является надежным протоколом транспортного уровня, который гарантирует доставку данных получателю. Основу этого механизма составляет подтверждение (ACK — acknowledgement) и последовательные номера байтов. Вот как это работает детально:
Основные принципы
- Нумерация байтов: Каждый передаваемый байт данных имеет свой порядковый номер (sequence number). Отправитель указывает в заголовке TCP номер первого байта в сегменте.
- Подтверждения (ACK): Получатель отправляет подтверждение, указывая номер следующего ожидаемого байта. Например, ACK=1001 означает: «Я успешно получил все байты до 1000 и ожидаю байт с номером 1001».
- Дуплексная связь: Подтверждения могут отправляться вместе с данными в обратном направлении (piggybacking), что повышает эффективность.
Процесс подтверждения шаг за шагом
Отправитель (Клиент) Получатель (Сервер)
| |
| --- Сегмент [SEQ=1, DATA] --> |
| |
| <-- ACK [ACK=101] ----------- |
| (подтверждены байты 1-100) |
| |
| --- Сегмент [SEQ=101, DATA] ->|
| |
| <-- ACK [ACK=201] ----------- |
- Передача сегмента: Отправитель отправляет сегмент данных с указанием начального номера последовательности (
SEQ) и размера данных (например, 100 байт). - Подтверждение приема: Получатель, успешно приняв данные, отправляет сегмент ACK, где поле
ACKсодержит номер следующего ожидаемого байта (в примере выше: 1 + 100 = 101). - Таймауты и повторная передача: Если отправитель не получил 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 адаптироваться к различным сетевым условиям, минимизируя задержки и максимизируя пропускную способность.