Длинный опрос / HTTP Streaming Общие вопросы - PullRequest
19 голосов
/ 27 августа 2011

Я пытаюсь создать теоретическое приложение для веб-чата с и , я читал о длинном опросе и потоковой передаче http, и мне удалось применить большинство представленных принциповв статьях.Тем не менее, есть 2 основные вещи, которые я до сих пор не могу понять.

С длинным опросом

  • Как сервер узнает, когда было отправлено обновление?нужно ли будет постоянно запрашивать базу данных или есть лучший способ?

с потоковой передачей HTTP

  • Как проверить результаты во время активности соединения Ajax?Мне известна функция jQuery success для вызовов ajax, но как мне проверить данные , пока соединение все еще установлено?

Буду признателен всем и каждомуответы, заранее спасибо.

Ответы [ 2 ]

25 голосов
/ 27 августа 2011

Да, кометоподобные техники обычно взрывают мозг вначале - просто заставляют вас думать по-другому. И еще одна проблема заключается в том, что для PHP не так много ресурсов, потому что все делают свою Comet в node.js, Python, Java и т. Д.

Я постараюсь ответить на ваши вопросы, надеюсь, это пролило бы свет на эту тему для людей.

Как сервер узнает, когда было отправлено обновление? нужно ли будет постоянно запрашивать базу данных или есть лучший способ?

Ответ таков: в наиболее общем случае вам следует использовать очередь сообщений (MQ). Функциональность RabbitMQ или Pub / Sub, встроенная в магазин Redis, может быть хорошим выбором, хотя на рынке доступно множество конкурирующих решений, таких как ZeroMQ, Beanstalkd и т. Д.

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

Также я должен отметить, что если вы будете искать реализации Comet-chat на других языках, вы можете заметить простые, не использующие MQ. Так как же они обмениваются информацией тогда? Дело в том, что такие решения обычно реализуются как автономные однопоточные асинхронные серверы, поэтому они могут хранить все соединения в локальном массиве потока (или что-то подобное), обрабатывать много соединений в одном цикле и просто выбирать одно и уведомлять при необходимости. Такие асинхронные серверные реализации являются современным подходом, который очень хорошо подходит для Comet-техники. Однако вы, скорее всего, реализуете свою Comet поверх mod_php или FastCGI, в этом случае этот простой подход вам не подходит, и вам следует использовать MQ.

Это может быть очень полезно для понимания того, как реализовать автономный асинхронный Comet-сервер для обработки множества соединений в одном потоке. Последние версии PHP поддерживают Libevent и Socket Streams, поэтому в PHP можно реализовать и такой тип сервера. В документации PHP есть пример .

Как проверить результаты, пока Ajax-соединение все еще активно? Мне известна функция успеха jQuery для вызовов ajax, но как проверить данные, пока соединение еще установлено?

Если вы проводите длительные опросы с помощью обычной техники Ajax, такой как обычный XHR, jQuery Ajax и т. Д., У вас нет простого способа передать несколько ответов в одном запросе Ajax. Как вы упомянули, у вас есть только обработчик «успеха», чтобы иметь дело с ответом в целом, а не с его частью. В качестве обходного пути люди отправляют только один ответ на запрос и обрабатывают его в обработчике «успеха», после чего они просто открывают новый запрос длинного опроса. Так работает HTTP-протокол.

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

Если вы хотите обрабатывать несколько ответов на один запрос / соединение надежным способом, вам следует рассмотреть возможность использования более продвинутой технологии, такой как WebSocket, которая поддерживается самыми современными браузерами, или на любой платформе, поддерживающей необработанные сокеты (например, как Flash или если вы разрабатываете для мобильного приложения, например).

Не могли бы вы подробнее рассказать об очередях сообщений?

