Установка соединения
TCP-соединение открывается тройным рукопожатием:
клиент → SYN (мой начальный номер — x)
клиент ← SYN-ACK (принял x, мой номер — y)
клиент → ACK (принял y)
Стороны обмениваются начальными номерами последовательности — от них считаются все байты потока. До первых данных проходит один полный оборот (RTT). Для HTTPS к нему добавляется рукопожатие TLS, поэтому новое соединение с далёким сервером стоит десятки и сотни миллисекунд.
Закрытие и TIME_WAIT
Соединение закрывается по половинам: каждая сторона отправляет FIN и получает ACK. Тот, кто закрыл первым, переходит в TIME_WAIT и держит запись о соединении 2×MSL — в Linux 60 секунд. Это защищает новое соединение с тем же адресом и портом от запоздавших пакетов старого.
Тысячи соединений в TIME_WAIT на клиенте — признак того, что он открывает новое соединение на каждый запрос. Лечится пулом соединений и keep-alive, а не настройками ядра.
RST — аварийный разрыв без вежливого закрытия.
Надёжная доставка
Каждый байт пронумерован. Получатель подтверждает принятое (ACK), неподтверждённое отправляется повторно — по таймауту или после трёх одинаковых ACK, которые сигнализируют о дыре в потоке. Получатель собирает байты в правильном порядке, даже если пакеты пришли вразнобой.
Два окна
TCP ограничивает, сколько данных можно отправить без подтверждения:
- окно получателя (flow control) — сколько он готов принять, чтобы не переполнить свой буфер;
- окно перегрузки (congestion control) — сколько, по оценке отправителя, выдержит сеть.
Новое соединение начинает с медленного старта: окно удваивается каждый RTT до первой потери, дальше растёт линейно, а при потере уменьшается. Отсюда полезная оценка: пропускная способность одного соединения ≈ окно / RTT. Через океан с RTT 150 мс даже широкий канал не заполняется одним соединением с маленьким окном.
Почему не всегда TCP
Гарантии TCP стоят задержки: потерянный пакет задерживает всё, что идёт за ним (блокировка начала очереди). Для голоса и игр опоздавшие данные уже не нужны — им подходит UDP. HTTP/2 мультиплексирует потоки в одном TCP-соединении, но одна потеря тормозит их все. HTTP/3 поэтому перешёл на QUIC поверх UDP — там каждый поток восстанавливается независимо.
TLS поверх TCP
TLS добавляет шифрование, целостность и подлинность сервера. В рукопожатии стороны договариваются об общем ключе по схеме Диффи — Хеллмана, сервер подтверждает сертификатом, что он тот, за кого себя выдаёт. Дальше данные шифруются симметрично. В TLS 1.3 рукопожатие занимает один RTT, используются только стойкие шифры с прямой секретностью: перехваченный трафик не расшифровать даже после утечки ключа сервера.
mTLS — сертификат предъявляет и клиент; так сервисы внутри компании проверяют друг друга.
Что запомнить
- SYN, SYN-ACK, ACK — один RTT до данных, плюс TLS.
- TIME_WAIT у клиента лечится пулом соединений.
- Надёжность — нумерация, подтверждения и повторы.
- Окно получателя бережёт его, окно перегрузки — сеть.
- Потеря пакета в TCP задерживает весь поток — отсюда QUIC.