Введение

Транспортный уровень. Протокол TCP: соединение, скользящее окно, управление потоком и перегрузкой

На этом занятии вы углубитесь в механизмы TCP: как устанавливается и разрывается соединение (трёхкратное рукопожатие и завершение), как работает скользящее окно для эффективной доставки без ожидания подтверждения каждого сегмента, а также управление потоком (чтобы не затопить медленного получателя) и управление перегрузкой (чтобы не перегрузить сеть).

В практике вы разберёте в Wireshark установку и разрыв TCP-соединения, передачу данных и поля заголовка, связанные с окном.

Этапы передачи в TCP

Три этапа процесса передачи

Передача данных по протоколу TCP состоит из трёх этапов. Сначала необходимо установить соединение между отправителем и получателем. Затем по установленному соединению передаются данные. После завершения обмена соединение корректно разрывается.

В отличие от UDP, где данные можно отправить сразу, в TCP перед первой порцией данных всегда идёт обмен служебными сегментами для установки соединения, а после передачи - для разрыва. Это создаёт дополнительные накладные расходы, но позволяет реализовать надёжность и согласование параметров.

Зачем нужно соединение

Цели установки соединения

Установка соединения в TCP нужна по нескольким причинам. Во-первых, стороны убеждаются, что отправитель и получатель готовы передавать и принимать данные. Во-вторых, происходит синхронизация нумерации потока байт: стороны договариваются о начальных номерах (ISN), с которых будут нумероваться байты в каждом направлении. В-третьих, можно согласовать дополнительные параметры протокола (например, максимальный размер сегмента MSS, масштаб окна, выборочные подтверждения SACK).

Трёхкратное рукопожатие

Шаг 1: сегмент SYN

Установка соединения выполняется процедурой, которая называется трёхкратное рукопожатие (three-way handshake). На первом шаге сторона, инициирующая соединение (клиент), отправляет сегмент, в заголовке которого установлен флаг SYN (synchronization). В этом же сегменте указывается начальный порядковый номер (ISN) - номер, с которого отправитель будет нумеровать байты своих данных в этом соединении.

Например, отправитель может выбрать ISN 7537. Этот номер не обязан быть нулём: он выбирается для защиты от смешивания сегментов старых и новых «инкарнаций» соединения при сбоях и перезагрузках.

Трёхкратное рукопожатие

Шаг 2: сегмент SYN+ACK

Получатель (сервер) в ответ отправляет сегмент, в котором установлены два флага: SYN и ACK. Флаг ACK означает, что поле «номер подтверждения» значимо: получатель подтверждает получение сегмента SYN и указывает номер следующего ожидаемого байта (например, 7538). Одновременно получатель устанавливает флаг SYN и сообщает свой начальный порядковый номер для данных в обратную сторону (например, 36829). Таким образом, за один сегмент получатель и подтверждает приход запроса, и синхронизирует свою нумерацию.

Трёхкратное рукопожатие

Шаг 3: сегмент ACK

Инициатор соединения отправляет третий сегмент с установленным флагом ACK. В нём указывается номер подтверждения - следующий ожидаемый байт от получателя (36830), а данные в этом сегменте начинаются с номера 7538. После этого оба направления синхронизированы: отправитель нумерует свои байты с 7537, получатель - с 36829. Соединение считается установленным, и можно передавать данные.

1) Клиент -> Сервер: SYN, ISN=7537 2) Сервер -> Клиент: SYN, ACK, ISN=36829, ACK=7538 3) Клиент -> Сервер: ACK, ACK=36830 Соединение установлено.
Зачем синхронизация номеров

Защита от инкарнаций соединения

Почему нельзя всегда нумеровать байты с нуля? Из-за сбоев сети возможны ситуации с несколькими «инкарнациями» одного и того же логического соединения. Например, отправитель установил соединение, начал передавать данные, затем произошла перезагрузка приложения. Отправитель заново устанавливает соединение и снова передаёт данные. Если нумеровать с нуля, старые задержавшиеся в сети сегменты могут прийти после установки нового соединения, и получатель не сможет однозначно определить, к какой инкарнации они относятся.

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

Разрыв соединения

Корректный разрыв: флаг FIN

Соединение TCP дуплексное: данные могут идти в обе стороны. Поэтому разрыв выполняется с двух сторон. Чтобы разорвать свою половину соединения, сторона отправляет сегмент с установленным флагом FIN (finish). Вторая сторона подтверждает получение запроса на разрыв (ACK). После этого направление «от отправителя FIN к получателю» закрыто - данные в эту сторону передавать нельзя. Но обратное направление ещё открыто.

