Глубокое погружение в протокол Linux TCP

ПримечаниеПримечание. Полная ментальная карта доступна по адресу: «DevOps in Linux Mind Map.

Формат заголовка TCP

Давайте сначала посмотрим на формат заголовка TCP. Как видно из этой диаграммы, он намного сложнее, чем UDP.

  • Порт источника/назначения: номера портов для источника и получателя. Без этих двух номеров портов мы не знаем, в какое приложение отправлять данные.
  • Порядковый номер: это для решения проблемы не по порядку. Если у вас нет хорошего порядкового номера, как вы можете подтвердить, какой из них должен быть первым, а какой позже?
  • Номер подтверждения: чтобы подтвердить отправленный пакет и убедиться, что другая сторона его получила.
  • Биты состояния. Например, SYN — инициировать соединение, ACK — ответить, RST — переподключиться, FIN — разорвать соединение и т. д. TCP ориентирован на установление соединения, поэтому обе стороны должны поддерживать состояние соединения.
  • Размер окна: используется для управления потоком TCP. Обе стороны в общении объявляют окно для определения своих текущих возможностей обработки.
  • Контроль перегрузки: для управления скоростью отправки.

Благодаря анализу заголовка TCP мы знаем, что для освоения протокола TCP мы должны сосредоточиться на следующих вопросах:

  • Проблема последовательности стабильна и не хаотична;
  • Проблема с потерей пакетов, обещают быть надежными;
  • Сопровождение соединения от начала и до конца;
  • Управление потоком, поймите пропорцию;
  • Контроль заторов, знайте, как продвигаться вперед и знайте, как отступать.

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

Теперь давайте посмотрим на установление TCP-соединения. Установление TCP-соединения часто называют трехсторонним рукопожатием.

Процесс рукопожатия можно описать так:

  • Клиент вызывает сокет, затем отправляет SYN и Seq на сервер, и его статус изменяется на состояние SYN_SEND.
  • Сервер переходит из состояния LISTEN в состояние SYN_RECV, затем сервер отправляет обратно SYN+ACK
  • Клиент получает его, и его состояние меняется на Established, затем клиент отправляет ACK обратно на сервер, сервер получает ACK, и статус становится Established.

На этом процесс трехэтапного рукопожатия TCP завершен. Если представить весь процесс, то он будет выглядеть так:

(1) Первое рукопожатие: определяет сервер (сервер может получать данные, а клиент может отправлять данные)

(2) Второе рукопожатие: определяет клиент (сервер может получать данные, а сервер может получать данные)

(3) Третье рукопожатие: сервер определяет (клиент может получать данные)

Четыре волны TCP

Поскольку TCP-соединение Duplex,, поэтому каждое направление должно быть закрыто отдельно. Когда сторона завершает свою задачу по передаче данных, она может отправить бит флага завершения FIN, чтобы разорвать соединение в этом направлении, Received a fin означает There is no data flow in this direction. TCP-соединение все еще может отправлять данные после получения FIN. Первая сторона, которая закроется, выполнит Active closure, а другая сторона выполнит Passive closure.

  • Первая волна: клиентский процесс отправляет сообщение о разрыве соединения и прекращает отправку данных. Освободите заголовок сообщения данных, fin = 1, и его порядковый номер будет SEQ = u (равным порядковому номеру последнего байта ранее переданных данных плюс 1). В это время клиент входит в состояние fin-wait-1. TCP предусматривает, что даже если сегмент FIN не несет данных, он использует серийный номер.
  • Вторая волна: сервер получает сообщение о разрыве соединения, отправляет подтверждающее сообщение ACK = 1, ACK = u + 1 и имеет собственный серийный номер SEQ = v. В это время сервер входит в состояние close-wait. Сервер TCP также уведомляет высокоуровневый прикладной процесс о том, что направление клиента к серверу освобождается. В это время он находится в полузакрытом состоянии, то есть у клиента нет данных для отправки, но если сервер отправляет данные, клиент все равно должен их принять. Это состояние будет длиться в течение определенного периода времени, то есть продолжительности всего состояния ожидания. После получения запроса на подтверждение от сервера клиент перейдет в статус fin-wait-2 и будет ждать, пока сервер отправит сообщение об освобождении соединения (перед этим ему необходимо принять окончательные данные, отправленные сервером).
  • Третья волна: после отправки окончательных данных сервер отправит сообщение о разрыве соединения клиенту fin = 1, ACK = u + 1. Поскольку он находится в полузакрытом состоянии, сервер, скорее всего, отправит еще немного данных. Предполагая, что порядковый номер равен SEQ = w, сервер перейдет в состояние last-ack и будет ждать подтверждения от клиента.
  • Четвертая волна: после получения от сервера сообщения о разрыве соединения клиент должен отправить подтверждение ACK = 1, ACK = w + 1, а его серийный номер — SEQ = u + 1. В это время клиент входит в состояние time-wait. Обратите внимание, что в настоящее время TCP-соединение не разорвано. Он должен пройти 2 * MSL (максимальное время жизни сегмента сообщения), прежде чем он перейдет в закрытое состояние, когда клиент отменит соответствующий TCB. Как только сервер получит подтверждение от клиента, он сразу же перейдет в закрытое состояние. Точно так же после отмены TCB соединение TCP завершается. Как видите, сервер завершает TCP-соединение раньше, чем клиент.

Почему три рукопожатия и четыре рукопожатия при закрытии

Потому что, когда сервер получает сообщение с запросом на соединение syn от клиента, он может напрямую отправить сообщение syn + ACK. Сообщение ACK используется для ответа, а сообщение syn используется для синхронизации.

Но при закрытии соединения, когда сервер получает сообщение fin, вполне вероятно, что он не закроет сокет немедленно, поэтому он может только ответить на сообщение ACK и сообщить клиенту: «Я получил сообщение fin, которое вы отправили». Только когда все сообщения на моем сервере отправлены, я могу отправлять сообщения fin, поэтому их нельзя отправлять вместе. Итак, для рукопожатия требуется четыре шага.

Конечный автомат TCP

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

  • LISTEN Ожидание запроса от удаленного приложения TCP
  • SYN_SENT Дождитесь подтверждения от удаленной конечной точки после отправки запроса на подключение. Состояние клиента после первого рукопожатия TCP
  • SYN-RECEIVED Конечная точка получила запрос на подключение и отправила подтверждение. Конечная точка ожидает окончательного подтверждения. Состояние сервера после второго рукопожатия TCP
  • УСТАНОВЛЕНО Указывает, что соединение установлено. Это нормальное состояние фазы передачи данных соединения.
  • FIN_WAIT_1 Ожидание подтверждения запроса на завершение соединения или запроса на завершение от удаленного TCP
  • FIN_WAIT_2 После того, как эта конечная точка отправит запрос на завершение соединения, дождитесь запроса на завершение соединения от удаленного TCP.
  • CLOSE_WAIT Конечная точка получила запрос на закрытие от удаленной конечной точки, и этот TCP ожидает запроса на завершение соединения от локального приложения.
  • ЗАКРЫТИЕ Ожидание подтверждения запроса на завершение соединения от удаленного TCP
  • LAST_ACK Ожидание подтверждения запроса на завершение соединения, ранее отправленного на удаленный TCP
  • TIME_WAIT Подождите достаточное время, чтобы удаленный TCP получил подтверждение своего запроса на завершение соединения.

Заключение