1. Обзор
Предыдущая статья《Вы действительно понимаете процесс Ping?》Мы проанализировали процесс Ping с помощью инструмента захвата пакетов. Мы знаем, что ping опирается на протокол ICMP, а затем запросы ARP также участвуют в локальной сети. Сегодня в этой статье мы также используем инструмент анализа захвата пакетов для анализа наших Как выглядит HTTP-запрос?
2. Подготовка окружающей среды
Изначально я хотел найти веб-сайт для анализа перехвата пакетов, но веб-сайт в официальной среде имеет слишком много HTTP-запросов, слишком много помех и не очень удобен для анализа, поэтому я сделал простую демонстрацию и вернул строку в HTTP-запрос.
окрестности:
1.响应http请求的服务demo
2.客户端ip:192.168.2.135
3.服务端:45.76.105.92
4.抓包工具:Wireshark
Я развернул демо на сервере и успешно начал доступ следующим образом:
Откройте средство захвата пакетов Wireshark для захвата пакетов. Результаты захвата пакетов следующие:
Рисунок Http-запрос На приведенном выше рисунке мы видим, что пакет был успешно перехвачен в HTTP-запрос и ответ, но мы видели, что существует много TCP-запросов.Далее давайте проанализируем, что делают эти TCP-запросы?3. Анализ захвата пакетов
А) трехстороннее рукопожатие
1. В начале было отправлено два запроса на сервер локально.Почему здесь два запроса?Поговорим об этом позже.Давайте сначала посмотрим на запросы портов, соответствующие HTTP, следующим образом:
192.168.2.135:60738---->45.76.105.92:8081
Глядя на скриншот выше, мы знаем, что это первое рукопожатие протокола TCP.Студенты, знакомые с протоколом TCP, должны знать, что существует три рукопожатия для установления соединения и четыре волны для отключения. (Студенты, которые мало знают о протоколе TCP, могут прочитать эту статью "Следуйте анимации, чтобы изучить трехстороннее рукопожатие TCP и четырехстороннюю волну.")
Сначала рассмотрим первый запрос:
60738 -> 8081 [SYN] Seq=0 Win=64240 Len=0 Mss=1460 Ws=256 SACK_PERM=1
Давайте проанализируем эту информацию запроса пакета:
- 60783 -> номер порта 8081: исходный порт ---> порт назначения
- [SYN]: Синхронный сигнал квитирования
- Посл: номер сообщения
- Win: размер окна TCP
- Лен: длина сообщения
- Mss: Максимальная длина сегмента
- Ws: коэффициент масштабирования окна
- SACK_PERM : опция SACK, здесь равна 1, чтобы включить SACK.
Ниже приведено краткое объяснение приведенной выше концепции.Прежде чем представить ее, давайте посмотрим на диаграмму структуры данных заголовка TCP, чтобы получить интуитивное представление о структуре данных заголовка TCP.
1. Win: Размер окна TCP, относится к максимальному количеству байтов, которое может принять передача TCP, которое может быть динамически настроено, то есть скользящее окно TCP, которое управляет скоростью отправки данных путем динамической настройки размера окна. Приведенное выше число занимает 2 байта, то есть 16 бит, тогда максимальное число, которое может поддерживаться, равно 2^16=65536, поэтому по умолчанию максимальное количество окон, которое может поддерживать тег заголовка TCP, составляет 65536 байт, что равно 64 КБ.
2. Len: длина сообщенияЭто относится к сегменту пакета данных.Поскольку весь TCP-пакет = Header+packSize, длина сообщения относится к общей длине передаваемого пакета данных, которая является размером HTTP-пакета в этом анализе.
3. Mss: Максимальная длина сегмента: это указывает максимальную длину сообщения, которое может быть передано.Для достижения наилучшей производительности передачи протокол TCP обычно согласовывает значение MSS обеих сторон при установлении соединения.Это значение часто заменяется значением MTU когда реализован протокол TCP (необходимо вычесть размер заголовка пакета данных IP 20 байт и заголовок сегмента данных TCP 20 байт), поэтому общее значение MSS равно 1460, что также согласуется со значением на нашей диаграмме захвата пакетов.
4. Ws: коэффициент регулировки масштаба окна.: В предыдущем разделе о размере окна TCP мы упомянули, что по умолчанию максимальный размер окна TCP может поддерживать только 64 КБ буферизованных данных.В сегодняшнюю эпоху высокоскоростного Интернета этот размер не должен соответствовать условиям. Поэтому для поддержки большего количества буферизованных данныхRFC 1323Параметры расширения TCP указаны в , одним из которых является коэффициент масштабирования окна Как это работает? Во-первых, этот параметр согласовывается на этапе синхронизации [SYN], и мы анализируем его на основе данных захвата пакетов, приведенных выше. Мы видим, что результатом согласования первого запроса является WS=256, а затем в фазе ACK вступает в силу коэффициент расширения, и размер окна корректируется. Эффективный захват пакетов выглядит следующим образом:
60738 ->8081 [ACK] Seq=1 ACK=1 Win=66560 Len=0
Мы обнаружили, что это окно стало больше, чем окно по умолчанию 66560. Мы проверяем детали сообщения:
Мы обнаружили, что фактическое запрошенное окно равно 260, коэффициент расширения WS равен 256, а окончательный расчетный размер окна равен 66560, поэтому мы знаем, что функция этого коэффициента расширения состоит в том, чтобы умножить исходный размер окна на коэффициент расширения, чтобы получить финальное окно размером 260*256=66560.
5. SACK_PERM: опция SACK, мы знаем, что передача TCP имеет механизм подтверждения пакетов.По умолчанию после получения пакета получатель отправляет подтверждение ACK.Однако по умолчанию поддерживается только последовательное подтверждение, то есть отправляются пакеты A, B и C .Если я получил пакеты от A и C, но B не получил их, поэтому для C я не буду подтверждать этот пакет.Мне нужно дождаться получения пакета B, прежде чем подтвердить его.Тогда TCP имеет механизм повторной передачи по тайм-ауту , Если пакет занимает много времени Если нет подтверждения, он будет повторно передан в случае его потери, что приведет к повторной передаче большого количества избыточных пакетов и пустой трате места при передаче. Чтобы решить эту проблему, SACK предлагает механизм выборочного подтверждения: после включения SACK получатель будет подтверждать все полученные пакеты, так что отправителю нужно будет повторно передать только действительно потерянные пакеты.
После краткого ознакомления с приведенными выше базовыми понятиями, давайте разберем процесс HTTP-запросов на основе перехвата пакетов.Согласно HTTP-запросу, локальный порт — 60378. Процесс, который я разбираю, выглядит следующим образом:
------------------------请求连接--------------------------
1) 60738 -> 8081 [SYN] Seq=0 Win=64240 Len=0 Mss=1460 Ws=256 SACK_PERM=1
2) 8081 -> 60738 [SYN,ACK] Seq=0 ACK =1 Win=29200 Len=0 MSS=1420 SACK_PERM=1 WS=128
3) 60738 -> 8081 [ACK] Seq=1 ACK=1 Win=66560 Len=0
4) Get /test HTTP/1.1
5) 8081 -> 60738 [ACK] Seq=1 ACK=396 Win=30336 Len=0
6) HTTP/1.1 200 (text/html)
7) 60738 -> 8081 [ACK] Seq=396 ACK=120 Win=66560 Len=0
------------------断开连接-----------------------------
8) 60738 -> 8081 [FIN ACK] Seq=396 Ack=120 Win=66560 Len=0
9) 8081 -> 60738 [FIN ACK] Seq=120 Ack=397 Win=30336 Len=0
10) 60738 -> 8081 [ACK] Seq=397 Ack=121 Win=66560 Len=0
Согласно описанному выше процессу, мы можем знать, что№1 - №3является очевидным трехсторонним рукопожатием, тогда№ 4сделал HTTP-запрос, затем№ 5является подтверждением получения HTTP-запроса,№ 6это ответ на HTTP-запрос,№ 7является подтверждением ответа на запрос.
Б) махнуть четыре раза
Приведенные выше серийные номера 8, 9 и 10 — это пакеты, которые я захватил после закрытия браузера.Поскольку браузер закрыт, мы должны знать, что TCP-соединение отключено. Некоторые одноклассники тут должны были обнаружить проблему.У нас разъединение 4 раза машет.В пакете который вы схватили всего три записи.Вы не правильно написали? Что я хочу вам сказать, так это то, что я не ошибся написал, это самый настоящий захват пакетов, а почему именно три раза, давайте разберем:
В нормальных условиях соединение разрывается 4-кратным маханием.Процесс 4-кратного махания выглядит следующим образом:
Анализируем эту картинку, и процесс завивки выглядит следующим образом:
1.客户端发起一个断开请求,进入 FIN-WAIT 状态
2.服务端确认断开请求
3.服务端立即发送一个断开请求,进入 CLOSE-WAIT 状态
4.客户端确认服务端断开请求,进入 TIME-WAIT 状态
Мы обнаружили, что вышеупомянутый процесс 2 и процесс 3 инициируются сервером, поэтому возможно ли объединить эти два запроса и отправить их клиенту одновременно?ответМожет. существуетRFC 2581Как упоминалось в разделе 4.2, ack может задержать подтверждение, если гарантировано, что пакет подтверждения прибудет в течение 500 мс. В соответствии с таким стандартом подтверждения TCP могут быть объединены с отложенными подтверждениями, поэтому на основе этого мы делаем вывод о следующем пакете:
9) 8081 -> 60738 [FIN ACK] Seq=120 Ack=397 Win=30336 Len=0
Подтверждение подтверждения клиенту и пакет сигнала отключения FIN, отправленный сервером, объединяются. Мы нажимаем на детали пакета следующим образом: Красное поле здесь показывает, что этот пакет № 9 является подтверждением ACK кадра 500. Из начального снимка экрана мы можем знать, что этот пакет является пакетом № 8.
8) 60738 -> 8081 [FIN ACK] Seq=396 Ack=120 Win=66560 Len=0
И сам пакет № 9 является отправленным сигнальным пакетом FIN, поэтому мы можем думать, что пакет № 9 объединяет содержимое ACK и FIN, поэтому обычные 4 раза махания становятся 3 раза после слияния.
Выше приведен полный HTTP-запрос, весь процесс представлен следующим образом:
C) Keep-Alive
Здесь должны быть некоторые студенты, которые спросят, поскольку это полный HTTP-запрос, есть ли трехстороннее рукопожатие для каждого запроса?
Ответ: действующее соглашение не
В версиях HTTP 0.9 и HTTP 1.0 для каждого запроса и ответа требуется трехэтапное рукопожатие, а вот HTTP 1.0 начинает пробовать непрерывное соединение, то есть параметр Keep-Alive, но официально он пока не поддерживается. Протокол HTTP 1.1, официальный. По умолчанию поддерживается параметр Keep-Alive, а по умолчанию используется постоянное соединение. Есть две основные функции Keep-Alive:
1.检查死节点
2.防止连接由于不活跃而断开
Проверить мертвые узлы
Основная цель - сделать так, чтобы соединение не удалось быстро найти, и можно было бы выполнить переподключение.Например, соединение между А и В было установлено, а узел В зависает по нештатной причине, а узел А не не знаю.В настоящее время есть две ситуации:
1. Если предположить, что узел B не восстановился, тогда узел B не ответит ACK, а узел A будет повторять попытки до определенного количества раз, чтобы узнать, что узел B является мертвым узлом.
2. Узел Б успешно перезагружается до отправки данных А. В это время узел А отправляет данные, но узел Б их не примет, а отправит сигнал RST (при получении данных на закрытом сокете он будет отправлять пакеты данных RST, одноранговому узлу требуется закрыть ненормальное соединение, и ему не нужно отвечать ACK), и тогда A знает, что узлу B необходимо повторно соединиться.
В приведенных выше двух случаях будет известно только то, что у другой стороны есть исключение при отправке данных. Keep-Alive время от времени отправляет тактовые импульсы, поэтому вы можете быстро узнать статус узла сервера.
Предотвращение разрыва соединений из-за бездействия
Мы знаем, что установление и обслуживание сетевых подключений потребляют ресурсы, а количество подключений, которые могут быть установлены на сервере, ограничено, поэтому брандмауэры или операционные системы будут освобождать неактивные подключения для экономии ресурсов и поддерживать активность при каждой отправке пакета пульса. в течение определенного периода времени - это сообщить брандмауэру или операционной системе, что мое соединение активно, и не убивать меня.
Я повторно загрузил пакет с помощью Keep-Alive, и скриншот выглядит следующим образом:
Рисунок Keep-Alive На приведенном выше рисунке последние два пакета — это отправленные пакеты проверки активности, а затем сервер подтверждает ACK.Когда мы видим пакет проверки активности, он фактически отправляет однобайтовый пакет, который является поддержкой активности. выполнить.После разговора о Keep-Alive давайте вернемся к первоначальному вопросу, почему в HTTP-запросе происходит рукопожатие между двумя портами? На самом деле к самому протоколу это не имеет никакого отношения, первый скриншот перехвата пакета (рисунок Http-Request) был получен мной с помощью Google Chrome, а последний снимок перехвата пакета (рисунок Keep-Alive) был получен мной с помощью браузера Firefox Да, после тщательного сравнения мы обнаружили, что браузер Firefox имеет только один порт для трехэтапного рукопожатия. Таким образом, возникновение этой ситуации является реализацией самого браузера.Почему Google Chrome реализует именно так?Я предполагаю: чтобы максимально обеспечить доступность HTTP-доступа, когда порт недоступен, вы можете немедленно переключиться на другой порт, чтобы завершить HTTP-запрос и ответ.. (Личное предположение, если есть авторитетный ответ, просьба сообщить на биржу)
4. Резюме
- HTTP-запрос основан на TCP-соединении, и трехстороннее рукопожатие TCP будет выполнено при первом подключении.
- HTTP использует Keep-Alive для постоянного подключения и регулярно отправляет пакет пульса, чтобы сообщить серверу, что он все еще активен.
- Отключение HTTP-соединения также приведет к четырем волнам TCP, но если сервер решит, что условия выполнены, сигналы ACK и FIN будут объединены, которые затем будут преобразованы в три волны.
5. Ссылка
[1] RFC 1323
[2] RFC 2581