Мое понимание HTTP-опросов, длинных опросов, HTTP-потоковой передачи и веб-сокетов

123

Я прочитал много сообщений в SO и в Интернете относительно ключевых слов в заголовке моего вопроса и многому у них научился. Некоторые вопросы, которые я прочитал, связаны с конкретными проблемами реализации, а другие сосредоточены на общих концепциях. Я просто хочу убедиться, что я понял все концепции и причины, по которым технология X была изобретена, а не технология Y и так далее. Итак, вот оно:

Http-опрос: в основном AJAX с использованием XmlHttpRequest.

Http Long Polling: AJAX, но сервер сохраняет ответ, если на сервере нет обновления, как только на сервере есть обновление, он отправляет его, а затем клиент может отправить другой запрос. Недостатком являются дополнительные данные заголовка, которые необходимо пересылать туда и обратно, что вызывает дополнительные накладные расходы.

Http Streaming: аналогично длинному опросу, но сервер отвечает заголовком «Transfer Encoding: chunked» и, следовательно, нам не нужно инициировать новый запрос каждый раз, когда сервер отправляет некоторые данные (и, следовательно, сохраняет дополнительные накладные расходы заголовка). Недостатком здесь является то, что мы должны «понимать» и выяснять структуру данных, чтобы различать несколько блоков, отправленных сервером.

Java-апплет, Flash, Silverlight: они обеспечивают возможность подключения к серверам сокетов через TCP / IP, но, поскольку они являются плагинами, разработчики не хотят зависеть от них.

WebSockets: это новый API, который пытается устранить недостатки вышеуказанных методов следующим образом:

  • Единственное преимущество WebSockets перед плагинами, такими как Java Applets, Flash или Silverlight, заключается в том, что WebSockets изначально встроены в браузеры и не зависят от плагинов.
  • Единственное преимущество WebSockets перед потоковой передачей по протоколу http заключается в том, что вам не нужно прилагать усилия для «понимания» и анализа полученных данных.
  • Единственное преимущество WebSockets перед Long Polling заключается в устранении лишнего размера заголовков, а также в открытии и закрытии сокетного соединения для запроса.

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

Спасибо!

Программный парень
источник
4
На события, отправленные сервером, также стоит обратить внимание, если вам не нужна двусторонняя связь.
leggetter
1
Это действительно полезный вопрос. Я думаю, что потенциально было бы более полезно, если бы был один ответ, в который могли бы внести свой вклад несколько авторов.
leggetter
@leggetter Спасибо, Фил, спасибо за подсказку относительно событий, отправленных сервером. Мне интересно узнать о сценариях двустороннего общения. Спасибо.
Software Guy
1
С HTTP Streaming и Long-Polling вам понадобится второе соединение для двунаправленной связи. Одно долгоживущее соединение для сервера -> «проталкивающая» связь клиента и второе недолговечное соединение для клиента -> связь с сервером. Это второе соединение используется для таких вещей, как установка и изменение подписок на данные. Таким образом, EventSource можно использовать в двунаправленном решении и, по сути, является стандартизированным решением, рожденным на основе HTTP Streaming и Long-Polling.
leggetter
1
Вы также можете ознакомиться с этой классификацией техник, которые я написал: stackoverflow.com/questions/12078550/…
Алессандро Алиноне

Ответы:

92

Различий больше, чем вы определили.

Дуплекс / направлениях:

  • Однонаправленный: HTTP-опрос, длинный опрос, потоковая передача.
  • Двунаправленный: WebSockets, сеть плагинов

В порядке увеличения задержки (приблизительно):

  • WebSockets
  • Сетевой плагин
  • HTTP потоковая передача
  • HTTP длинный опрос
  • HTTP-опрос

CORS (поддержка разных источников):

  • WebSockets: да
  • Сеть плагинов: прошивка через запрос политики (не уверен в других)
  • HTTP * (недавняя поддержка)

Собственные двоичные данные (типизированные массивы, капли):

  • WebSockets: да
  • Сеть плагинов: не с Flash (требуется кодирование URL через ExternalInterface)
  • HTTP *: недавнее предложение о включении поддержки двоичного типа

