Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm working on a game where players connect to a game server and to a lobby to play a card game against others.

I have a pretty good idea how to code it and such, I'm just not sure regarding a few details.

The game will have multiple lobbies, so although all lobbies run from the same exe and server, the player is bound to a specific lobby.

When the player connects to a lobby, I need to:

-Tell all the players in the lobby about it

-Send that player their list of online friends

-Send that player the list of all players online (in that lobby)

-Send that player the list of all current games and who's playing in each game (This info is all displayed in a ListBox).

Once that player is connected, I need to ensure that while they were receiving that information, if anyone else joined, or any games ended / started etc, that they dont miss any of those messages.

In a single-threaded world, I'd find this pretty simple, but I fear this would mean horrible lag or something every time someone joins. (I could be wrong though).

I'm wondering in general what would be an ideal way to tackle this problem such that it minimizes slow downs for other players. What I mean is, the whole server should not halt for 3 seconds while a user joins.

I guess with a message system it is not too bad since the server can get work done while it waits for the reply. But how robust is such a message system? Login / Authentication be on its own thread, and then it sends a message to the lobby thread which would handle any lobby related transactions. Should each game be in its own thread or should I loop through each active game and process them iteratively?

In addition, each game has a private chat between the 4 players. Each lobby has a chat that only players in the lobby and not in a game can see.

I was also wondering if I should incrementally update the lobby for players in a game or send them a full update when they finish a game.

If anyone could lead me in the right direction for any or all of these questions I would really appreciate it.

I'm coding this in C++ with a network library called ENet, but I'm not looking for any code, but maybe psudocode.

Thanks

share|improve this question
1  
While running each game server as it's own server might seem like overkill, it could make managing this alot easier, and avoid stalling anyone's game. You could have one master server, game servers connect to this server and announce their lobby there. Clients would connect to this master server as well and receive the list of lobbies, players, whatever you need. Once you choose a lobby, you connect to the game server it's actually running on, which could publish changes to the connected players as they happen, or at set intervals, on request, or any combination. –  melak47 May 8 '12 at 10:04
    
@melak47 Would you suggest that every game be in its own thread? –  Milo May 8 '12 at 11:19
    
I was actually thinking separate processes. It looks like you could separate the responsibilities into client, master server and game server neatly, it would take only a slight amount more networking for the game server - master server communication, but in return you wouldn't have to worry about threading/synchronization/scheduling, and it would allow you to physically separate master server and game servers. This may or may not be very bad practice, but from my PoV it seemed like a neat idea to separate separate processes –  melak47 May 8 '12 at 11:28
    
This would mean around 50 processes per lobby since each lobby supports up to 50 games. –  Milo May 8 '12 at 11:39
1  
I guess that's not so neat then. Threading each game sounds good in principle, but I can't imagine the card game being all that cpu intensive on the server side so you could probably get away with threading each lobby and simply iterating through the games. Depending on the type of game I also don't think events are going to happen at a very fast pace, you should have enough time just waiting for the clients to display animations, then make their moves each step of the game, to send whatever messages you need –  melak47 May 8 '12 at 11:49
show 2 more comments

1 Answer

up vote 5 down vote accepted
+400

You've got a whole lot of meandering questions there, so here's a huge meandering response :)

Network traffic, queueing, and consistency

A good server needs to be event-driven and asynchronous. I'll give an example.

You say "When the player connects to a lobby, I need to: -Tell all the players in the lobby about it". That's right, you totally do! And a first attempt at writing the code would simply send all the players the necessary information. This runs into obvious problems - if one player has a very slow connection, then you'll be sitting there waiting for that one player's modem to finally send the previous packet so you can send the next packet. Not ideal.

What you really want to do is queue up messages for every player, then, when the server has a little spare time, send as much of that queued data as you can. There are plenty of ways, depending on your OS, to just send "as much as possible", then keep the rest around in the buffer until the next time you need to send data out.

This introduces its own set of problems. For example, if someone starts piling up unsent data, they'll slowly get further and further behind realtime. There's not much you can do about this besides make your network protocol use fewer bytes, but at least it won't hurt the other players. Worse, a sufficiently large player buffer could cause your server to run out of RAM. Realistically, in this case, you just disconnect the player if they fall too far behind (measured in either seconds or bytes - measure both and have a kill threshold for each.)

Once you've done this, the problems with lost messages go away. A player logs on, you send them a "logon" message. Then you send incremental updates as people log on and off and chat. You don't need to know how much of the logon message the player has seen - all the incremental messages are queued and will also show up. The player may get a big blob of updates immediately after the logon message, sure, but that's okay! Everything will still be consistent.

Scalability

Note that this can all be done singlethreaded. You'll be using something like select() or epoll() in order to make it efficient. Multithreading is a horrible tangle that you may want to avoid unless you need the efficiency - consider it a dangerous speed hack. For a card game, you won't need it. (This advice may be incorrect if you have a million users.)

It may be reasonable to spin up multiple servers, however. This can be spread out among multiple physical computers or left on just one computer. If you have dualcore computers, it may be perfectly reasonable to run two servers on one computer just so you can avoid the morass of multithreading. You want to divide your servers by role, you don't want monolithic servers that do everything. A reasonable division in your case, and note this is almost certainly enormous overkill, don't worry about it for a long time:

  • "user" servers that handle communication with the player, network buffering, and player settings and stats.
  • "lobby" servers that handle your lobby chatting and manage the creation of new games.
  • "game" servers that handle the details of each game.

Each of these servers will handle a large number of actual elements - I'm not saying you run a game server for each game, I'm saying you run a game server for each thousand games. But if you need to expand to the multiserver world - again, you almost certainly don't - keeping your servers narrow-purpose will make your life a whole lot easier.

Protocol

As for questions like this:

I was also wondering if I should incrementally update the lobby for players in a game or send them a full update when they finish a game.

you've got two questions you need to answer.

First, do you intend for players to be able to see the lobby while they're playing a game? If so, you'll obviously need to incrementally update.

Second, do you expect incremental lobby update bandwidth will be excessive? If so, then you'll obviously want to wait to update.

Personally, I think this question just isn't an important one. The bandwidth is likely irrelevant. The answer really comes down to "do what is easiest to code", IMHO. But in general, you'll have to weigh server load vs. player experience.

If you've got any further questions, toss me a comment and I'll make things clearer as needed.

share|improve this answer
    
+1 if not just for starting "event-driven and asynchronous" and then for a heroic effort at trying to condense an entire class of Server 101 into one message =) –  Patrick Hughes May 12 '12 at 15:45
    
Hi, thanks for that awesome answer! In terms of the queuing, I think ENet has some sort of dynamic throttling algorithm. Also, the players will never need to access the lobby while in game, but if I already have to implement incremental, I may as well stick with it. I was thinking of having: A master server which will pretty much just authenticate and show the list of lobbies. Then the player chooses a lobby and connects to it. This keeps it scalable and simple. I was wondering what kind of problems Id run into with 1 thread for games in the lobby. –  Milo May 13 '12 at 17:18
    
Yeah, that all seems reasonable to me. If you'll already need to get incremental updates working, which you will, there's no reason to add an entire second update system without proving it necessary. And one thread per server, handling many games simultaneously, shouldn't present any problems - that's how most heavyweight servers work, from webservers to AAA MMORPG servers. Obviously you'll want to make sure the process doesn't crash :V but that just comes with the territory. –  ZorbaTHut May 13 '12 at 20:43
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.