Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Web Development

HTTP Кратко: HTTP-соединения

by
Difficulty:IntermediateLength:LongLanguages:
This post is part of a series called HTTP Succinctly.
HTTP Succinctly: HTTP Messages
HTTP Succinctly: HTTP Web Architecture

Russian (Pусский) translation by Liliya (you can also view the original English article)

В последней статье мы рассмотрели HTTP-сообщения и увидели примеры текстовых команд и кодов, которые поступают от клиента на сервер и обратно в транзакцию HTTP. Но как информация в этих сообщениях перемещается по сети? Когда открыты сетевые подключения? Когда закрываются соединения? Вот такие некоторые вопросы, на которые ответит эта статья, как мы смотрим на HTTP с точки зрения низкого уровня. Но сначала нам нужно понять некоторые абстракции ниже HTTP.


Экскурс по сети

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

Например, HTTP - это то, что мы называем протоколом уровня приложения, поскольку он позволяет двум приложениям обмениваться данными по сети. Довольно часто одним из приложений является веб-браузер, а другое приложение - веб-сервер, например IIS или Apache. Мы видели, как сообщения HTTP позволяют браузеру запрашивать ресурсы с сервера. Но спецификации HTTP не говорят ничего о том, как сообщения действительно пересекают сеть и доходят до сервера, - это работа протоколов более низкого уровня. Сообщение от веб-браузера должно перемещаться по нескольким слоям, и когда он приходит на веб-сервер, он перемещается вверх через ряд слоев, чтобы достичь процесса веб-службы.

Figure 4: Protocol layers
Слои протокола

Слой под HTTP — это протокол уровня транспорта. Почти весь HTTP-трафик проходит по TCP (короткий для протокола управления передачей), хотя HTTP не требуется. Когда пользователь вводит URL-адрес в браузер, браузер сначала извлекает имя хоста из URL-адреса (и номера порта, если есть), и открывает разъем TCP, указывая адрес сервера (полученный от имени хоста) и порта (который по умолчанию - 80).

Когда приложение имеет открытый разъем, он может начать запись данных в разъем. Единственное, о чем нужно беспокоиться в браузере, это написать правильно отформатированное сообщение HTTP-запроса в сокет. Уровень TCP принимает данные и гарантирует, что сообщение будет доставлено на сервер без потери или дублирования. TCP автоматически отправит любую информацию, которая может быть потеряна при транзите, и именно поэтому TCP известен как надежный протокол. Помимо обнаружения ошибок TCP также обеспечивает управление потоком. Алгоритмы управления потоком в TCP гарантируют, что отправитель не будет отправлять данные слишком быстро, чтобы получатель обрабатывал данные. Управление потоком важно в этом мире разнообразных сетей и устройств.

Короче говоря, TCP предоставляет службы, жизненно важные для успешной доставки HTTP-сообщений, но делает это прозрачным способом, поэтому большинству приложений не нужно беспокоиться о TCP. Как показано на предыдущем рисунке, TCP - это только первый уровень под HTTP. После того, как TCP на транспортном уровне идет IP как протокол сетевого уровня.

IP — короткий для Интернет-протокола. В то время как TCP отвечает за обнаружение ошибок, управление потоком и общую надежность, IP отвечает за сбор фрагментов информации и перемещение их через различные коммутаторы, маршрутизаторы, шлюзы, повторители и другие устройства, которые перемещают информацию из одной сети в другую во всем мире. IP пытается выполнить доставку данных в пункт назначения (но это не гарантирует доставку - это работа TCP). IP требует, чтобы компьютеры имели адрес (известный IP-адрес, пример - 208.192.32.40). IP также отвечает за разбиение данных на пакеты (часто называемые датаграммами), а иногда и на фрагментацию и сборку этих пакетов, поэтому они оптимизированы для определенного сегмента сети.

Все, о чем мы говорили до сих пор, происходит внутри компьютера, но в конечном итоге эти IP-пакеты должны перемещаться по проводу, оптоволоконному кабелю, беспроводной сети или спутниковой линии. Это ответственность за уровень канала передачи данных. В настоящее время общий выбор технологии - Ethernet. На этом уровне пакеты данных становятся кадрами, а протоколы низкого уровня, такие как Ethernet, фокусируются на 1 с, 0 и электрические сигналы.

В конце концов сигнал достигает сервера и поступает через сетевую карту, где процесс отменяется. Уровень канала передачи данных передает пакеты на уровень IP, который передает данные в TCP, который может собирать данные в исходное HTTP-сообщение, отправленное клиентом, и вставлять его в процесс веб-сервера. Это прекрасно спроектированная часть работы, сделанная по стандартам.


Быстрый запрос HTTP с розетки и C#

Если вам интересно, как выглядит приложение, которое будет обрабатывать HTTP-запросы, то следующий код C # - это простой пример того, как выглядит код. Этот код не имеет обработки ошибок и пытается записать любой ответ сервера в окно консоли (так что вам нужно запросить текстовый ресурс), но он работает для простых запросов. Копия следующего примера кода доступна из https://bitbucket.org/syncfusion/http-succinctly. Имя образца - это сокеты-образец.