Пропускная способность при снижении эффективности:

  • Сеть плагинов: Flash-сокеты необработанные, за исключением первоначального запроса политики
  • WebSockets: подтверждение установления соединения и несколько байтов на кадр
  • HTTP-поток (повторное использование подключения к серверу)
  • HTTP long-poll: соединение для каждого сообщения
  • HTTP-опрос: соединение для каждого сообщения + нет сообщений с данными

Поддержка мобильных устройств:

  • WebSocket: iOS 4.2 и выше. Некоторый Android через эмуляцию Flash или с помощью Firefox для Android или Google Chrome для Android, которые обеспечивают встроенную поддержку WebSocket.
  • Сеть плагинов: немного Android. Не на iOS
  • HTTP *: в основном да

Сложность использования Javascript (от самого простого до самого сложного). По общему признанию, меры сложности несколько субъективны.

  • WebSockets
  • HTTP-опрос
  • Сетевой плагин
  • HTTP длинный опрос, потоковая передача

Также обратите внимание, что есть предложение W3C по стандартизации потоковой передачи HTTP под названием Server-Sent Events . В настоящее время он находится на довольно ранней стадии развития и предназначен для предоставления стандартного API Javascript с сопоставимой простотой с WebSockets.

канак
источник
1
Большое спасибо за хороший ответ, Канака. Не могли бы вы рассказать мне, почему / как HTTP-поток имеет большую задержку, чем веб-сокеты? может быть, на простом примере? большое спасибо.
Software Guy
2
@SoftwareGuy. Много причин. В последних версиях браузеров вы можете использовать обработчик событий onprogress XMLHTTPRequest, чтобы получать уведомления о данных. Но в спецификации указано, что 50 мс - это наименьший интервал уведомления. В противном случае вы должны запросить данные ответа. Кроме того, клиентские отправления устанавливают новое HTTP-соединение и, таким образом, значительно увеличивают задержку приема-передачи. Кроме того, многие веб-серверы прерывают HTTP-соединения примерно через 30 секунд, что означает, что вам часто приходится заново устанавливать push-соединение с сервером. Я видел задержки в обе стороны WebSocket 5-10 мс в локальной сети. Задержка потоковой передачи HTTP, вероятно, составит 50 мс +.
kanaka
Большое спасибо за подробный ответ :)
Software Guy
1
@leggetter Спасибо, Фил, вы имеете в виду, что отправка данных с клиента на сервер через потоковую передачу http вызовет накладные расходы? возможна ли отправка данных на сервер через потоковую передачу HTTP без открытия нового соединения? Спасибо.
Software Guy
1
@Nathan звучит как хороший дипломный проект магистра! Конечно, опрос будет держать систему более загруженной, чем модель, управляемая событиями, но то, что именно может быть экономия энергии, потребует довольно обширного эмпирического тестирования в различных масштабах.
kanaka
13

Некоторые отличные ответы от других, которые охватывают множество вопросов. Вот еще немного.

Единственное преимущество WebSockets перед плагинами, такими как Java Applets, Flash или Silverlight, заключается в том, что WebSockets изначально встроены в браузеры и не зависят от плагинов.

Если под этим вы имеете в виду, что вы можете использовать Java-апплеты, Flash или Silverlight для установления соединения через сокет, то да, это возможно. Однако вы не часто видите это в реальном мире из-за ограничений.

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

Более того, WebSocket может использовать порты 80 и 443, не требуя выделенных портов, опять же благодаря дизайну протокола, который максимально совместим с существующей инфраструктурой HTTP.

Эти альтернативы сокетов (Java, Flash и Silverlight) сложно безопасно использовать в архитектуре с перекрестным происхождением. Таким образом, люди, часто пытающиеся использовать их из разных источников, скорее будут терпеть неуверенность, чем прилагать усилия, чтобы сделать это безопасно.

Они также могут потребовать открытия дополнительных «нестандартных» портов (что администраторы ненавидят делать) или файлов политик, которыми необходимо управлять.