Когда вторая сторона тоже хочет завершить передачу, она отправляет свой сегмент с FIN и получает ACK. Только после этого соединение считается полностью разорванным.

Быстрый разрыв

Флаг RST (reset)

Для быстрого разрыва соединения без ожидания подтверждений используется сегмент с флагом RST (reset). В этом случае соединение разрывается сразу в обе стороны. RST обычно применяют при ошибках или когда одна из сторон не хочет принимать соединение. В нормальном сценарии закрытия приложения предпочтителен корректный разрыв по FIN.

Александр
То есть три пакета туда-обратно - и только потом данные? Да, накладные расходы заметные.
Подтверждение доставки

Остановка и ожидание vs скользящее окно

В сетях используются два основных подхода к подтверждению доставки. Остановка и ожидание (stop-and-wait): отправитель передаёт одну порцию данных, останавливается и ждёт подтверждения; получив ACK, передаёт следующую порцию. Такой метод часто применяется на канальном уровне (например, в Wi-Fi).

В TCP используется другой подход - скользящее окно: отправитель может отправить несколько сегментов подряд, не дожидаясь подтверждения каждого. Получатель может подтвердить сразу несколько полученных сегментов одним кумулятивным подтверждением. Это значительно повышает эффективность использования канала в составных сетях с ненулевой задержкой.

Скользящее окно

Почему не останавливаться после каждого сегмента

При времени оборота (RTT) 10 мс и передаче по одному сегменту за раз за секунду можно отправить только около 100 сегментов. При типичном размере полезных данных в сегменте порядка 1460 байт это даёт примерно 143 Кбит/с - для современных гигабитных каналов крайне мало. Поэтому в TCP выгодно отправлять в сеть несколько сегментов подряд, не дожидаясь ACK на каждый - для этого и служит механизм скользящего окна.

Что такое окно

Окно - данные без подтверждения

Окно в контексте TCP - это данные (байты), которые уже отправлены в сеть, но получение которых ещё не подтверждено. Размер окна - это количество байт, которые разрешено передать в сеть без получения подтверждения. Сегменты, получение которых уже подтверждено, считаются «слева» от окна; ещё не отправленные - «справа». Окно «скользит» вперёд по потоку байт по мере прихода подтверждений: после ACK граница сдвигается, и можно отправлять новые данные.

Кумулятивное подтверждение

Один ACK на несколько сегментов

В TCP по умолчанию используется кумулятивное подтверждение. В поле «номер подтверждения» указывается номер следующего ожидаемого байта. Это означает: «все байты до этого номера (не включая его) получены». Таким образом, один ACK подтверждает доставку всех предыдущих байт. Это удобно и экономит трафик. Кумулятивное подтверждение хорошо подходит для окон небольшого размера.

Выборочное подтверждение

SACK (Selective Acknowledgement)

При большом размере окна может быть потерян один сегмент в середине потока. При только кумулятивном подтверждении отправитель вынужден повторно передавать все данные начиная с потерянного сегмента. Выборочное подтверждение (SACK) позволяет явно указать диапазоны уже полученных блоков данных. Тогда отправитель повторяет только реально потерянный фрагмент. SACK не используется по умолчанию - стороны должны согласовать его при установке соединения (опция в handshake).

Мария
Окно в заголовке TCP - это то же самое «скользящее окно»?
Дмитрий
Поле Window в заголовке - это про управление потоком: сколько байт готов принять получатель. А «скользящее окно» - общая идея, сколько можно слать без ACK; итоговый размер учитывает и получателя, и перегрузку.
Управление потоком

Зачем нужно управление потоком

Управление потоком (flow control) в TCP - это предотвращение затопления медленного получателя быстрым отправителем. Устройства в сети имеют разную производительность и разный размер буферов. Если отправитель (например, мощный сервер) будет слать данные слишком быстро, буфер на стороне получателя (например, смартфона) переполнится, лишние сегменты будут отброшены, и их придётся передавать заново. Управление потоком решает эту проблему.

Поле «размер окна» в заголовке

Буфер получателя и Window

Данные, приходящие по TCP, попадают в буфер операционной системы, откуда их читает приложение. Если приложение читает медленно или занято, буфер заполняется. В заголовке TCP получатель передаёт в каждом сегменте поле Window (размер окна) - сколько байт он готов принять. По сути, это объём свободного места в буфере. Отправитель не должен отправлять больше данных, чем указано в размере окна, иначе они могут быть отброшены.

Окно нулевого размера

Zero Window и Zero Window Probe

