TCP: надёжное соединение
Разбираем TCP — протокол, который гарантирует надёжную и упорядоченную доставку данных.
TCP (Transmission Control Protocol) — транспортный протокол с установлением соединения, который гарантирует, что данные дойдут полностью, без потерь и в правильном порядке.
Что обещает TCP
IP-пакеты могут теряться, дублироваться, приходить не по порядку — сеть это не гарантирует. TCP надстраивается сверху и даёт приложению надёжный «поток байтов»: что отправили — то и получили, в том же порядке. Цена — накладные расходы и задержки. На TCP работают HTTP, почта, SSH — всё, где потеря данных недопустима.
Трёхстороннее рукопожатие (3-way handshake)
Прежде чем слать данные, стороны устанавливают соединение в три шага, обмениваясь начальными номерами последовательности (seq):
# Моделируем номера в 3-way handshake (без реальной сети)
client_seq = 1000
server_seq = 5000
print(f'1. Клиент -> Сервер: SYN, seq={client_seq}')
print(f'2. Сервер -> Клиент: SYN+ACK, seq={server_seq}, ack={client_seq + 1}')
print(f'3. Клиент -> Сервер: ACK, seq={client_seq + 1}, ack={server_seq + 1}')
print('Соединение установлено!')
Вывод:
1. Клиент -> Сервер: SYN, seq=1000 2. Сервер -> Клиент: SYN+ACK, seq=5000, ack=1001 3. Клиент -> Сервер: ACK, seq=1001, ack=5001 Соединение установлено!
Смысл шагов: SYN — «давай соединимся, мой номер 1000»; SYN+ACK — «согласен, мой номер 5000, жду твой 1001»; ACK — «подтверждаю». После этого можно слать данные. Поле ack всегда равно «следующему ожидаемому seq».
Нумерация и упорядочивание
Каждый байт в TCP пронумерован. Если сегменты придут не по порядку (а IP это допускает), приёмник соберёт их обратно по номерам:
# Сегменты пришли не по порядку — собираем по номеру
received = [(3, 'мир'), (1, 'При'), (2, 'вет, ')]
print('Пришли в порядке:', [n for n, _ in received])
ordered = sorted(received)
message = ''.join(text for _, text in ordered)
print('После сборки: ', repr(message))
Вывод:
Пришли в порядке: [3, 1, 2] После сборки: 'Привет, мир'
Подтверждения и повтор
Получив данные, приёмник шлёт ACK — «дошло до такого-то байта». Если отправитель не дождался ACK за отведённое время, он считает сегмент потерянным и отправляет его заново. Так TCP гарантирует доставку даже в ненадёжной сети.
Контроль потока (flow control)
Что если отправитель быстрее, чем приёмник успевает обрабатывать? Приёмник сообщает размер своего окна (window) — сколько байт он готов принять прямо сейчас. Отправитель не шлёт больше, чем влезает в окно. Это защищает медленного получателя от захлёбывания.
Контроль перегрузки (congestion control)
Отдельная задача — не перегрузить саму сеть между узлами. TCP начинает осторожно (slow start) и постепенно наращивает скорость, пока не заметит потери пакетов — тогда сбрасывает темп. Так множество TCP-соединений «делят» канал, не устраивая коллапс.
Завершение соединения
Закрывается соединение тоже упорядоченно — обменом сегментов FIN/ACK с каждой стороны (каждая сторона закрывает свою «половину» потока).
Итог
- TCP даёт надёжный упорядоченный поток байтов поверх ненадёжного IP.
- Соединение открывается 3-way handshake: SYN → SYN+ACK → ACK.
- Данные нумеруются, подтверждаются ACK и при потере отправляются заново.
- Контроль потока бережёт приёмник, контроль перегрузки — сеть.