Sign in to follow this  

Dealing with multi-player threads...

This topic is 4339 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

When I first started designing the classes and such for a MUD I was under the impression it would be easiest to have threads for each player, and each thread await input from the player, etc. Reading around these boards however, some people were mentioning that it isn't a good idea to do that. My question is, what are some methods (not methods in programming, just ways of doing it, haha) of dealing with user input? I've come up with a few ideas but it seems like they leave room for abuse if someone used a hacked client.

Share this post


Link to post
Share on other sites
Have you taken a peek at how some other MUDs such as (CircleMud) have coded networking? The client to connect to these would usually be a simple Telnet terminal, so hacking it with that would be pretty tough.

I had thought they used threading (or forking) but it turns out they just use select() to determine who has sent data.

Anyway, if you have threading and the connection is blocked waiting for data, then it wouldn't be able to send out new information to the player, so that is one of the reasons I probably wouldn't choose that method of implementation.

Share this post


Link to post
Share on other sites
I have it worked out so I can send data to the user whenever, and accept data from the user whenever, but are there any negative effects from each user having their own thread?

Share this post


Link to post
Share on other sites
Quote:
Original post by Kraiger
I have it worked out so I can send data to the user whenever, and accept data from the user whenever, but are there any negative effects from each user having their own thread?


There aren't any EXTRA negative effects. You'll still have to worry about the standard negative effects of threading, like tough debugging, simultaneous access issues, and confusing race conditions, on top of whatever overhead you might have for thread switching.

Share this post


Link to post
Share on other sites
There isn't really much advantage to be had by having one thread per client. Programming certain logic might be easier, because rather than having a state machine per client, you just use the program counter. Consider:


// pseudo-code
// socket has been accepted
while (username is not acceptable) {
prompt for username;
check username for validity;
}
while (password is incorrect) {
prompt for password;
check password for validity;
}
logon user;
while (player is still connected) {
process command;
}
close socket;
// end of thread


However, this is likely to be outweighed by the more complex programming for the rest of the system, i.e. ensuring synchronised access to shared stuff, making sure threads are started / stopped cleanly.

Mark

Share this post


Link to post
Share on other sites
That code structure can be written for each client using fibers (a k a "cooperative threads" or "coroutines"). Fibers are better than regular threads in that they don't require explicit locking for many cases (as they all execute within a single pre-emptive thread context).

You still have the cost of a fiber stack per fiber (just like the cost of a thread stack per thread), though, which may make them more expensive than you'd like for a system with many clients.

Share this post


Link to post
Share on other sites
Hello, kind of new here. But thought I might put in my own 2 cents real quick.

As far as stack size goes, can't you set this so as not to take up too much space in memory? Not more than you need at least.

I've been writing some netowrk code for a small, "Battlefield"-type, game engine, and ( don't laugh ) went the multi-threaded route.

I went with hooking __event() functions from each thread to an event handler to funnel them into one area. From what I've read, it's thread safe, but books can be deceiving sometimes.

The way it is going right now, it looks like this will be a global message handler to modify game data. The main thread would also send messages here to handle game data modifications.

The only good thing I see about this so far, is that I can add in networking, physics, AI, input, etc modularly. The only worry now is about accessing data in a safe fashion. I may have to run the main function as a modData/getData function.

Anyhow, I'm just a home-brew hacker, so don't take anything I said with a grain of salt.

Share this post


Link to post
Share on other sites
having developed an industrial strength vpn I can tell you that a good solution is to have a group of threads, and assign pieces of work to a thread (ie dispatcher),..when the piece of work is complete return the thread to the free thread pool.

a common thing i see these forums is people wanting to have one thread for receiving data on each connection. This is a big no no. When some data is indicated to be received, task it into a queue and have a free thread take care of the work.

multithreaded coding is difficult to develop and even more difficult to maintain, deadlocks are common mistakes, but with multicore cpus out there and growing you will all have to rethink how we develop software.

all the best.
Cubex

Share this post


Link to post
Share on other sites
@Cubex: Interesting!

The typical problem with a distributed simulation (i e, most physically based games) is that everybody wants to mutate the same state database (i e, the game world), so you end up serializing everybody on "the world lock" anyway. Thus, trying to offload networking to more than one other thread just won't give you anything -- and trying to do event dispatching from multiple threads just won't be a win.

Designing compelling, server-authentic, physically based game mechanics that don't require a central datastore (at least per "zone" or "area") and also doesn't run the risk of deadlocks is something that I believe hasn't yet been done. I'd love to see the description of such mechanics if someone has it, though!

