Archived

This topic is now archived and is closed to further replies.

Xienen

Need some help with my Server Side App

Recommended Posts

Xienen    110
Alright, I''m making this game, Galaxy Soldiers, which is, like most new games now, an MMOARPG(Note the A for Action . Anyways, I am using Win32, DirectX, and Async WinMsg driven Winsock calls for the client side code, and now, I''m down to writing the server side code, and I have a few options, some obviously better than others: 1) Just write a Win32 app using Async WinMsg driven sockets, which could slow the app and obviously make it non-cross platform 2) Use non-blocking Winsock calls, which I am not really sure how to use, I just have a very basic understanding of them 3) Use blocking socks and have a multi-thread program, which I have no idea in the world how to do If you could, please explain why you chose the one you did, and if possible, explain somewhere to get some info on it, or explain some of it yourself so that I might be able to use that technique. (Note: I have used the tutorials from this site, but none of them applied well enough to my game for me to be able to use them) Any and All help is very much appreciated! Thank You. -= Xienen =- -= C++ Lead Programmer =- -= http://www.galaxysoldiers.net =-

Share this post


Link to post
Share on other sites
Synchronized    122
Here''s some food for thought:

Last week I talked with one of the programming leads of an upcoming massively multiplayer game. Specifically he was the head of the server team.

I have had some ideas how such a beast would be coded, but I''ve never heard how it was actually done until I talked to him.

Apparently, MMORPG servers are multithreaded apps that run on SMP machines. And the server actually makes multiple socket connections to the client.

A couple sockets would be TCP, which is used for all essential traffic (the information can not be lost, i.e. buying equipment from a store or making some other kind of transaction).

While the remaining sockets are UDP, which would be used for all non-critical information.

Could it be done in one thread of execution? Probably but the performance would suck when there are a large number of players.

If I was going to tackle a problem like this, I would definitely go multi-threaded.

Actually multi-threaded programming isn''t really that difficult there are alot of tutorials on-line and plenty of good books.

The challenge is just to make sure the various threads are sharing data in a safe and efficient way, with the major emphasis being on safe.

- Synchronized

Share this post


Link to post
Share on other sites
Synchronized    122
Their server code was optimized for SMP machines (i.e. more than one processor).

Real simple example. Your program has 4 threads and the machine your code is running on has 4 processors. Each thread will have it''s own processor.

Now multi-threaded apps can run on a single processor machine, each thread has to share that one cpu. So one thread will block and wait while another is running on the cpu.

But if you have more than one cpu, the threads can run in parallel, i.e. at the same time.

But in both the single processor and multi-processor case, the code MUST be "Thread-safe". This basically means that if a thread is manipulating some shared memory, another thread doesn''t come in and screw it up until the first is done.

- Synchronized

Share this post


Link to post
Share on other sites
Synchronized    122
Right, for the most part you should be fine.

But here is a very simple multi-threading example which will exemplify some of the bigger issues.

      

int globalData = 0;


void
f()
{
int i;
for (i = 0; i < 20; i++) {
globalData++;
}
}


void
g()
{
int i;
for (i = 0; i < 20; i++) {
globalData++;
}
}



So let's say you get some threads going and put both f and g in their own thread and start them both up so they're executing in parallel.

You would expect this code to put 40 into globalData. And you might run this once and 40 is in globalData. Then you run it again and 10 is in globalData. Then you run it again and 2 is in globalData.

Because the threads aren't checking to make sure they have sole access to the shared data, one clobbers what the other one does.

So let's say you have one world object and one thread which moves NPCs around and one thread listening for player movements.

If the NPC thread doesn't check to make sure it has sole access to the world object, the other thread could come in and clobber something the NPC thread is updating.

Just some things to keep in mind.

- Synchronized

Edited by - Synchronized on March 18, 2001 2:14:21 AM

Edited by - Synchronized on March 18, 2001 2:15:41 AM

Share this post


Link to post
Share on other sites
wazoo69    157
(win32) Can't you just use a CRITICAL_SECTION object???

ie. in Synchronized's sample code, define a variable as a
CRITICAL_SECTION (ie. CRITICAL_SECTION gdata)

Then before you access globaldata, call EnterCriticalSection(&gdata)

would this work??