Если буфер получателя заполнен, он может отправить подтверждение с размером окна 0. Это значит: «пока не готов принимать данные». Отправитель останавливает передачу и ждёт. Когда приложение прочитает данные из буфера, получатель отправит новое подтверждение с ненулевым размером окна. Если такое сообщение потеряется, отправитель может периодически отправлять небольшой сегмент-зонд (Zero Window Probe), чтобы получить актуальный размер окна.

Управление перегрузкой

Зачем и что такое перегрузка

Проблема перегрузки связана уже не с получателем, а с сетью. Если много отправителей одновременно передают много данных, маршрутизаторы и каналы не справляются - пакеты отбрасываются, отправители повторяют передачу, нагрузка растёт. В 1986 году в интернете произошёл коллапс перегрузки: каналы были забиты, но полезная скорость упала на порядки. После этого в TCP ввели механизмы управления перегрузкой (congestion control), чтобы размер отправляемых данных зависел от загрузки сети.

Два окна в TCP

Окно перегрузки и окно управления потоком

В TCP фактически используются два ограничения на объём неподтверждённых данных. Окно управления потоком задаётся получателем (поле Window в заголовке) - сколько байт он может принять. Окно перегрузки вычисляется отправителем на основе сигналов о загрузке сети (потери, задержки, явные уведомления ECN). Итоговый размер окна, которым руководствуется отправитель, - минимум из этих двух значений.

AIMD

Аддитивное увеличение, мультипликативное уменьшение

Один из базовых алгоритмов управления перегрузкой - AIMD (Additive Increase, Multiplicative Decrease). При отсутствии признаков перегрузки размер окна перегрузки понемногу увеличивается (например, на размер одного сегмента за каждое подтверждение). При появлении перегрузки (например, потеря сегмента) окно уменьшается в несколько раз (часто вдвое). Так протокол «нащупывает» подходящую скорость: осторожно наращивает и резко снижает при перегрузке. График размера окна во времени напоминает пилу.

Медленный старт

Slow Start

Чистый AIMD на быстрых каналах приводит к медленному росту окна. Поэтому в TCP дополнительно используется медленный старт (slow start): в начале передачи окно перегрузки небольшое (например, 2-4 сегмента), а при получении каждого ACK окно увеличивается (например, удваивается), пока не достигнет порога. После этого применяется более плавное аддитивное увеличение. При сигнале перегрузки окно снова снижается. Детали описаны в RFC 5681.

Сигналы перегрузки

Как TCP узнаёт о перегрузке

Перегрузку можно определить по нескольким признакам. Самый надёжный - потеря сегмента (нет подтверждения, сработал таймаут или пришли дубликаты ACK). Часто потеря в современных сетях связана именно с перегрузкой. Другой признак - задержка: подтверждения приходят заметно позже. Третий - явное уведомление о перегрузке (ECN) от маршрутизаторов, если в сети поддерживается механизм ECN. На основе этих сигналов отправитель уменьшает окно перегрузки.

Окно управления потоком: задаёт получатель (Window в заголовке). Окно перегрузки: вычисляет отправитель (AIMD, slow start). Итог: min(окно потока, окно перегрузки).
Итог по теме

Краткое резюме

Установка соединения TCP - трёхкратное рукопожатие (SYN, SYN+ACK, ACK); разрыв - по FIN с каждой стороны или RST для сброса. Скользящее окно позволяет отправлять несколько сегментов без ожидания ACK; подтверждение может быть кумулятивным или выборочным (SACK). Управление потоком - через поле Window в заголовке (буфер получателя); управление перегрузкой - через окно перегрузки на стороне отправителя (AIMD, медленный старт). Итоговое окно - минимум из окна потока и окна перегрузки.

Далее - интерактивные задания, тест допуска и практика в Wireshark.

Задание 1

Порядок этапов трёхкратного рукопожатия

Расставьте этапы установки соединения TCP в правильном порядке (перетащите блоки).

  • Сервер отправляет SYN+ACK и свой ISN
  • Клиент отправляет SYN с начальным номером (ISN)
  • Клиент отправляет ACK, соединение установлено
Задание 2

Скользящее окно и подтверждения

Выберите верные утверждения.

Задание 3

Сопоставление: окно и сторона

Окно управления потоком (поле Window)
Окно перегрузки
Задание 4

Разрыв соединения и алгоритмы перегрузки

Какой флаг TCP используется для корректного разрыва соединения (каждая сторона закрывает свою половину)?

Что делают при перегрузке в алгоритме AIMD?

Финальный допуск

Краткий тест (8 вопросов)

Для доступа к практике нужно набрать не менее 80% - минимум 7 правильных ответов из 8.

1. Установка соединения TCP называется:

2. В первом сегменте установки соединения установлен флаг:

3. Для быстрого разрыва соединения без ожидания подтверждения используется флаг:

