Текстовый чат для сайта

image

Хочу поделиться опытом создания текстового чата на основе nginx-push-stream-module модуля Nginx, PHP и Javascript. Этот модуль функционирует по принципу long polling и может быть использован как для обмена мгновенными сообщениями между пользователями, так и для системы push–уведомлений.

Добавление модуля Nginx


Будем считать, что у вас уже установлен Nginx. Поэтому для начала нужно скачать и добавить модуль nginx-push-stream-module и пересобрать Nginx вручную. Подробное руководство по добавлению модуля можно найти здесь и здесь, думаю, нет смысла писать повторно.

Конфигурация


Для осуществления поддержки long polling, в конфигурации Nginx объявим точку публикации сообщений (в данном примере publish) и точку подписки для получения сообщений (в данном примере subscribe).

http {
…
    server {
    …
    location /publish {
             push_stream_publisher               admin;    # определяет режим для данного блока
             push_stream_channels_path    $arg_id;   # id канала для публикации сообщения
             push_stream_store_messages         on;   # включение или отключение очереди сообщений
             allow          127.0.0.1;   # делает публикацию сообщений доступной только с  вашего сервера
          }

          location ~ /subscribe/(.*) {
             push_stream_subscriber         long-polling ; # определяет блок как подписчика 
                                                           # (существуют разные режимы)
             push_stream_channels_path                 $1;  # id канала для подписки
             push_stream_longpolling_connection_ttl    300s;  # период времени, в течении которого подписчик 
                                                               # остается подключенным (ожидает сообщение) до 
                                                               # переподключения
            push_stream_last_received_message_time  $arg_time;  # время получения последнего сообщения
            push_stream_last_received_message_tag     $arg_tag;  # метка, определяющая последнее доставленное 
                                                                 #сообщение    
          }

   }

push_stream_shared_memory_size          32M;
}


Внутри блока http нужно указать директиву push_stream_shared_memory_size, то есть размер выделяемой памяти.

Отправка сообщений в PHP


В PHP сообщения отправляем обычным POST методом.

$channel_id = subscriber1;  //id канала для публикации сообщения 

$message=’Привет!’; // сообщение

//отправка сообщения
$ch = curl_init('http://127.0.0.1/publish?id='.$channel_id);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($message));
curl_exec($ch);
curl_close($ch);


Получение сообщений в Javascript (Jquery)


Есть несколько способов подписаться на канал, самый простой – Ajax запрос методом GET.

var channelId = subscriber1; //id подписчика
var  last_etag=0; //переменная для заголовка 'Etag'
var  last_time=null; //переменная для заголовка 'Last-Modified'

function new_message() {
    $.ajax({
        url: '/subscribe/' + channelId,
        type: "GET",
        dataType: 'json',
        beforeSend: function(xhr){xhr.setRequestHeader('Etag', last_etag);xhr.setRequestHeader('Last-Modified', last_time);},
        success: function(data, status, xhr) {
        last_etag =xhr.getResponseHeader('Etag'); //присваиваем новое значение переменной last_etag 
                                                  // из заголовка 'Etag' ответа
        last_time =xhr.getResponseHeader('Last-Modified'); // присваиваем новое значение переменной last_time 
                                                           // из заголовка 'Last-Modified' ответа

         //здесь что-то делаем с полученным сообщением

         setTimeout(new_message, 500);	 // переподключаемся сразу после получения ответа
        }
    })
}
new_message();

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

Similar posts

Ads
AdBlock has stolen the banner, but banners are not teeth — they will be back

More

Comments 17

    +2
    Вообще-то, наверное, «текстовый чат».
      +1
      Вы правы, исправил. Спасибо!
      +3
      Так делали ещё во времена, когда я ходил пешком под стол, да и решение такое вполне очевидно и не вызывает какого-либо интереса, в чём смысл статьи — притвориться КО?

      Я бы понял, если бы рассказывалось о реализации поллинга или архитектуре\паттернах вебсокетной реализации.
        +1
        Наверное реклама проекта, потому что статья на самомо деле слабоватая. Пару гистов чтобы не забыть )))
          +6
          Не совсем так. В этой реализации, как я вижу, PHP не дёргается каждые пол секунды как «ещё во времена, когда я ходил пешком под стол» а дёргается nginx что как я понимаю в десятки раз увеличивает нагрузку которую сможет такое решение выдержать по сравнению с той реализацией, которую вы имеете ввиду.

          По сути статья в 2х словах — смотрите какой интересный модуль есть у nginx и как его можно использовать.

          Автору спасибо за наводку на модуль, интересно будет посмотреть его.
            0
            ETag и Last-Modified же собирается после отработки всего серверного кода, разве нет? Если я прав, то мы получаем наоборот только увеличение нагрузки (двойной запрос) — один на проверку актуальности, другой на получение данных.
              0
              Нет, JS всегда(если конечно же в какой-то момент AJAX запрос не вернёт success и дело не дойдёт до setTimeout), каждые пол секунды, долбит nginx на тему нет ли чего нового (при этом PHP не используется). Все сообщения Nginx хранит в ОЗУ —

              push_stream_shared_memory_size 32M;


              А в nginx они попадают, в данном примере, через PHP, который при каком-то событии пихает их туда вот так:
              $channel_id = subscriber1; //id канала для публикации сообщения

              $message=’Привет!’; // сообщение

              //отправка сообщения
              $ch = curl_init('http://127.0.0.1/publish?id='.$channel_id);
              curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
              curl_setopt($ch, CURLOPT_POST, true);
              curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($message));
              curl_exec($ch);
              curl_close($ch);


              По крайней мере я так это понял по коду. Но могу ошибаться.
                0
                О как. Да, похоже на правду, спасибо, моя вина что не разобрался в коде и подходе.
                  +2
                  Не совсем так, Ajax запрос отправляется один раз каждые 5минут (согласно директиве push_stream_longpolling_connection_ttl 300s;), а при success делает повторный запрос (переподключается) через полсекунды.
            0
            Кстати говоря, вот ещё статья про этот плагин на хабре Long Polling от А до Я своими руками
              0
              Я бы на вашем месте использовал websocket.
                0
                В вебсокет «снаружи» не отправить. Да и кол-во коннекшенов к нему лимитировано в браузере
                0
                Хе. тема видеочата в разы была бы интереснее.
                  –2
                  О. Это первая статья на Хабре? Тогда — с почином!
                  0
                  Не знал про подобный модуль, очень вовремя появился пост. Который раз уже такое случается — всплывает проблема и практически сразу на хабре появляется статья с решением. Магия (:

                  Есть необходимость использовать websocket или long-polling, проект на Groovy + Grails (Java). Есть grails-плагины использующие Atmosphere, но как-то не хочется с ними возиться, да и непонятно, что с производительностью.

                  А тут такое интересное решение, а главное — универсальное (подходит для чего угодно), да и производительность должна быть неплохой.
                    –1
                    Ничего особенного.
                      0
                      er

                      Only users with full accounts can post comments. Log in, please.