该文章长期维护版
:Долина обезьян.com/2020/77E'Ezhu7…
Трехстороннее рукопожатие и четырехстороннее рукопожатие являются обычными тестовыми площадками в различных компаниях, а также имеют определенный уровень дифференциации, а также используются некоторыми интервьюерами в качестве разминочных вопросов. Многие друзья говорили, что ответ на этот вопрос был хорош в начале, но чем больше я отвечал на него позже, тем холоднее он становился и, наконец, прекратился.
Типичный сценарий интервью, который я видел, выглядит так:
Интервьюер: Пожалуйста, представьте следующее трехстороннее рукопожатие.
Соискатель: первое рукопожатие — это когда клиент отправляет сообщение на сервер, второе — когда сервер получает сообщение, а затем отвечает сообщением клиенту, а третье рукопожатие — когда клиент получает сообщение. другое сообщение на сервер, и трехстороннее рукопожатие прошло успешно.
Интервьюер: Тогда что?
Соискатель: Это трехсторонний процесс рукопожатия, очень простой.
Интервьюер: . . . . . .
(Дополнительно: классная песня для вас)
Помните фразу из «Долины обезьян»:Чем проще вопрос в интервью, то вообще таит в себе относительно большую яму, и вообще надо расширять вопрос. Является ли ответ соискателя выше неправильным? Конечно, да, но это может немного отличаться от ожиданий интервьюера.
Я надеюсь, что все смогут прочитать следующие вопросы, и урожай будет больше.
- Пожалуйста, нарисуйте схематическую диаграмму трех рукопожатий и четырех волн
- Почему при подключении происходит трехстороннее рукопожатие?
- Что такое очередь полусоединений?
- Фиксирован ли ISN (начальный порядковый номер)?
- Могут ли данные передаваться во время трехэтапного рукопожатия?
- Если третье рукопожатие потеряно, что будет делать клиент-сервер?
- Что такое SYN-атака?
- Зачем нужно махать четыре раза?
- Какой смысл ждать 2MSL, когда четыре раза машешь рукой, чтобы разорвать соединение?
1. Трехстороннее рукопожатие
Трехстороннее рукопожатие (Three-way Handshake) фактически означает, что при установлении TCP-соединения клиенту и серверу необходимо отправить в общей сложности 3 пакета. Основная функция трехэтапного рукопожатия состоит в том, чтобы подтвердить нормальные возможности обеих сторон по приему и отправке и указать свои собственные порядковые номера инициализации для подготовки к последующей надежной передаче. По сути, это подключение к указанному порту сервера, установление TCP-соединения, синхронизация серийных номеров и номеров подтверждения обеих сторон, обменTCP窗口大小
Информация.
В начале клиент находится в состоянии Closed, а сервер — в состоянии Listen. Трехстороннее рукопожатие:
-
Первое рукопожатие: клиент отправляет сообщение SYN на сервер и указывает порядковый номер инициализации клиента ISN(c). В этот момент клиент находится в
SYN_SEND
государство.Бит синхронизации в заголовке — SYN=1, начальный порядковый номер — seq=x, а сегмент с SYN=1 не может нести данные, но используется порядковый номер.
-
Второе рукопожатие: после того, как сервер получит сообщение SYN от клиента, он ответит своим собственным сообщением SYN, а также укажет свой собственный номер ISN последовательности инициализации. При этом в качестве значения ACK будет использоваться ISN + 1 клиента, что указывает на то, что он получил SYN клиента. В это время сервер находится в
SYN_RCVD
статус.В сегменте подтверждения SYN=1, ACK=1, номер подтверждения ack=x+1 и начальный порядковый номер seq=y.
-
Третье рукопожатие: после того, как клиент получит сообщение SYN, он отправит сообщение ACK. Конечно, он также использует ISN + 1 сервера в качестве значения ACK, указывая, что он получил сообщение SYN сервера. клиент в
ESTABLISHED
государство. После того, как сервер получает сообщение ACK, он также находится вESTABLISHED
Статус, на данный момент обе стороны установили соединение.Сегмент подтверждения ACK=1, номер подтверждения ack=y+1, порядковый номер seq=x+1 (изначально seq=x, поэтому второму сегменту требуется +1), сегмент ACK может переносить данные, а не перенос данных не использует порядковые номера .
Сторона, отправившая первый SYN, выполнит активное открытие, а другая сторона, получившая этот SYN и отправившая обратно следующий SYN, выполнит пассивное открытие.
В программировании сокетов, когда клиент выполняет connect(), будет запущено трехстороннее рукопожатие.
1.1 Почему нам нужно три рукопожатия вместо двух?
Чтобы понять эту проблему, нам нужно сначала понять, какова цель трехэтапного рукопожатия и можем ли мы достичь той же цели всего двумя рукопожатиями.
- Первое рукопожатие: клиент отправляет сетевой пакет, а сервер его получает. Таким образом, сервер может прийти к выводу, что возможности клиента по отправке и возможности сервера по приему являются нормальными.
- Второе рукопожатие: сервер отправляет пакет, а клиент его получает. Таким образом, клиент может прийти к выводу, что возможности приема и отправки сервера и возможности приема и отправки клиента являются нормальными. Однако в настоящее время сервер не может подтвердить, нормальная ли приемная способность клиента.
- Третье рукопожатие: клиент отправляет пакет, а сервер его получает. Таким образом, сервер может прийти к выводу, что возможности клиента по приему и отправке являются нормальными, а собственные возможности отправки и получения сервером также являются нормальными.
Следовательно, требуется три рукопожатия, чтобы подтвердить, что возможности приема и отправки обеих сторон в норме.
Представьте, что если вы используете два рукопожатия, произойдет следующая ситуация:
Если клиент отправляет запрос на подключение, но не получает подтверждения, поскольку пакет запроса на подключение потерян, клиент повторно передает запрос на подключение. Позже было получено подтверждение, и соединение было установлено. После завершения передачи данных соединение разрывается, а клиент отправляет всего два сегмента запроса на соединение, первый из которых теряется, а второй доходит до сервера, но первый потерянный сегмент находится только вНекоторые сетевые узлы зависают надолго, а сервер задерживается до определенного времени после разрыва соединения, В это время сервер ошибочно полагает, что клиент отправил новый запрос на соединение, поэтому отправляет клиенту сегмент подтверждения, соглашаясь установить соединение, и не использует трехэтапное рукопожатие. отправляет подтверждение, устанавливается новое соединение.В это время клиент игнорирует отправленное сервером подтверждение и не отправляет данные, затем сервер последовательно ждет, пока клиент отправит данные, тратя ресурсы.
1.2 Что такое очередь полусоединений?
После того, как сервер впервые получит SYN клиента, он будет находиться в состоянии SYN_RCVD. В это время две стороны не полностью установили свое соединение. Сервер поместит соединение запроса в это состояние в состояние SYN_RCVD.очередь, мы называем эту очередьочередь полуобъединения.
Конечно есть ещеполностью подключенная очередь, то есть трехстороннее рукопожатие завершено, и установленное соединение будет помещено в очередь полных соединений. Если очередь заполнена, может произойти потеря пакетов.
Вот еще немного оВремя повторной передачи SYN-ACKПроблема: После отправки сервером пакета SYN-ACK, если он не получил пакет подтверждения клиента, сервер повторно передает его в первый раз, ждет некоторое время и не получает пакет подтверждения клиента и выполняет вторую повторную передачу. Если количество повторных передач превышает максимальное количество повторных передач, заданное системой, система удаляет информацию о соединении из очереди полусоединений. Обратите внимание, что время ожидания для каждой повторной передачи не обязательно одинаково и обычно увеличивается экспоненциально, например, время интервала составляет 1 с, 2 с, 4 с, 8 с...
1.3 Фиксирован ли ISN (начальный порядковый номер)?
Когда конец отправляет свой SYN для установления соединения, он выбирает начальный порядковый номер для соединения. ISN со временем меняются, поэтому каждое соединение будет иметь свой ISN. ISN можно рассматривать как 32-битный счетчик, который увеличивается на 1 каждые 4 мс. Цель выбора порядкового номера таким образом состоит в том, чтобы предотвратить передачу задержанного в сети пакета в более позднее время, что приведет к его неправильной интерпретации одной стороной соединения.
Одной из важных функций трехэтапного рукопожатия является то, что клиент и сервер обмениваются ISN (начальным порядковым номером), чтобы другая сторона знала, как собирать данные в соответствии с порядковым номером при следующем получении данных. Если ISN фиксирован, злоумышленнику легко угадать последующие номера подтверждения, поэтому ISN генерируется динамически.
1.4 Можно ли передавать данные во время трехэтапного рукопожатия?
Фактически, во время третьего рукопожатия данные могут передаваться. но,Первое и второе рукопожатия не могут передавать данные
Почему это?Вы можете придумать вопрос.Если первое рукопожатие может нести данные, если кто-то хочет злонамеренно атаковать сервер, он каждый раз будет помещать много данных в сообщение SYN при первом рукопожатии. Поскольку злоумышленник просто игнорирует нормальные возможности сервера по приему и отправке, а затем лихорадочно повторяет пакеты SYN, это заставит сервер тратить много времени и памяти на получение этих пакетов.
Это,Одна простая причина, по которой данные не помещаются в первое рукопожатие, заключается в том, что это делает сервер более уязвимым для атак. В третий раз клиент уже находится в состоянии ESTABLISHED. Для клиента он установил соединение и уже знает, что возможности сервера по приему и отправке в норме, так что ничего страшного в переносе данных нет.
1.5 Что такое SYN-атака?
Выделение ресурсов на стороне сервера выделяется во время двустороннего рукопожатия, а ресурсы на стороне клиента выделяются после завершения трехэтапного рукопожатия., поэтому сервер уязвим для SYN-флуда. Атака SYN означает, что клиент подделывает большое количество несуществующих IP-адресов за короткий промежуток времени и непрерывно отправляет SYN-пакеты на сервер, сервер отвечает на пакет подтверждения и ждет подтверждения от клиента. исходный адрес не существует, сервер должен постоянно повторять передачу, пока не истечет тайм-аут. , эти поддельные SYN-пакеты будут занимать несвязанную очередь в течение длительного времени, в результате чего обычные SYN-запросы будут отбрасываться, поскольку очередь заполнена, вызывая перегрузку сети или даже системный паралич. SYN-атака — типичная DoS/DDoS-атака.
Очень удобно обнаруживать SYN-атаки, когда вы видите большое количество полусоединенных состояний на сервере, особенно IP-адрес источника является случайным, вы можете в принципе сделать вывод, что это SYN-атака. В Linux/Unix вы можете использовать встроенную команду netstats для обнаружения SYN-атак.
netstat -n -p TCP | grep SYN_RECV
Общие методы защиты от SYN-атак следующие:
- Сократите время ожидания SYN
- Увеличьте максимальное количество полусоединений
- Фильтр защиты шлюза
- Технология файлов cookie SYN
2. Помашите четыре раза
Для установления соединения требуется трехстороннее рукопожатие, а для прекращения соединения требуется четырехстороннее рукопожатие (существуют также четырехсторонние рукопожатия, называемые четырехсторонними рукопожатиями). Это делается по протоколу TCP.наполовину закрытый(полузакрыть) вызвано. Так называемое полузакрытие на самом деле означает, что TCP предоставляет возможность одному концу соединения получать данные с другого конца после завершения их передачи.
Удаление TCP-соединения требует отправки четырех пакетов, поэтому это называется четырехсторонним рукопожатием, Либо клиент, либо сервер могут активно инициировать ручную волну.
В начале обе стороны находятся в состоянии ESTABLISHED, если клиент первым инициирует запрос на закрытие. Процесс четырехкратного взмаха выглядит следующим образом:
- Первая волна: клиент отправляет сообщение FIN, и в сообщении указывается порядковый номер. В этот момент клиент находится в
FIN_WAIT1
государство. то есть выдатьсегмент освобождения соединения(FIN=1, порядковый номер seq=u) и снова прекратить отправку данных, активно закрыть TCP-соединение, войти в состояние FIN_WAIT1 (ожидание завершения 1) и дождаться подтверждения от сервера. - Вторая волна: после того, как сервер получит FIN, он отправит сообщение ACK и использует значение серийного номера клиента + 1 в качестве значения серийного номера сообщения ACK, указывая, что сообщение клиента было получено. серверная часть в
CLOSE_WAIT
государство. То есть сервер отправляет сегмент освобождения соединения после его получения.сегмент подтверждения(ACK=1, номер подтверждения ack=u+1, порядковый номер seq=v), сервер переходит в состояние CLOSE_WAIT (ожидание закрытия), TCP в это время находится в полузакрытом состоянии, и соединение между клиентом и сервер освобождается. После того, как клиент получает подтверждение от сервера, он переходит в состояние FIN_WAIT2 (ожидание завершения 2) и ожидает сегмента освобождения соединения, отправленного сервером. - Третья волна: Если сервер тоже хочет отключиться, как и первая волна клиента, отправьте сообщение FIN и укажите серийный номер. В это время сервер находится в
LAST_ACK
статус. То есть у сервера нет данных для отправки клиенту, и сервер отправляетсегмент освобождения соединения(FIN=1, ACK=1, серийный номер seq=w, номер подтверждения ack=u+1), сервер переходит в состояние LAST_ACK (последнее подтверждение) и ожидает подтверждения от клиента. - Четвертая волна: после того, как клиент получает FIN, он также отправляет сообщение ACK в качестве ответа и использует значение серийного номера сервера + 1 в качестве значения серийного номера своего собственного сообщения ACK.
TIME_WAIT
государство. Требуется некоторое время, чтобы гарантировать, что сервер войдет в состояние CLOSED после получения собственного сообщения ACK.После того, как сервер получит сообщение ACK, он закроет соединение и будет находиться в состоянии CLOSED.CLOSED
государство. То есть после того, как клиент получит от сервера сегмент освобождения соединения, он отправляетсегмент подтверждения(ACK=1, seq=u+1, ack=w+1), клиент переходит в состояние TIME_WAIT (время ожидания). В это время TCP не освобождается, и клиент переходит в состояние CLOSED только после того, как время, установленное таймером ожидания, равно 2MSL.
Получение FIN означает просто отсутствие потока данных в этом направлении.Обычно клиент выполняет активное завершение работы и переходит в состояние TIME_WAIT.Сервер обычно выполняет пассивное завершение работы и не входит в состояние TIME_WAIT.
В программировании сокетов любая сторона выполняет операцию close() для создания волны.
2.1 Зачем нужно махать четыре раза?
Потому что, когда сервер получает сообщение с запросом на соединение SYN от клиента, он может напрямую отправить сообщение SYN+ACK. вСообщение ACK используется для ответа, а сообщение SYN используется для синхронизации.. Но при закрытии соединения, когда сервер получает сообщение FIN, он, скорее всего, не закроет SOCKET немедленно, поэтому он может сначала ответить сообщением ACK, сообщив клиенту: «Я получил отправленное вами сообщение FIN». Я могу отправлять сообщения FIN только до тех пор, пока не будут отправлены все сообщения на моем сервере, поэтому их нельзя отправлять вместе. Итак, требуется четыре волны.
2.2 Состояние ожидания 2MSL
Состояние TIME_WAIT также становится состоянием ожидания 2MSL. Каждая конкретная реализация TCP должна выбрать максимальное время жизни сегмента MSL (Maximum Segment Lifetime), которое представляет собой максимальное время в сети до того, как какой-либо сегмент будет отброшен. Это время ограничено, поскольку сегменты TCP передаются по сети в виде IP-датаграмм, которые имеют поле TTL, ограничивающее их время жизни.
Для значения MSL, заданного конкретной реализацией, принцип обработки следующий: когда TCP выполняет активное завершение работы и отправляет последний ACK, соединение должно оставаться в состоянии TIME_WAIT в течение 2-кратного MSL. Это позволяет TCP отправить последний ACK еще раз в случае, если этот ACK будет потерян (другая сторона истечет время ожидания и повторно отправит последний FIN).
Другим последствием этого ожидания 2MSL является то, что сокет, определяющий соединение (IP-адрес и номер порта клиента, IP-адрес и номер порта сервера), больше не может использоваться во время ожидания 2MSL для TCP-соединения. Это соединение можно использовать только после окончания 2MSL.
2.3 Какой смысл ждать 2MSL при разрыве соединения четырехкратным взмахом руки?
MSLЭто английская аббревиатура от Maximum Segment Lifetime, что можно перевести как «наибольшее время жизни сегмента». Это максимальное время существования любого пакета в сети. По истечении этого времени пакет будет отброшен.
Чтобы гарантировать, что последний сегмент ACK, отправленный клиентом, может достичь сервера. Поскольку ACK может быть потерян, сервер в состоянии LAST-ACK не может получить подтверждающее сообщение для FIN-ACK. Сервер повторно передаст FIN-ACK с тайм-аутом, а затем клиент снова передаст подтверждение, перезапустив таймер ожидания. Наконец, и клиент, и сервер могут нормально завершить работу. Предполагая, что клиент не ждет 2MSL, а сразу отпускает закрытие после отправки ACK, после потери ACK сервер не может нормально войти в состояние закрытого соединения.
Две причины:
- Убедитесь, что последний сегмент ACK, отправленный клиентом, может достичь сервера. Этот сегмент ACK может быть потерян, так что B в состоянии LAST-ACK не может получить подтверждение отправленного сегмента FIN+ACK, сервер повторно передает сегмент FIN+ACK с течением времени, а клиент может повторно передать сегмент FIN+ACK. в течение 2MSL, затем клиент повторно передает подтверждение, перезапускает таймер 2MSL, и, наконец, и клиент, и сервер переходят в состояние CLOSED.Если клиент находится в состоянии TIME-WAIT Если вы не ждете какое-то время, а отпускаете соединение сразу после отправки сегмента ACK, вы не сможете получить повторно переданный сервером сегмент FIN+ACK, поэтому сегмент подтверждения не будет отправлен повторно, и сервер не сможет нормально работать. государство.
- Предотвращает появление «несуществующего сегмента запроса на соединение» в этом соединении. После отправки клиентом последнего сегмента ACK, после 2MSL, все сегменты, сгенерированные текущим соединением, могут исчезнуть из сети, так что следующее новое соединение не появится.Старый сегмент запроса на соединение.
2.4 Почему состояние TIME_WAIT должно пройти через 2MSL, чтобы вернуться в состояние CLOSE?
Теоретически, после отправки всех четырех пакетов можно сразу войти в состояние CLOSE, но сеть может оказаться ненадежной, и последний ACK может быть потерян. такСостояние TIME_WAIT используется для повторной отправки сообщений ACK, которые могут быть потеряны..
3. Резюме
«Подробное объяснение TCP/IP, том 1: протокол» содержит диаграмму перехода состояния TCP, которая очень показательна и помогает каждому понять изменения состояния при трехэтапном рукопожатии и четырехэтапной волне. Как показано на рисунке ниже, толстые сплошные стрелки представляют обычные переходы состояний клиента, а толстые пунктирные стрелки — обычные переходы состояний сервера.
В дальнейшем интервьюер попросит вас три раза пожать руку и четыре раза помахать рукой, и просто кинуть ему эту статью.Все, что он хочет спросить, здесь.
Ссылка: "Подробное объяснение TCP/IP, том 1: протокол"