Wazoo




Edited by - wazoo69 on March 18, 2001 1:29:56 PM

Share this post


Link to post
Share on other sites
Synchronized    122
Here, I updated my program for win32, not MFC (MFC has it's own worker thread classes, I'll list some books to consider at the end)

        
#include <windows.h>

#define _MT

#include <process.h>

#include <stdio.h>



#define THREAD_SAFE 1



#ifdef THREAD_SAFE

CRITICAL_SECTION cs;

#endif


INT globalData = 0;
INT done = 0;


VOID
fThread(PVOID pvoid)
{
int i,temp;


#ifdef THREAD_SAFE

EnterCriticalSection(&cs);

#endif


for (i = 0; i < 20; i++) {
temp = globalData;
Sleep(1);
globalData = temp+1;
}
done++;


#ifdef THREAD_SAFE

LeaveCriticalSection(&cs);

#endif


}


VOID
gThread(PVOID pvoid)
{
int i;


#ifdef THREAD_SAFE

EnterCriticalSection(&cs);

#endif


for (i = 0; i < 100; i++)
globalData++;

done++;


#ifdef THREAD_SAFE

LeaveCriticalSection(&cs);

#endif


}


INT
main(INT argc, CHAR **argv)
{


#ifdef THREAD_SAFE

InitializeCriticalSection(&cs);

#endif


_beginthread(fThread,0,NULL);
_beginthread(gThread,0,NULL);


while (done != 2);


printf("%d\n", globalData);


}


Here's is what is happening, main is starting up two threads, fThread and gThread, and then busy loops until both increment the done variable.

Now if you run the code with the #define left in you will always get 120 and the program will end.

However if you comment the #define out, the results will be unpredictable. The program could theoretically hang because of the way the main loop is busy waiting for done to be set to two. ( I don't feel like writing up a whole wait for thread to end piece of code ) But typically when I ran the program on my machine with #define commented out, it always ended with the result of 20.

Why was my result always 20, because as soon as fThread began it got the value of globalData and then slept for 1 millisecond (This would be equivalent to doing involved calculations on the the data before setting it). In that one millisecond, my machine is fast enough and had enough resources to spare so gThread started up did all of it's increments and was done before fThread got out of the sleep. You could throw in some printf's and see all of that happen in the code.

If you try this on your machine, the results may vary depending on the speed and what else you have running.

So that should start to give you an idea of what is going on with threads. Take note that CRITICAL_SECTION only works for threads, not processes. For processes to share memory you have to use a different idea. But if you're just writing one app which has numerous threads of execution then you can get away with CRITICAL_SECTIONS.

Now also take note, my program up there is pretty poorly coded. While being thread-safe it is not efficient at all. Code in the critical section should be done quickly, no waiting, get in and get out. If you start hanging around in critical areas you can starve other threads waiting for that particular resource.

Also, if you start playing around with more than one critical section and numerous threads you could find yourself in deadlock. For example say Thread A is in critical section 1 and wants to jump into critical section 2 for some value. However Thread B is in critical section 2 and wants to jump into critical section 1 for a value. BIG PROBLEM. Deadlock has occured and everything will hang.

You will encounter these and many more issues when you start to play around multi-threaded applications.

However, as I said before there is a ton of good material out there on writing multi-threaded applications. Usually books on operating systems in general have whole chapters devoted to multi-threaded / multi-process theory.

For specific platforms:

Win32:

"Programming Windows Fifth Edition" by Charles Petzold
"Win32 System Programming Second Edition" by Johnson M. Hard

MFC:

MFC is a different beast than Win32 for threads. Sure you can do the Win32 method, but if your doing Object Orientated programming, MFC provides Thread objects and whatnot to work with.

"Programming Windows with MFC Second Edition" by Jeff Prosise

General Unix:

"Unix Network Programming Volume 2: Interprocess Communications Second Edition" by W. Richard Stevens (I've got to give out props to my boy Stevens, he was the man when it came to Unix programming in general).

Actually for you since you're doing Network programming and threading, all of Stevens Network Programming books might be a wise investment. Even though it's Unix, the concepts are very general.

- Synchronized

Edited by - Synchronized on March 18, 2001 12:25:14 AM

Share this post


Link to post
Share on other sites