Общие вопросы по полному опросу/HTTP-потоку

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

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

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

С потоком HTTP

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

Я буду благодарен за любые ответы, спасибо заранее.

Ответ 1

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Ответ 2

Как проверить результаты во время соединения Ajax, все еще активен? Я знаю функцию jQuery success для вызовов 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 отсутствует, однако, поскольку успех, ошибка, полный и statusCode охватывают все мыслимые требования.

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

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

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