Очередь сообщений - это термин, который описывает автономную (или встроенную) реализацию шаблона Observer (также известного как «Опубликовать / Подписаться» или просто PubSub). Если вы разрабатываете большое приложение, его использование очень полезно - оно позволяет отделить различные части вашей системы, реализовать асинхронный дизайн, управляемый событиями, и значительно упростить вашу жизнь, особенно в гетерогенных системах. Он имеет много приложений для реальных систем, я упомяну лишь пару из них:

  • Очереди задач. Допустим, мы пишем собственный YouTube и нам нужно конвертировать видеофайлы пользователей в фоновом режиме. Очевидно, у нас должно быть веб-приложение с пользовательским интерфейсом для загрузки фильма и фиксированное количество рабочих процессов для преобразования видеофайлов (возможно, нам даже понадобится несколько выделенных серверов, на которые только уйдут наши сотрудники). Также нам, вероятно, придется написать нашим работникам на C, чтобы обеспечить лучшую производительность. Все, что нам нужно сделать, - это просто настроить сервер очереди сообщений для сбора и доставки задач преобразования видео из веб-приложения нашим работникам. Когда рабочий появляется, он подключается к MQ и бездействует в ожидании новых задач. Когда кто-то загружает видеофайл, веб-приложение подключается к MQ и публикует сообщение с новым заданием. Мощные MQ, такие как RabbitMQ , могут в равной степени распределять задачи по количеству подключенных работников, отслеживать, какие задачи были выполнены, гарантировать, что ничего не потеряно, и обеспечивать отказоустойчивость и даже интерфейс администратора для просмотра текущих задач, ожидающих выполнения. и статистика.
  • Асинхронное поведение. Наш Comet-чат - хороший пример. Очевидно, что мы не хотим периодически опрашивать нашу базу данных (что тогда использует Comet? - Небольшая разница в выполнении периодических Ajax-запросов). Мы бы предпочли, чтобы кто-то уведомил нас о появлении нового сообщения в чате. И очередь сообщений - это кто-то. Допустим, мы используем Redis хранилище ключей / значений - это действительно отличный инструмент, который обеспечивает реализацию PubSub среди своих функций хранилища данных. Самый простой сценарий может выглядеть следующим образом:
    1. После того, как кто-то входит в чат, делается новый запрос на длинный опрос Ajax.
    2. Обработчик запросов на стороне сервера выдает команду Redis для подписки на канал 'newmessage'.
    3. Как только кто-то вводит сообщение в свой чат, обработчик на стороне сервера публикует сообщение в теме "newmessage" Redis.
    4. После публикации сообщения Redis немедленно уведомит всех ожидающих обработчиков, которые ранее подписались на этот канал.
    5. После получения уведомления PHP-код, который сохраняет запрос на длительный опрос, может вернуть запрос с новым сообщением чата, поэтому все пользователи будут уведомлены. В этот момент они могут читать новые сообщения из базы данных, или сообщения могут передаваться непосредственно в полезную нагрузку сообщения.

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

5 голосов
/ 08 сентября 2011

Как проверить результаты, пока Ajax-соединение все еще активно? Мне известна функция успеха jQuery для вызовов ajax, но как мне проверить данные, пока соединение еще установлено?

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

Если вы сохраняете соединение между клиентом и сервером открытым, можно отправлять обновления, которые добавляются к ответу. При каждом обновлении происходит событие XMLHttpRequest.onreadystatechange, и значение XMLHttpRequest.readyState будет равно 3. Это означает, что XMLHttpRequest.responseText продолжает расти.

Вы можете увидеть пример этого здесь: http://www.leggetter.co.uk/stackoverflow/7213549/

Чтобы увидеть код JS, просто просмотрите исходный код. Код PHP:

<?php
$updates = $_GET['updates'];
if(!$updates) {
  $updates = 100;
}

header('Content-type: text/plain');
echo str_pad('PADDING', 2048, '|PADDING'); // initial buffer required

$sleep_time = 1;
$count = 0;
$update_suffix = 'Just keep streaming, streaming, streaming. Just keep streaming.';
while($count < 100) {
  $message = $count . ' >> ' . $update_suffix;
  echo($message);
  flush();
  $count = $count + 1;
  sleep($sleep_time);
}
?>

В браузерах на основе Gecko, таких как Firefox, можно полностью заменить responseText с помощью multipart/x-mixed-replace. Я не привел пример этого.

Не похоже, что можно достичь такой же функциональности, используя jQuery.ajax. Обратный вызов success не срабатывает при каждом событии onreadystatechange. Это удивительно, поскольку в документации говорится:

Механизм onreadystatechange не предоставляется, однако, так как success, error, complete и statusCode охватывают все возможные требования.

Таким образом, документация потенциально неверна, если я не понимаю ее неправильно?

Вы можете увидеть пример, который пытается использовать jQuery здесь: http://www.leggetter.co.uk/stackoverflow/7213549/jquery.html

Если вы посмотрите на вкладку сети в инструментах Firebug или Chrome Developer, вы увидите, что размер файла stream.php увеличивается, но обратный вызов success по-прежнему не срабатывает.

...