TCP

Материал из llmdocs — справочник разработчика
TCP
Полное названиеTransmission Control Protocol
АвторыВинтон Серф, Роберт Кан
СпецификацияRFC 793 (1981), актуальная — RFC 9293 (2022)
Уровеньтранспортный (модели OSI и TCP/IP)
Гарантиинадёжность, порядок, целостность, управление потоком и перегрузкой
Установление соединениятройное рукопожатие (SYN, SYN-ACK, ACK)
Алгоритмы перегрузкиReno, CUBIC (по умолчанию в Linux), BBR

TCP (англ. Transmission Control Protocol — протокол управления передачей) — транспортный протокол стека TCP/IP, который превращает ненадёжную доставку пакетов протоколом IP в надёжный упорядоченный поток байтов между двумя программами. TCP гарантирует, что данные дойдут полностью, без искажений и в том порядке, в каком были отправлены, а скорость передачи подстроится под возможности получателя и сети.

Поверх TCP работают HTTP/1.1 и HTTP/2, TLS, SSH, почтовые протоколы, протоколы баз данных — большая часть трафика интернета. Альтернатива для задач, где важнее скорость, чем гарантии, — UDP.

История

Винтон Серф и Роберт Кан описали протокол в 1974 году; позже его разделили на IP (маршрутизация) и TCP (надёжная доставка). Спецификация вышла как RFC 793 в 1981 году, а в 2022 году её переработали и объединили с последующими исправлениями в RFC 9293.[1] В 1986 году интернет пережил серию «коллапсов перегрузки», когда полезная пропускная способность падала в тысячу раз; Ван Якобсон в 1988 году предложил алгоритмы управления перегрузкой, которые спасли сеть и с изменениями используются до сих пор.[2]

Установление и завершение соединения

TCP — протокол с установлением соединения. Перед передачей данных стороны обмениваются тремя сегментами — тройное рукопожатие:

Клиент                         Сервер
  | ------ SYN (seq=x) ---------> |
  | <---- SYN-ACK (seq=y, ack=x+1) |
  | ------ ACK (ack=y+1) -------> |
  |      соединение установлено    |

Рукопожатие занимает один круг «туда-обратно» (RTT) до отправки первых данных, а TLS поверх TCP добавляет ещё один круг. Завершение — обмен сегментами FIN и ACK с каждой стороны; сторона, закрывшая соединение первой, проводит некоторое время в состоянии TIME_WAIT, чтобы опоздавшие пакеты не попали в новое соединение. Сегмент RST обрывает соединение немедленно — например, при попытке подключиться к закрытому порту.

Надёжность и порядок

  • Номера последовательности. Каждый байт потока имеет номер; получатель собирает данные по порядку, даже если пакеты пришли вразнобой, и отбрасывает дубликаты.
  • Подтверждения. Получатель сообщает, до какого байта всё получено (ACK). Неподтверждённые данные отправитель повторяет по таймауту или после трёх повторных подтверждений (fast retransmit).
  • Контрольная сумма выявляет повреждённые сегменты.

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

Управление потоком защищает получателя: в каждом подтверждении он сообщает размер окна — сколько ещё байтов готов принять. Медленный получатель автоматически притормаживает быстрого отправителя.

Управление перегрузкой защищает сеть. Отправитель держит окно перегрузки и увеличивает его, пока сеть справляется: сначала экспоненциально (медленный старт), затем линейно. Потеря пакета воспринимается как сигнал перегрузки, и окно резко уменьшается. Алгоритмы:

Алгоритм Сигнал Где используется
Reno, NewReno потери пакетов классика, учебники
CUBIC потери; рост окна по кубической функции времени по умолчанию в Linux, Windows, macOS[3]
BBR оценка пропускной способности и минимальной задержки Google, YouTube; полезен на каналах с потерями[4]
sysctl net.ipv4.tcp_congestion_control                # текущий алгоритм в Linux
sudo sysctl -w net.ipv4.tcp_congestion_control=bbr    # включить BBR

Порты и сокеты

Соединение однозначно определяется четвёркой: IP-адрес и порт клиента, IP-адрес и порт сервера. Сервер слушает известный порт (443 для HTTPS, 22 для SSH, 5432 для PostgreSQL), а клиент получает случайный временный порт.

ss -tlnp                   # слушающие TCP-сокеты и процессы
ss -tn state established   # установленные соединения
ss -s                      # сводка, включая TIME_WAIT
nc -vz example.com 443     # проверить, открыт ли порт

Утилита ss — современная замена netstat.[6]

Проблемы и оптимизации

  • Блокировка начала очереди (head-of-line blocking). Поток строго упорядочен: потеря одного пакета задерживает все последующие данные, даже относящиеся к другим запросам. В HTTP/2 это тормозит все параллельные потоки — главная причина появления QUIC.
  • Задержка установления. Рукопожатие TCP плюс TLS — два круга до первого байта данных. TCP Fast Open позволяет отправлять данные уже в SYN при повторных соединениях,[5] TLS 1.3 сокращает своё рукопожатие до одного круга.
  • Алгоритм Нейгла склеивает мелкие записи в один сегмент, экономя трафик, но добавляя задержку; интерактивные приложения отключают его опцией TCP_NODELAY.
  • Keepalive. Простаивающие соединения могут обрываться промежуточными устройствами (NAT, файрволы); периодические проверки поддерживают их и выявляют «мёртвые» соединения.

TCP и приложения

Для программиста TCP — это сокет, в который пишут и из которого читают поток байтов. Важно помнить, что это поток, а не сообщения: один вызов send не обязательно соответствует одному recv на другой стороне. Протокол приложения должен сам разделять сообщения — длиной в заголовке, разделителями или, как в HTTP, заголовком Content-Length.

См. также

Источники

  1. RFC 9293 — Transmission Control Protocol (TCP)
  2. V. Jacobson — Congestion Avoidance and Control (SIGCOMM 1988)
  3. RFC 9438 — CUBIC for Fast and Long-Distance Networks
  4. N. Cardwell et al. — BBR: Congestion-Based Congestion Control (ACM Queue, 2016)
  5. RFC 7413 — TCP Fast Open
  6. ss(8) — Linux manual page