Короче говоря, использование Java, Flash или Silverlight для подключения к сокетам достаточно проблематично, поэтому вы не увидите, как они часто используются в серьезных архитектурах. Flash и Java имеют такую ​​возможность, вероятно, по крайней мере 10 лет, и все же она не является распространенной.

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

Некоторые реализации WebSocket используют Flash (или, возможно, Silverlight и / или Java) в качестве запасного варианта, когда соединение WebSocket не может быть установлено (например, при работе в старом браузере или при вмешательстве посредника).

Хотя какая-то запасная стратегия для таких ситуаций является разумной и даже необходимой, большинство из тех, кто использует Flash и др., Будут иметь недостатки, описанные выше. Так не должно быть - существуют обходные пути для достижения безопасных соединений с возможностью кросс-происхождения с использованием Flash, Silverlight и т. Д. - но большинство реализаций этого не делают, потому что это непросто.

Например, если вы полагаетесь на WebSocket для соединения с разными источниками, это будет работать нормально. Но если вы затем запустите в старом браузере или вмешался брандмауэр / прокси и, скажем, полагаетесь на Flash в качестве запасного варианта, вам будет трудно установить такое же соединение между разными источниками. Если, конечно, вы не заботитесь о безопасности.

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

Единственное преимущество WebSockets перед потоковой передачей по протоколу http заключается в том, что вам не нужно прилагать усилия для «понимания» и анализа полученных данных.

Это не так просто, как открыть поток HTTP и сидеть сложа руки, пока ваши данные текут в течение минут, часов или дольше. Разные клиенты ведут себя по-разному, и вам нужно с этим справляться. Например, некоторые клиенты будут буферизовать данные и не передавать их приложению, пока не будет достигнут некоторый порог. Хуже того, некоторые не передают данные в приложение, пока соединение не будет закрыто.

Таким образом, если вы отправляете несколько сообщений клиенту, возможно, что клиентское приложение не получит данные, например, пока не будет получено 50 сообщений. Это не слишком в реальном времени.

Хотя потоковая передача HTTP может быть жизнеспособной альтернативой, когда WebSocket недоступен, это не панацея. Для надежной работы в бесплодных землях Интернета в реальных условиях необходимо хорошее понимание.

Есть ли другие существенные отличия, которых мне не хватает?

Есть еще одна вещь, о которой еще никто не упомянул, поэтому я подниму ее.

Протокол WebSocket был разработан как транспортный уровень для протоколов более высокого уровня. Хотя вы можете отправлять сообщения JSON или что-то еще напрямую через соединение WebSocket, оно также может передавать стандартные или настраиваемые протоколы.

Например, вы можете использовать AMQP или XMPP через WebSocket, как это уже сделали люди. Таким образом, клиент может получать сообщения от брокера AMQP, как если бы он был подключен непосредственно к самому брокеру (а в некоторых случаях это так).

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

(Естественно, вы хотите иметь возможность делать все это безопасно, поэтому обратитесь к поставщику или поставщику WebSocket.)

Некоторые люди называют WebSocket TCP для Интернета. Потому что так же, как TCP передает протоколы более высокого уровня, WebSocket тоже, но способом, совместимым с веб-инфраструктурой.

Таким образом, хотя отправка сообщений JSON (или любых других) напрямую через WebSocket всегда возможна, следует также учитывать существующие протоколы. Потому что для многих вещей, которые вы хотите сделать, вероятно, уже есть продуманный протокол.

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

Это был отличный вопрос, и все ответы были очень информативными!

Робин Циммерманн
источник
Большое спасибо Робин за отличную помощь и информацию. Если я могу спросить еще одну вещь: я где-то наткнулся на статью, в которой говорится, что потоковая передача HTTP также может кэшироваться прокси, а веб-сокеты - нет. что это значит?
Software Guy
Поскольку StackOverflow ограничивает размер в ответных комментариях, я дал свой ответ ниже: stackoverflow.com/questions/12555043/…
Робин Циммерманн,
@RobinZimmermann, мой любимый ответ. +1 за действительно хороший подробный ответ.
securecurve
10