Обратите внимание, как программа должна искать адрес сервера (используя Dns.GetHostEntry), и сформулировать правильное HTTP-сообщение с оператором GET и заголовком Host. Фактическая сетевая часть довольно проста, потому что реализация сокета и TCP заботятся о большей части работы. TCP понимает, например, как управлять несколькими подключениями к одному и тому же серверу (все они будут получать разные номера портов локально). Из-за этого два невыполненных запроса на один и тот же сервер не запутаются и не получат данные, предназначенные для другого.


Сеть и Wireshark

Если вам нужна видимость TCP и IP, вы можете установить бесплатную программу, такую ​​как Wireshark (доступная для OSX и Windows с сайта wirehark.org). Wireshark - это сетевой анализатор, который может отображать каждый бит информации, проходящей через ваши сетевые интерфейсы. Используя Wireshark вы можете наблюдать TCP-сообщения, которые являются TCP-сообщениями, необходимыми для установления соединения между клиентом и сервером до того, как начнутся фактические HTTP-сообщения. Вы также можете видеть заголовки TCP и IP (по 20 байтов каждый) для каждого сообщения. На следующем рисунке показаны последние два шага рукопожатия, затем запрос GET и перенаправление 304.

Figure 5: Using Wireshark
Использование Wireshark

С Wireshark вы можете видеть, когда HTTP-соединения установлены и закрыты. Важная часть, чтобы убрать все это, заключается не в том, как рукопожатия и TCP работают на самом низком уровне, но этот HTTP почти полностью связан с TCP, чтобы заботиться обо всей тяжелой работе, а TCP включает некоторые накладные расходы, например рукопожатия. Таким образом, характеристики производительности HTTP также зависят от характеристик производительности TCP, и это тема для следующего раздела.


HTTP, TCP и Эволюция Интернета

В самые старые времена Интернета большинство ресурсов были текстовыми. Вы можете запросить документ с веб-сервера, выйти и прочитать в течение пяти минут, а затем запросить другой документ. Мир был прост.

Для сегодняшней сети большинство веб-страниц требуют больше, чем одного ресурса для полного рендеринга. Каждая страница веб-приложения имеет одно или несколько изображений, один или несколько файлов JavaScript и один или несколько файлов CSS. Нередко исходный запрос для домашней страницы порождает 30 или 50 дополнительных запросов для извлечения всех других ресурсов, связанных со страницей.

В старые времена для браузера также было просто установить соединение с сервером, отправить запрос, получить ответ и закрыть соединение. Если сегодняшние веб-браузеры открывали соединения по одному, и ожидали, что каждый ресурс будет полностью загружен до начала следующей загрузки, сеть будет очень медленной. Интернет полон задержек. Сигналы должны перемещаться на большие расстояния и прокладывать себе путь через разные аппаратные устройства. Также есть некоторые накладные расходы при установлении TCP-соединения. Как мы видели в скриншоте Wireshark, для завершения HTTP-транзакции может быть выполнено трехэтапное рукопожатие.

Эволюция от простых документов до сложных страниц потребовала некоторой изобретательности в практическом использовании HTTP.


Параллельные соединения

Большинство пользовательских агентов (ака веб-браузеров) не будут обрабатывать запросы по очереди один за другим. Вместо этого они открывают несколько параллельных подключений к серверу. Например, при загрузке HTML для страницы браузер может видеть две тега <img> на странице, поэтому браузер откроет два параллельных соединений, чтобы загрузить два изображения одновременно. Количество параллельных соединений зависит от пользовательского агента и конфигурации агента.

Долгое время мы рассматривали два как максимальное количество параллельных соединений, которые создавал браузер. Мы считали два максимальных, потому что самый популярный браузер на протяжении многих лет - Internet Explorer (IE) 6 - допускал бы только два одновременных подключения к одному хосту. IE только подчинялся правилам, изложенным в спецификации HTTP 1.1, в которой говорится:

Однопользовательский клиент НЕ ДОЛЖЕН поддерживать более двух соединений с любым сервером или прокси.

Чтобы увеличить количество параллельных загрузок, многие веб-сайты используют некоторые трюки. Например, ограничение на два подключения для каждого хоста, то есть браузер, такой как IE 6, с радостью сделает два параллельных подключения к www.odetocode.com и два параллельных подключения к изображениям.odetocode.com. Путем размещения изображений на другом сервере веб-сайты могут увеличить количество параллельных загрузок и ускорить загрузку своих страниц (даже если записи DNS были настроены так, чтобы указать все четыре запроса на один и тот же сервер, поскольку ограничение на два подключения для каждого хоста имя, а не IP-адрес).

На сегодня это разные вещи Большинство пользовательских агентов будут использовать другой набор эвристик при выборе количества параллельных подключений. Например, Internet Explorer 8 теперь откроет до шести одновременных подключений.

