Кратко

  • Накопительное подтверждение TCP останавливается на первом пропуске. SACK позволил получателю назвать участки данных, пришедшие после отсутствующего фрагмента.
  • RFC 2018 разрешил получателю избавиться от ранее объявленных данных. Отправитель обязан хранить свою копию, пока накопительное подтверждение не дойдёт до неё.

В архив приходят страницы первая, вторая и четвёртая. Штамп приёма можно поставить только до второй: третья потерялась. Сотрудник пишет карандашом, что четвёртая лежит на столе. Когда стол переполнится, он вправе убрать бумагу. В TCP разница между штампом и пометкой оказалась решающей для восстановления потока.

RFC 1072 1988 года объяснял проблему на каналах с большим произведением пропускной способности на задержку. После потери одного сегмента накопительное число застывало. Отправитель не видел по нему, какие следующие части уже доставлены. Новые круги ожидания замедляли исправление; повторная передача наугад тратила канал. Выборочный отчёт должен был показать островки данных за дырой. RFC 1072 предлагал эксперимент, а окончательное описание опции появилось позже.

В октябре 1996 года RFC 2018 определил опцию SACK. Прежде чем получатель мог её посылать, другая сторона должна была объявить SACK-Permitted в начальном SYN. Обычное число подтверждения осталось в заголовке TCP и по-прежнему отмечало непрерывно полученный префикс. Блоки SACK обозначали границы интервалов, принятых дальше. На одном конверте оказалось два разных сообщения: до какой страницы дошёл штамп и какие разрозненные страницы сейчас лежат на столе.

Места для второго сообщения было мало. Поле опций TCP не вмещало произвольное число островков. RFC 2018 отдавал первый блок тому интервалу, куда входил сегмент, вызвавший ACK, если только тот сегмент не продвинул накопительное число. Остальные доступные места следовало использовать для других интервалов; повтор недавно названных блоков помогал пережить потерю ACK. У отправителя появлялась полезная, но ограниченная карта чужой очереди.

Раздел 8 разрушал удобную иллюзию надёжного сейфа. Получатель мог выбросить принятые вне порядка данные, которые уже объявил через SACK, в частности из-за нехватки буфера. Это называется reneging. В следующих отчётах нельзя было продолжать показывать старые выброшенные интервалы как сохранённые. Особое правило первого блока всё равно сообщало о новейшем прибытии, даже если получатель собирался сразу от него избавиться. Отчёт свидетельствовал о доставке и состоянии очереди в тот миг; гарантию хранения он не выдавал.

Отправителю досталось жёсткое правило: не удалять байты, пока их не накрыло накопительное подтверждение. SACK помогал выбрать, что переслать в первую очередь, и временно обойти участки, которые выглядели доставленными. Исходная копия оставалась доступной. Если на другой стороне освободили буфер раньше, чем пришёл недостающий сегмент, восстановление ещё можно было выполнить.

RFC 2883, опубликованный в июле 2000 года, нашёл для той же опции ещё одну работу. D-SACK сообщал о повторно полученных данных. Смысл накопительного поля и расписание ACK оставались прежними. Дубликат мог попасть только в один ACK; потеря этого пакета стирала подсказку. Даже подробная квитанция должна была сама доехать.

SACK избавил отправителя от части догадок при повреждённой последовательности. При этом протокол оставил старое правило хорошего архива: по карандашной записи можно решать, что доставлять дальше. Последний экземпляр выбрасывают лишь после того, как официальный штамп догонит его.