PHP бесконечный цикл или jQuery setInterval? - PullRequest
5 голосов
/ 26 декабря 2011

Js:

<script>
function cometConnect(){
    $.ajax({
          cache:false,
          type:"post",
          data:'ts='+1,
          url: 'Controller/chatting',
          async: true,
          success: function (arr1) {
              $(".page-header").append(arr1);
          },
          complete:function(){
            cometConnect(true);
            nerr=false;
          },
          dataType: "text"
        }); 
}
cometConnect();
</script>

Php:

public function chatting()
{
    while(true)
    {
       if(memcache_get(new_message))
          return new_message; 
       sleep(0.5);
    }
}

Является ли это лучшим решением, чем установка setInterval, который подключается к методу PHP, который возвращает сообщение, если оно есть каждую 1 секунду (1 секунда увеличивается +0,25 каждые 5 секунд, скажем)?

Если бы я использовал первое решение, я мог бы, вероятно, использовать sleep (0.5), он бы мгновенно давал мне сообщения, потому что цикл php дешев, не так ли?

Итак, какое решение лучше (что более важно, которое требует меньше ресурсов?).Потому что таких чатов будет сотни.

Плюс, может ли первое решение вызвать проблемы?Допустим, я бы перезагрузил страницу или остановил бы выполнение каждые 30 секунд, чтобы не получить 502 Bad Gateway.

РЕДАКТИРОВАТЬ: Я считаю, что второе решение лучше, поэтому ясобираюсь переопределить мой сайт, но мне просто интересно, может ли это вызвать проблемы у пользователя или нет?Может ли случиться что-то непредвиденное?Первая проблема, которую я заметил, это то, что вы не можете перейти на другую страницу, пока не появится хотя бы одно новое сообщение.

Ответы [ 5 ]

9 голосов
/ 29 декабря 2011

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

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

  1. введите
  2. отправить сообщение
  3. получить сообщение
  4. выход

Таким образом, цикл на стороне клиента выглядит следующим образом (псевдокод):

while (userInChat)
{
    if (userEnteredMessages)
    {
        userSendMessages(userEnteredMessages)
    }
    if (chatNewMessages)
    {
        displayMessages(chatNewMessages)
    }
}

Как вы уже отметили в своем вопросе, проблема заключается в том, чтобы внедрить подобный чат для веб-сайта.

Чтобы реализовать такой «цикл» для веб-сайта, вы в первую очередь сталкиваетесь с ситуацией, когда вы не хотите, чтобы здесь был реальный цикл. Пока пользователь находится в чате, он будет запускаться, запускаться и запускаться. Итак, вы хотите распределить выполнение цикла по времени.

Для этого вы можете преобразовать его в набор функций событий:

ChatClient
{
    function onEnter()
    {
    }
    function onUserInput(messages)
    {
        sendMessages = send(messages)

        display(sendMessages)
    }
    function onReceive(messages)
    {
        display(messages)
    }
    function onExit()
    {
    }
}

Теперь возможно инициировать события вместо цикла. Осталась только реализация, которая запускает эти события с течением времени, но на данный момент это не очень интересно, потому что это будет зависеть от того, как на самом деле реализован обмен данными чата.

Всегда существует удаленная точка, к которой клиент чата (каким-то образом) подключен, чтобы отправлять свои собственные сообщения и получать новые сообщения.

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

Это уже видно в приведенном выше псевдокоде ChatClient, происходит событие, когда пользователь вводит одно или несколько сообщений, которые затем будут отправлены (записаны). И прочитанные сообщения будут доступны в функции события onReceive.

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

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

Поток сообщений начинается с первого сообщения и заканчивается последним. Итак, вы просто даете первому сообщению номер 1, а затем каждое новое сообщение получит следующий более высокий номер. Давайте назовем это идентификатором сообщения.

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

Не связанные с потоком сообщения - это сообщения, которые пользователь уже ввел, но которые еще не были отправлены на сервер. Пока сервер получает «свободные» сообщения, он может поместить их в поток, назначив идентификатор:

    function onUserInput(messages)
    {
        sendMessages = send(messages)

        display(sendMessages)
    }

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

Затем программа отображения может отображать сообщения в порядке их потоков.

Таким образом, независимо от того, как реализовано взаимодействие клиент / сервер, с такой структурой вы можете фактически обрабатывать систему чата на основе сообщений и отсоединять ее от базовых технологий.

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

Другое взаимодействие - чтение новых сообщений с сервера.Чтобы сделать это по сети эффективно, клиент сообщает серверу, с какого сообщения ему нравится читать.Затем сервер будет передавать сообщения с этого времени (ID) клиенту.

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

