10

I'm making a web browser based multiplayer game. I've determined that websockets are the best way to handle communications given its realtime nature. The client uses a HTML5 canvas to render the game and websockets to communicate with the host.

I've elected to use PHP for hosting the game as it seems to be preferred by hosting providers. I haven't used PHP before but have done similar things with websockets in Java, but relying heavily on multithreading.

I've been looking at a few tutorials on php sockets with multiple clients; but most of them do things like fork off new processes for each client. Since I'll have a constantly running game loop I don't think this is suitable.

What I'm trying to achieve is a means of assigning ports to each client as they connect, listening for new clients, exchanging data with the current list of clients and running the game loop all together.

The places where I need help are:

  • How to find and assign ports to new clients, notify the client of that port, and clean it up when they disconnect.
  • How to do the above, and all other socket transactions, without blocking the game loop. It would be acceptable to accept messages from clients in partial chunks and only act upon a complete message.

Can anyone give me some technical advice on how to achieve these goals? I don't think this all looks like too much to ask of PHP but correct me if I'm wrong!

Some pseudocode of what I'd ideally like to achieve server-side. None of the functions should block: Array clients;

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

[Update] For anyone interested, I created a dedicated application supporting web sockets (specifically using Java, and 'TooTallNates' web socket library) rather than an actual web service as it seemed to make more sense, though incidentally it seems most web browsers have since slung web sockets in the bin due to security issues.

Toby Wilson
  • 1,467
  • 5
  • 19
  • 42
  • 1
    In case you can get a VPS or something that allows you to run Node.js on it, I would strongly suggest to take the Node path. Multiplayer servers in Node.js are a piece of cake. – Ivo Wetzel Nov 23 '10 at 23:35
  • Isn't node.js a client side solution for websockets? – Toby Wilson Nov 24 '10 at 12:17
  • no, nodejs in short is blazing fast, eventdriven, serverside javascript for writing servers. – nocksock Nov 24 '10 at 16:27
  • Also: I would suggest to use NodeJS for this task. – nocksock Nov 24 '10 at 16:28
  • 1
    PHP is not really the optimal solution to this, you want a language that is either event based (nodejs), or has an evented framework (ruby - eventmachine, python - twisted, tornado, just to name a few). Long running PHP scripts are the path to pain and tears (voice of experience here..) – James Butler Dec 07 '11 at 13:22
  • I remember PHP does not support multithreading, you might choose another. – Danil Chernokalov May 25 '13 at 00:30
  • I'm using PHP WebSockets for realtime game server: https://github.com/Devristo/phpws – psycho brm Oct 20 '13 at 03:01

2 Answers2

7

You really need to run a PHP daemon in order to do this effectively (and it NEEDS to be PHP 5.3). I wrote a fairly completely overview of using PHP for daemon processes. Whatever you chose, I would suggest you use an event based, run loop system.

I've designed a basic RunLoop library called LooPHP which could probably be helpful, especially if your going to be dealing with *_select. I'd be more than happy to answer any question you have about that.

EDIT:

In an event based system you don't simply while a list of commands, you react to a listener. For example...

Instead of doing:

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

Run loops work by registering listener (sockets, and other async event generators)

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

The above case is a very simple 1 source EventLoop and a manually add timed functions ( these can be added even from within a call to ReactClass).

In the application I'm working I needed to have both asynchronous event feed into the backend (via a socket) and then needed to have the ability to call functions arbitrary offset from the original event (for timed-out clients, etc).

If you'd like more examples, you can find them over at github.

I hope you find this useful.

Community
  • 1
  • 1
Kendall Hopkins
  • 43,213
  • 17
  • 66
  • 89
  • I like the look of this. Could you show me how to set this up so that the event functions have access to an array of objects that is being constantly updated in a seperate game loop? – Toby Wilson Nov 24 '10 at 12:09
  • Is it possible to use this library as a game server to which web game will connect to update its status say 3 times a second? – psycho brm Oct 17 '13 at 20:04
  • @psychobrm It depends on your load, size and cost. I'd give it a try and see if it scales well enough for you. – Kendall Hopkins Oct 17 '13 at 22:17
6

I wouldn't suggest using PHP for this type of application. PHP doesn't officially support multithreading and running a PHP script for an undefined period of time (like a server) isn't really an advertised feature.

Of course you could try and make history :)

(please correct me if i'm mistaken)

Daniel Sorichetti
  • 1,921
  • 1
  • 20
  • 34
  • 3
    Maybe I've made history... I've done socket server daemons with PHP in the past (because my employer enforced that technology) and I don't see what the problem is. It works just fine, with both a single process or multiple ones. – netcoder Nov 24 '10 at 00:07
  • 1
    Same here, I've currently writing a game backend in PHP (as a daemon). It listens/writes messages via a XMPP gateway. So far, it's works very well (not super fast, but can't beat PHP usability). – Kendall Hopkins Nov 24 '10 at 01:49
  • 1
    @Kendall: I don't think speed is really an issue. I've written socket daemons in Java as well, and PHP beats most of them speed-wise. First, there's no JVM to start. Second, PHP is very close to C raw sockets, unlike Java's abstract socket layer. – netcoder Nov 24 '10 at 02:40
  • I'll have to agree with you on the undefined running time; if it turns out my intended host won't allow server scripts run indefinately then PHP is going in the bin in favour of a different technology & host. – Toby Wilson Nov 24 '10 at 12:04
  • Someone suggested storing the game state in an SQL database, but I don't see how that would work as in game events would happen serverside, plus would probably have a large CPU overhead. – Toby Wilson Nov 24 '10 at 12:05
  • @netcoder: The less tightly controlled your environtment is, the more problems appear. I 've written a socket daemon to implement a very responsive chatroom (that was before AJAX) for a large open source project and believe me, with all the different configs on which people ran the thing and with all the different clients (in this case, browsers) and their quirks, it was a nightmare. – Jon Nov 24 '10 at 15:36
  • Accepted, because ditching PHP was the path I took. I can't see any good reason to use PHP for this as any hosts that won't allow Java services etc more than likely won't allow PHP scripts to execute for indefinite periods of time. I've successfully used Java to create the host process, and it was ultimately easy. – Toby Wilson Dec 07 '10 at 16:44
  • Totally agree with netcoder, especially nowadays PHP beats any WebSockets on any tech like Java for example, because it is now OPCache pre-compiled byte code, there is no JVM or other shitty over-engineering dust, and because of scalar types PHP7 became even faster then with pre OPCache integration, just in case out of the box. I've written my own library for WebSocket Server/Client, because there weren't enough for both - https://github.com/arthurkushman/php-wssc . It is just 1.2.5 version, maybe not fully production ready, but works well. There are others like Ratchet etc. – Arthur Kushman Jun 16 '16 at 08:53