Простой publish-subscribe для мультиплеера на CoronaSDK, Gideros, Moai

    Однажды с коллегой столкнулись с проблемой реализации рилтайм мультиплеера на CoronaSDK. Сначала попробовали сервис pubnub.com, но со временем поняли, что не устраивает их latency (у них все через http) и цены. Не найдя ничего получше, решили на скорую руку создать на Node.js свой велосипед (или скорее самокат, потому как весь серверный код умещается в 90 строк с комментариями).

    Назвали в шутку NoobHub. Распространяется под лицензией WTFPL.


    Штука получилась весьма быстрой и, судя по отзывам пользователей, способной крутиться месяцами на сервере без перезапусков и утечек памяти. Системные требования: Node.js 0.6.x и выше (входит в стандартный пакет Ubuntu), никаких дополнительных модулей не требуется.
    Если Вы пишете мобильное мультиплеер приложение на Lua используя CoronaSDK, Moai или Gideros, то есть хорошие новости: клиент под эти SDK отлично работает, бери и пользуйся.

    Несколько фактов:


    • Выпущено несколько десятков приложений от разных разработчиков, все хвалят (косячить нечему). Вот к примеру частый гость российских топов, Durak HD
    • Написать свой клиент для любого языка, где есть сокеты — проще простого
    • Lua код может служить примером работы с LuaSocket
    • В демо проект захардкоджен мой тестовый сервер, так что даже ничего поднимать ненадо чтобы потестить (количесто тестящих периодически поднимается до 200 CCU. Я надеюсь никто по ошибке не использует его в продакшене, на том сервачке всего 64 Mb RAM...)

    Использование


    Запустили сервер:
    $ node server.js
    На клиенте создали объект:
    hub = noobhub.new({ server = "127.0.0.1"; port = 1337; });
    

    Подписались на канал, в колбек-функции обрабатываем сообщение других участников:
    hub:subscribe({
          channel = "hello-world";  
            callback = function(message)
    
                if(message.action == "ping")   then 
                    print("Pong!")
                end;
    
            end;
        });
    
    

    Отправили сообщение:
     hub:publish({
            message = {
                action  =  "ping",
                timestamp = system.getTimer()
            }
        });
    
    


    Занудные подробности


    Ключевым элементом Node.js скрипта является объект server, который слушает порт и реагирует на соединения. Для каждого из них создаётся socket с уникальным хешем для последующего поиска и удаления в случае необходимости.
    Сокеты в свою очередь слушают события получения данных и закрытия соединения.
    Они распознают два типа сообщений: __SUBSCRIBE____ENDSUBSCRIBE__ — подписка на канал,
    __JSON__START_<_MESSAGE>__JSON__END__ — произвольное сообщение. При подписке сокет добавляется в пул CHANNELNAME и все последующие сообщения приходящие по данному каналу будут передаваться и новоприбывшему. Во втором случае тело MESSAGE будет адресовано всем подписчикам канала CHANNELNAME. Для отсоединения достаточно закрыть сокет на стороне клиента, а дальше сервер знает, что делать с дезертиром.
    Получается, что один EventLoop ноды делает всю работу по получению данных и расфасовке их клиентам в сокеты. Если клиентов будет много, соответственно увеличенный цикл будет вносить задержку в доставку сообщений. Вопрос конечно, сколько надо клиентов чтобы просадка была хоть сколько-то заметной. При 2к CCU просадки latency не наблюдалось (больше у нас просто небыло), но я сомневаюсь что и 20к даст заметную просадку.
    На клиенте все с точностью до наоборот, клиент подключается к socket серверу, подписывается на канал, и асинхронно слушает сообщения от других участников канала.
    Есть автоматический reconnect & resubscribe при обрыве (облегчает жизнь юзерам с плохим коннектом на EDGE/3G).

    Итого: простой Publish-Subscribe для небольших и даже средних проектов.


    Исходный код сервера и клиентов: https://github.com/Overtorment/NoobHub
    Поделиться публикацией
    Похожие публикации
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 4
    • +1
      pubnub вообще-то через вебсокеты :) Да и нода у вас уж очень древняя
      • 0
        Nope. Lua клиент через HTTP. А нода 0.6 это минимальная, на свежих тоже работает.
        • +1
          Да, точно, Lua согласен. Интересно, есть там модули для websocketa а то не очень приятно городить свой протокол поверх
      • +1
        Очень удобный и шустрый сервис, пользуем его для парочки своих прил на Corona SDK. Ещё дописать бы к нему механизм контроля потерянных пакетов и цены бы не было. Редко, но бывает пока один клиент в оффлайне и реконнектится, другой может что-то слать в канал. Впрочем, это актуально для turn-based прил только, и то это весьма специфичный момент.

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