Идеальная реализация состояла бы в том, чтобы иметь одно соединение ссервер, который позволяет читать и писать сообщения в полнодуплексном режиме.Однако в javascript такой технологии еще не существует.Эти вещи разрабатываются с помощью Websockets и API-интерфейсов Webstream и тому подобного, но на данный момент давайте упростим ситуацию и посмотрим, что у нас есть: HTTP-запросы без сохранения состояния, немного PHP на сервере и база данных MySQL.

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

Сценарий записи транзакции просто подключится к базе данных, вставит сообщение (я) ивернуть идентификаторы.Это очень распространенная операция, и она должна быть быстрой (mysql имеет своего рода мост memcache, который должен сделать операцию сохранения еще более быстрой и удобной).

Сценарий чтения транзакций одинаково прост, он просто прочитает всесообщения с идентификатором выше, чем переданные ему и возвращающие его клиенту.

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

Тем не менее ваш веб-сервер и общее интернет-соединение могут быть недостаточно быстрыми (хотя существует keep-alive ).

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

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

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

Если в будущем веб-сокеты станут более доступными (что, возможно, никогда не будетслучай из соображений безопасности), вы также можете предложить другой тип сервера для веб-сокетов.Пока структура данных потока не повреждена, это будет работать с разными типами серверов рядом друг с другом.База данных позаботится о соответствии.

Надеюсь, что это полезно.


В качестве дополнительного примечания: HTML5 предлагает нечто, называемое Потоковые обновления с сервером.Отправленные события с онлайн-демонстрацией и PHP / JS .Функция HTML 5 уже предлагает объект события в javascript, который можно использовать для создания примерной транспортной реализации клиента чата.

5 голосов
/ 03 января 2012

Теперь это не задача PHP или jQuery. Node.js! Есть socket.io, что означает WebSockets.

Я объясню, почему node.js лучше. У меня есть задача обновлять маркеры страниц каждые 10 секунд. Я сделал это с первым методом. Когда количество постоянных пользователей достигает 200. Http-сервер и php были в беде. Было много запросов, которые были излишними.

Что дает вам Node.js:

  • Создание отдельных комнат для чатов ( здесь )
  • Отправляет данные только тем, у кого есть обновления (например, если у меня нет новых сообщений, мое обновление будет заблокировано, когда будет выбор из базы данных)
  • Вы запускаете 1 запрос к БД в 0,5 секунды, независимо от количества пользователей

Просто посмотрите на Node.js и Socket.io. Это решение помогло мне с большим ускорением.

5 голосов
/ 26 декабря 2011

Я написал сообщение в блоге о том, как мне пришлось справляться с подобной проблемой (используя node.js, но принципы применимы). http://j -query.blogspot.com / 2011/11 / Стратегии-для-масштабирование в реальном времени web.html

Мое предложение: если оно будет большим, либо: а) вам нужно кэшировать как сумасшедший на уровне веб-сервера, что, вероятно, означает, что для вашего вызова AJAX должна быть временная метка, или б) используйте что-то вроде socket.io , который предназначен для масштабирования веб-приложений в реальном времени и имеет встроенную поддержку каналов.

5 голосов
/ 29 декабря 2011

Бесконечные циклы в php могут и будут использовать 100% вашего процессора.Функции сна решат эту проблему.Однако вы, вероятно, не хотите, чтобы отдельный HTTP-процесс выполнялся постоянно для каждого клиента, подключенного к вашему серверу, потому что у вас закончились подключения.У вас может быть только один процесс php, который просматривает все входящие сообщения и направляет их нужному человеку по мере их поступления. Этот процесс можно запускать из задания cron раз в минуту.Я написал этот тип вещей много раз, и это работает как шарм. Примечание: убедитесь, что вы не запускаете процесс, если он уже запущен, или у вас возникнут проблемы с многопроцессорностью (например, получение двойных сообщений).Другими словами, вам нужно сделать процесс безопасным.

Если вы хотите общаться в режиме реального времени, то вы можете взглянуть на StreamHub , который открываетполнодуплексное соединение с браузером клиента.

2 голосов
/ 26 декабря 2011

Прежде всего, спросите себя, нужно ли часто обновлять чат. Какой тип чатов будет происходить? Это в реальном времени? Простые вопросы и ответы? Техническая поддержка? И т. Д. Во всех случаях, кроме чатов в реальном времени, вам будет лучше использовать дизайн с длинным опросом на основе JS, потому что мгновенные ответы не так важны. Если это для чатов в реальном времени, то вы должны рассмотреть Gmail-подобный дизайн, при котором вы сохраняете XHR открытым и отправляете сообщения обратно клиенту по мере их получения. Если ресурсы соединения вызывают беспокойство, вы можете получить их, используя длинный опрос с очень коротким интервалом (например, 5-10 секунд).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...