4. Скользящее окно в TCP нужно для:

5. Поле Window в заголовке TCP (управление потоком) задаётся:

6. Окно перегрузки в TCP определяет:

7. Алгоритм AIMD - это:

8. Итоговый размер окна, которым руководствуется отправитель TCP, равен:

Практика

Практика: анализ TCP в Wireshark - соединение, данные, разрыв

Вы выполните пошаговые действия за компьютером: откроете сайт по HTTP (например, networks.ru или другой без шифрования), захватите трафик в Wireshark, примените фильтр по IP сайта. Затем разберёте установку соединения (три сегмента: SYN, SYN+ACK, ACK), передачу данных (поток байт, флаг PSH), разрыв соединения (FIN, ACK с обеих сторон). Файл для сдачи не требуется - проверка по результату на экране и по контрольным вопросам.

Практика - Шаг 1

Подготовка: браузер и Wireshark

1Откройте Wireshark и выберите активный сетевой интерфейс (через который вы выходите в интернет). Запустите захват трафика. Откройте браузер и перейдите на сайт по HTTP без шифрования (например, http://networks.ru или http://example.com). После загрузки страницы остановите захват в Wireshark.
Практика - Шаг 2

Фильтр по IP адресу сайта

2В Wireshark примените фильтр по IP-адресу сервера (например, ip.addr == 93.184.216.34 для example.com или адрес вашего сайта). Так вы увидите только трафик между вашим компьютером и выбранным хостом. Убедитесь, что в списке есть TCP-пакеты.
Практика - Шаг 3

Найдите установку соединения

3Найдите группу пакетов, относящихся к одному TCP-соединению (один и тот же порт клиента и порт 80). Первые три пакета обмена - это трёхкратное рукопожатие. Выберите первый пакет и разверните в нижней панели заголовок TCP.
Практика - Шаг 4

Первый сегмент - SYN

4В первом сегменте установки соединения найдите флаги: должен быть установлен SYN. Поля Sequence number и Acknowledgment number: в первом сегменте номер подтверждения обычно 0 (ничего ещё не подтверждаем). Запишите порт отправителя (клиента) и порт получателя (80).
Практика - Шаг 5

Второй сегмент - SYN, ACK

5Выберите второй пакет handshake. В нём должны быть установлены флаги SYN и ACK. Номер подтверждения (Acknowledgment number) на единицу больше порядкового номера первого сегмента - сервер подтверждает получение SYN. Запишите порядковый номер, который сервер использует для своих данных.
Практика - Шаг 6

Третий сегмент - ACK

6Третий пакет - только флаг ACK. В нём клиент подтверждает получение SYN от сервера. После этих трёх сегментов соединение установлено. Убедитесь, что дальше идут пакеты с данными (например, HTTP).
Практика - Шаг 7

Передача данных - порты и номера

7Выберите пакет с данными (например, HTTP-запрос или ответ). В заголовке TCP найдите Sequence number и Acknowledgment number. Обратите внимание на поле Window size - размер окна управления потоком. В сегментах с данными часто установлен флаг PSH (push) - данные можно передать приложению.
Практика - Шаг 8

Разрыв соединения - FIN

8В конце обмена найдите сегменты с флагом FIN. Обычно сначала один участник отправляет FIN (и ACK), второй отвечает ACK, затем второй отправляет свой FIN и получает ACK. Всего четыре сегмента для полного разрыва двухстороннего соединения. Убедитесь, что видите оба направления закрытия.
Практика - Шаг 9

Опции в handshake

9Вернитесь к первому или второму сегменту установки соединения. Разверните блок опций TCP (Options). Проверьте, есть ли опция MSS (Maximum Segment Size), Window scale, SACK Permitted. Запишите значение MSS для вашего соединения.
Практика - Шаг 10

Второе соединение (параллельное)

10Браузеры часто открывают несколько TCP-соединений к одному серверу (разные порты клиента, один порт 80). Найдите второе соединение и убедитесь, что в нём тоже видны три сегмента установки, обмен данными и разрыв. Порядок пакетов от двух соединений может чередоваться.
Практика - Шаг 11

Контрольные вопросы

Ответьте себе (устно или в тетради):

  • Сколько сегментов потребовалось для установки одного TCP-соединения? Назовите флаги в каждом.
  • Какой порт источника (клиента) и порт назначения вы видели?
  • В каком сегменте передаётся размер окна (Window)? Менялся ли он в ходе обмена?
  • Сколько сегментов участвовало в разрыве соединения (FIN/ACK с обеих сторон)?

Если вы уверенно находите в Wireshark этапы установки, передачи и разрыва - вы закрепили тему занятия.