In what way is your VPN solution similar to a distributed simulation like this? Do you have some central datastore that all the connections need to access for each packet?

Share this post


Link to post
Share on other sites
@hplus0603:

i think you are skillful in mmog server program, and would you tell me how many players a single-threaded server can process without obviouse delay(generic sever computer and do not take into account the bandwidth).

Share this post


Link to post
Share on other sites
@hplus0603:

Perhaps I misread the question, my understanding was the question was referring to server design of the MUD. Performance is a key issue here for a scalable MUD server design. Distributing the same state data to each client does not impact how to handle incoming data from multiple sockets. Different data will have different priority for game state, not all data is essential when tranmitting to each client. eg. player position.

Using a dispatcher frees the system to handle multiple asynchronous requests and scales well with multi-cpu.

Regards
Cubex

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
the only problem with a thread per user is there is a max of like 200ish threads on windows, so a better approach would be like a thread per 100 users, useing select within the threads to check for data on each threads designated 100 users

Share this post


Link to post
Share on other sites
When considering the scalability of serving a text-based multiplayer game, here are the major steps I would be concerned about:

1) Reading input from players.
2) Mutating the world state based on that input.
3) Sending out the observed changes to the world to each observing player.

I had a long rant about how the serialization cost of doing 2) in each of the threads of a multi-threaded server may actually cost more than it gains in reducing pressure of 1); in the end I added more links and put it up on my web site instead.

[Edited by - hplus0603 on January 28, 2006 4:22:02 PM]

Share this post


Link to post
Share on other sites
Quote:
Step 3) is never much of a scalability concern, because you can easily fit all the data you need to send to a client in the outgoing TCP buffer, and the sending of that data will be done by the kernel in response to a network adapter interrupt, not in response to any specific user thread. If the buffer fills up, you either drop data, or disconnect the user (those are really the only two options).


This is what I've been thinking about - what to do if a particular client is slow to receive data. For some types of games, there may be a more tolerant approach that allows such clients to stay connected.

Approach 1: Resize the buffering in the game server for that client. This would allow a client to stay connected during a momentary 'hiccup'. The downside is that the client can get his butt kicked by enemies before being able to make the first counter-attack. But that's why we have auto-attack in MMOs.

Approach 2: Slow down that game. Once again going with the MMO example which is typically fast-turn-based (for example one turn per second), if a small number of clients is slow to receive data from the server, the game can slow itself down to allow all clients to receive all the pending data. The downside of course is that many players suffer for one player's skinny pipe.

Anyway, on a typical server box (or any box for that matter), how much data can an outgoing TCP buffer hold? I'm assuming each client connection has its own outgoing TCP buffer.

Share this post


Link to post
Share on other sites
You should make thread pools. For instance make a thread that handles 20-50 users at a time. This will offer very low performance hit... and if you are on really outdated hardware maybe limit it to 10 connections/users per thread. This should be done at the socket/connection level in your server though, that way you can refer to connections easily. You should also be keeping a central list (vector if you prefer that term) or array of users for looking up other user's information.

If you would like more information PM me I will give you some code samples.

Share this post


Link to post
Share on other sites
@wyled: Whether to create thread pools (and thus use IOCP on Windows) is basically what this thread is about. You didn't actually read the article, did you?

@SteveTaylor: You can set the TCP buffering size on your own. Check out the SO_RCVBUF and SO_SNDBUF socket options. The defaults vary based on OS, OS version, and sometimes tuning variables. There may also be a system-wide limit on the amount of buffering, in addition to the per-socket limit; if so, the system might (or might not) have some system-specific way of configuring that limit.

I don't like the idea of trying to dynamically re-configure the buffer size. What if all clients go slow at once? That could easily happen if there's some partial (or full) service outage at your ISP. If you want to be robust, you have to be prepared to deal with that case, so set the buffers to the maximum size you're prepared to deal with up front.

Also note that if the buffer is filling up, it MAY be a hiccup, or it MAY be that you're actually sending too much data for the client's connection. What do you do then? He just can't keep up. I'd drop him (or her) if the buffer actually fills up -- the buffer should be significantly bigger than what you would need to write during a single pulse, so if you can't drain enough data during a few pulses, then you just can't keep up.

Now, for a text-based MUD, running out of space in the TCP buffer is quite unlikely to actually happen. Unless you have lots of users who like to paste novels into their chat lines :-)

Share this post


Link to post
Share on other sites

This topic is 4339 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this