Реальный вопрос: сколько соединений слишком много? Параллельные соединения будут подчиняться закону убывающих возвратов. Слишком много соединений может насыщать и поддерживать сеть, особенно когда задействованы мобильные устройства или ненадежные сети. Таким образом, слишком много соединений могут повредить производительность. Кроме того, сервер может принимать только конечное количество соединений, поэтому, если 100 000 браузеров одновременно создают 100 подключений к одному веб-серверу, то будет не очень хорошо. Тем не менее, использование более чем одного соединения для агента лучше, чем загрузка всего в серийном режиме.

К счастью, параллельные соединения - это не единственная оптимизация производительности.


Постоянные соединения

В первые дни Интернета пользовательский агент открывал и закрывал соединение для каждого отдельного запроса, отправленного на сервер. Эта реализация соответствовала идее HTTP о том, что она является полностью без государственным протоколом. По мере роста количества запросов на страницу также возникали накладные расходы, вызванные рукопожатиями TCP и структурами данных в памяти, необходимыми для установления каждого сокета TCP. Чтобы уменьшить эти накладные расходы и повысить производительность, спецификация HTTP 1.1 предполагает, что клиенты и серверы должны внедрять постоянные соединения и создавать постоянные соединения по умолчанию для типа соединения.

Постоянное соединение остается открытым после завершения одной транзакции с запросом-ответом. Такое поведение оставляет пользовательский агент с уже открытым сокетом, который он может использовать, чтобы продолжать делать запросы на сервер без накладных расходов на открытие нового сокета. Персистентные соединения также избегают стратегии медленного запуска, которая является частью управления перегрузкой TCP, что делает постоянные соединения более эффективными с течением времени. Короче говоря, постоянные соединения сокращают использование памяти, уменьшают использование ЦП, уменьшают перегрузку сети, уменьшают задержку и обычно улучшают время отклика страницы. Но, как и все в жизни есть и обратная сторона.

Как упоминалось ранее, сервер может поддерживать только конечное количество входящих соединений. Точный номер зависит от объема доступной памяти, конфигурации серверного программного обеспечения, производительности приложения и многих других переменных. Трудно дать точное число, но, вообще говоря, если вы говорите о поддержке тысяч одновременных подключений, вам нужно будет начать тестирование, чтобы проверить, поддерживает ли сервер нагрузку. Фактически, многие серверы настроены на ограничение количества параллельных подключений намного ниже точки, где сервер будет падать. Конфигурация - это мера безопасности, которая помогает предотвратить атаки на отказ в обслуживании. Для кого-то относительно легко создать программу, которая откроет тысячи постоянных подключений к серверу и не даст серверу отвечать реальным клиентам. Постоянными соединениями являются оптимизация производительности, а также уязвимость.

Думая об уязвимости, нам также нужно задаться вопросом, как долго поддерживать постоянное соединение открытым. В мире бесконечной масштабируемости соединения могут оставаться открытыми до тех пор, пока запускается программа пользовательского агента. Но поскольку сервер поддерживает конечное число подключений, большинство серверов настроено на закрытие постоянного соединения, если он неактивен в течение некоторого периода времени (например, в Apache, например, пять секунд). Пользовательские агенты также могут закрывать соединения после периода простоя. Единственная видимость подключений закрывается через сетевой анализатор, такой как Wireshark.

В дополнение к агрессивному закрытию постоянных соединений большинство веб-серверных программ можно настроить для отключения постоянных подключений. Это характерно для общих серверов. Совместные серверы жертвуют производительностью, позволяя максимально возможное количество подключений. Поскольку постоянные соединения - это стиль соединения по умолчанию с HTTP 1.1, сервер, который не разрешает постоянные подключения, должен включать заголовок Connection в каждом ответе HTTP. Примером может служить следующий код.

Заголовок Connection: close является сигналом для пользовательского агента, что соединение не будет постоянным и должно быть закрыто как можно скорее. Агенту не разрешается делать второй запрос по тому же соединению.


Конвейерные соединения

Параллельные соединения и постоянные соединения широко используются и поддерживаются клиентами и серверами. Спецификация HTTP также позволяет конвейерные соединения, которые не так широко поддерживаются ни серверами, ни клиентами. В конвейерном соединении пользовательский агент может отправить несколько HTTP-запросов в соединение, прежде чем ждать первого ответа. Конвейеризация позволяет более эффективно упаковывать запросы в пакеты и может уменьшить задержку, но она не так широко поддерживается как параллельные и постоянные соединения.


Где мы?

В этой главе мы рассмотрели HTTP-соединения и рассказали о некоторых оптимизациях производительности, которые стали доступны по спецификациям HTTP. Теперь, когда мы углубились в HTTP-сообщения и даже рассмотрели подключения и поддержку TCP под протоколом, мы сделаем шаг назад и рассмотрим Интернет с более широкой точки зрения.

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.