Если я могу спросить еще одну вещь: где-то я наткнулся на статью, в которой говорится, что потоковая передача http также может кэшироваться прокси, а веб-сокеты - нет. что это значит?

(StackOverflow ограничивает размер ответов на комментарии, поэтому мне пришлось отвечать здесь, а не в строке.)

Неплохо подмечено. Чтобы понять это, представьте себе традиционный сценарий HTTP ... Представьте, что браузер открыл веб-страницу, поэтому он запрашивает , скажем, http://example.com . Сервер отвечает HTTP, который содержит HTML для страницы. Затем браузер видит, что на странице есть ресурсы, поэтому он начинает запрашивать файлы CSS, файлы JavaScript и, конечно же, изображения. Это все статические файлы, которые будут одинаковыми для всех клиентов, запрашивающих их.

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

Итак, клиент №1 запрашивает , скажем, http://example.com/images/logo.gif . Этот запрос проходит через прокси-сервер на центральный веб-сервер, который обслуживает logo.gif. Когда logo.gif проходит через прокси, прокси сохранит это изображение и свяжет его с адресом http://example.com/images/logo.gif. .

Когда приходит клиент №2 и также запрашивает http://example.com/images/logo.gif , прокси может вернуть изображение, и никакой связи с веб-сервером в центре не требуется. Это дает более быстрый ответ конечному пользователю, что всегда хорошо, но это также означает, что на центр меньше нагрузки. Это может привести к снижению затрат на оборудование, сетевых затрат и т. Д. Так что это хорошо.

Проблема возникает при обновлении logo.gif на веб-сервере. Прокси-сервер будет продолжать обслуживать старое изображение, не подозревая о наличии нового изображения. Это приводит к тому, что по истечении срока действия прокси-сервер будет кэшировать изображение только на короткое время, прежде чем он «истечет», и следующий запрос пройдет через прокси-сервер на веб-сервер, который затем обновит кеш прокси. Существуют также более продвинутые решения, в которых центральный сервер может передавать данные в известные кеши и т. Д., И все может стать довольно сложным.

Как это связано с вашим вопросом?

Вы спросили о потоковой передаче HTTP, когда сервер передает HTTP-поток клиенту. Но потоковая передача HTTP похожа на обычный HTTP, за исключением того, что вы не прекращаете отправлять данные. Если веб-сервер обслуживает изображение, он отправляет клиенту HTTP-протокол, который в конечном итоге завершается: вы отправили все изображение. И если вы хотите отправить данные, это точно так же, но сервер просто отправляет очень долго (например, это гигантское изображение, скажем) или даже никогда не завершает работу.

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

Итак, если ваш клиент сделал запрос, например, о ценах на акции и получил ответ, то следующий клиент может сделать тот же запрос и получить кэшированные данные. Наверное, не то, что вы хотите! Если вы запрашиваете цены на акции, вам нужны самые свежие данные, верно?

Так что это проблема.

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

Робин Циммерманн
источник
1
отличная деталь Робин, большое спасибо! я очень ценю ваш обстоятельный ответ. Я уже многому научился у всех здесь замечательных людей! :)
Software Guy
4

HTTP ограничивает количество соединений, которые клиент может иметь с сервером, до 2 (хотя это может быть уменьшено с помощью поддоменов), и IE, как известно, активно применяет это. Firefox и Chrome позволяют больше (хотя я не могу точно вспомнить, сколько именно). Это может показаться не такой уж большой проблемой, но если вы постоянно используете одно соединение для обновлений в реальном времени, все остальные запросы должны блокироваться через другое HTTP-соединение. Кроме того, наличие большего количества открытых соединений от клиентов увеличивает нагрузку на сервер.

WebSockets - это протокол на основе TCP и, как таковой, не страдают от этого ограничения на количество подключений на уровне HTTP (но, конечно, поддержка браузеров неоднородна).

Сок
источник
спасибо thejuice, так что, помимо проблемы нескольких одновременных подключений, как указано вами, верны ли остальные мои предположения относительно веб-сокетов?
Software Guy