PHP игровой сервер, несколько TCP-клиентов?

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

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

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

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

Где мне нужна помощь:

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

Может ли кто-нибудь дать мне некоторые технические советы о том, как достичь этих целей? Я не думаю, что все это выглядит слишком много, чтобы спросить PHP, но исправьте меня, если я ошибаюсь!

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

while(gamerunning)
{
    CheckForNewClients();
    GetStatusFromClients();
    DoGameUpdate();
    SendGameStateToClients();
}

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

Ответ 1

Я бы не предложил использовать PHP для этого типа приложений. PHP официально не поддерживает многопоточность и работает PHP script для undefined периода времени (например, сервера), не является рекламой.

Конечно, вы могли бы попробовать сделать историю:)

(пожалуйста, поправьте меня, если я ошибаюсь)

Ответ 2

Вам действительно нужно запустить демон PHP, чтобы сделать это эффективно (и ему НЕОБХОДИМО быть PHP 5.3). Я написал довольно полный обзор использования PHP для процессов демона. Независимо от того, что вы выбрали, я бы предложил вам использовать основанную на события систему run loop.

Я разработал базовую библиотеку RunLoop под названием LooPHP, которая, вероятно, будет полезна, особенно если вы собираетесь иметь дело с *_select. Я был бы более чем счастлив ответить на любой вопрос, который у вас есть.

EDIT:

В системе на основе событий вы не просто while список команд, вы реагируете на прослушиватель. Например...

Вместо этого:

while( 1 ) {
    ... /* listen, react */
} /* repeat */

Запуск циклов работы путем регистрации слушателя (сокетов и других генераторов событий async)

class ReactClass { ... }

$loop = new LooPHP_EventLoop( new ReactClass );

//add one time event
$loop->addEvent( function() {
    print "This event was called 0.5 second after being added\n";
}, 0.5 /* in seconds */ );

//this creates a repeating event, this is called right away and repeats
$add_event = function() use ( $loop, &$add_event ) {
    print "This event is REPEATEDLY called 0.1 every second\n";
    $loop->addEvent( $add_event, 0.1 );
};
$add_event();

//start the loop processing, no events are processed until this is done
$loop->run(); //php doesn't leave this call until the daemon is done
exit(0); //cleanly exit

Вышеприведенный случай представляет собой очень простой 1 источник EventLoop и вручную добавляет временные функции (их можно добавить даже из вызова ReactClass).

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

Если вам нужны другие примеры, вы можете найти их в github.

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