Advertisement

TCP & UDP server implementation question

Started by February 26, 2004 11:54 AM
8 comments, last by Shadowed 20 years, 11 months ago
Hello. I actually have more than one question and I don''t know whether I should post separate topics or write all in one, so since they all are about implementing a server I''ll keep it simple - all here. Brief info first, the server should deal with both TCP and UDP protocols: TCP for transferring large amounts of data, files and pre-loading caching, UDP for game-state-updates and small in-game information chunks which are critical on delivery speed and size. It should run on Windows/Winsock. The first question is: what''s a better idea - to have one program running which deals with both UDP and TCP parts or to keep them separate? The second question is about the TCP server: it should support multiple [>1000] connections at once. What''s the best way to organize the connections part - using Windows asynchronous sockets or 1-thread-per-connection style or anything else I may not be informed about? Thanks a lot for help.. -- I hate you.
--I hate you.
As for the UDP & TCP in the same program... what do you mean with a program? If you mean like seperate processes... no... that''s not nescesary.
My module on my website (www.structweb.com ... module is buggy, a new version is on its way, but it serves its purpose as example) supports both UDP and TCP by deriving their specialised functionality from a base class. Both have the same interface, but simply implement different protocols.
If you would like both UDP and TCP functionality, you simply make two instances of the module, one derived from the UDP module, and one from the TCP module. It has no effect on the operation of your program.


And your second question, 1 thread per connection.... 1000+ threads and sockets... I''m not too sure your system would be happy about that, though I''ve never really done a load test with threads and sockets so I can''t say if 1000 threads is significant, but I guess it would have a real impact.
With an FD_SET you can perform a check on how many of the sockets inside the FD_SET have data to read. Then you loop through all socks and read your data.
The method including source can be found on www.gametutorials.com
More specifically: http://www.gametutorials.com/Tutorials/Networking/Networking_Pg1.htm :: The last tut is especially interresting in your case.
Module provided earlier also uses the same method for the TCP module.
STOP THE PLANET!! I WANT TO GET OFF!!
Advertisement
Thanks a lot for the response and the answers.

So if I don''t actually run two different processes for UDP & TCP, for downloading files to user hosts and sending away game state updates, and if I don''t use threads per connection, but handling all that in one process, then I feel like pretty lost in actual server logics.. If you could help me with a pseudocode or a flowchart, that would be great.. As far as I understand the things, it has to be something like this:

CUDPServerSocket.init()
CTCPServerSocket.init()

while(not asked to quit)
{
if (CUDPServerSocket.NewConnection())
then create thread and forget

if (CTCPServerSocket.NewConnection())
then create another thread and forget
}


am I going the right way?
--I hate you.
Yes, you're on the right way... in my opinion.

The UDP and TCP data reception runs in its own thread.
So you have your main loop
Your UDP data reception thread
and your TCP data reception thread (Plus perhaps another thread for handling incomming TCP connections).


Threads of your application:

-- main loop thread
* Game logic, drawing to the screen, etc etc

-- TCP connection acceptance thread
* If you started a server this will handle new clients connecting to the application. (See tutorial in previous post)

-- TCP data thread
* Loop through all sockets and read their data
* handle the data in this same thread, for example write it to a file

-- UDP data thread
* Read from your one UDP socket
* handle incoming data in this thread, for example update the gamestate

OK, so, your UDP thread updates your gamestate constantly... and your main loop reads your gamestate constantly, at the same time.

That's how I would do it. Making two executables for TCP and UDP functionality is not nescesary. It is a possible solution though if you might want to run each one seperate without relying on the other. For example if you want a user to only download files, and not play the game. Or vice versa. But if he has to download before he can even connect to a game, then it's handy to have both in the same application, else the user has to switch between programs before he can actually play.
It's one of those design choices. Do you, or the user get anything out of it making two seperate executables?

I hope this answers a few things... again, your solution, and my solution are both possible, probably equally good if you implement it well.

[edited by - Structural on February 27, 2004 2:33:43 AM]
STOP THE PLANET!! I WANT TO GET OFF!!
You might want to look into IOCP

I know, it can be a pain, but it pays off when serving large numbers of users.

IOCP Referances that I have found helpful:
http://www.gamedev.net/community/forums/topic.asp?topic_id=187992
http://www.gamedev.net/community/forums/topic.asp?whichpage=1&pagesize=20&topic_id=204416
http://www.gamedev.net/community/forums/topic.asp?topic_id=158626
http://www.gamedev.net/community/forums/topic.asp?topic_id=199612 <-- Good resource for the pro's and con's
http://www.faqs.org/rfcs/rfc768.html
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndllpro/html/msdn_servrapp.asp <-- Great article, very sound, logical explaination of IOCP structure (little source code though )
http://www.gamedev.net/community/forums/topic.asp?topic_id=74732 <-- Clears up some confussion regarding IOCP's relationship to Overlapped I/O
http://support.microsoft.com/default.aspx?scid=kb;en-us;192800 <-- A MUST READ
http://www.mvps.org/win32/network/sockhim.html <-- Sample source code using TCP / IP with IOCP

[/bookmark_dump_file]



And, might I point out, that doing a full blown MMORPG by yourself (or even with a small team) is about friggin' imposible unless you really know your stuff. You might try implementing a simplistic MMOG demo package with features such as player accounts, login / validation, walking, chatting, and perhaps area transitions to familiarize yourself with just what is involved.

Please keep in mind that the above comment outright assumes you are making a MMOG. I feel it is fairly safe to assume this, given your specifications.

Tell him about the twinky...

[edited by - QBRADQ on February 27, 2004 6:22:56 AM]
Tell him about the twinky...
OK, I got the point.. but some kind of misunderstanding - what ''drawing on the screen'' do you mean? We''re talking about the server application, so I didn''t get that part. I will also have collision detection and user actions being validated server side, what about a thread for that?

Seems like the topic is going pretty interesting, maybe it will help others as well later.
--I hate you.
Advertisement
quote:
Original post by QBRADQ
And, might I point out, that doing a full blown MMORPG by yourself (or even with a small team) is about frigging imposible unless you really know your stuff. You might try implementing a simplistic MMOG demo package with features such as player accounts, login / validation, walking, chatting, and perhaps area transitions to familiarize yourself with just what is involved.



Yes I''m doing a full blown MMORPG with a small team, and I think I am capable of doing the impossible. In fact I wasn''t a big expert of sockets programming, so the client part went really easy and I kind of underestimated the server part [feeling miserable because of that now, uh], but a lot has already been done and that includes not only programming but the game design and art stuff, so I really have no choice except pushing myself beyond the impossible to make the server either I won''t be able to look straight into the eyes of the rest members of my team. I''ll make it, whatever it takes.

So thanks a lot for any assistance

And the bookmarks were great, too, you really helped me to figure out a lot.

--
I hate you.
--I hate you.
quote:
Original post by Shadowed
OK, I got the point.. but some kind of misunderstanding - what 'drawing on the screen' do you mean? We're talking about the server application, so I didn't get that part. I will also have collision detection and user actions being validated server side, what about a thread for that?

Seems like the topic is going pretty interesting, maybe it will help others as well later.


When you are playing a single player game, you only have one thread... your main, that might look a bit like this:

int main()
{
createWindow();
initPlayworld();
while (true)
{
updatePhysics();
updateAI();
drawScreen();
}
}

You server looks like this, you have to create those extra threads first.

int main()
{
startTCPDataThread();
startTCPConnectionThread();
startUDPDataThread();
initPlayworld();
while (true)
{
updatePhysics();
updateAI();
// drawScreen(); We don't use this in our server
sendUpdatedGameStateToClients();
}
}

Your TCP and UDP threads fill your gamestate with fresh data... Or save player button presses in a buffer.
At that very same moment your updatePhysics() reads from that buffer where the keypresses are stored in and updates the gamestate accordingly.

So your updatePhysics() might look like this for the server:

updatePhysics()
{
buffer = getUDPKeyBuffer();

for(each key in buffer)
{
player = getPlayerBelongingTo(buffer, key);
updateGameState(player,key); //if key == forward, move player forward, etc etc
}
}


And your UDPThread

UDPDataThread()
{
while (true)
{
buffer = recv(stuffFromSocket);
key = getKeyPressFromBuffer(buffer);
player = getPlayerIdFromBuffer(buffer);
TossStuffIntoUDPKeyBuffer(key, player);
}
}

That's how I see it... I just pulled this right out of my sleeve, but that looks like one way to do it.

[edited by - Structural on February 27, 2004 7:13:42 AM]
STOP THE PLANET!! I WANT TO GET OFF!!
One little addition:
Basically you treat your network clients, as if they were local players... your local player sends a key to your gamestate, and the gamestate then handles the rest...
On the server, the gamestate logic is IDENTICAL, except your connect x local players who send keys to the gamestate. The gamestate knows nothing about the network... it just sees a lot of local players sending keys.


The crazy thing is that you can design your application exactly like that. All players, AI, net and local, send keys to your gamestate.
AI, local and network player all send keys... AI looks at its current state, and says: NOW I MOVE FORWARD... I PRESS THE FORWARD KEY.
Local player reads input from the keyboard...
Network player, read keypresses from the network...

class Player { int init(); virtual int update(); }

class AIPlayer : public Player {
int update() {
key = deviseStrategy();
GameState:: PressKey(key,myPlayerId);
}
class NetPlayer : public Player {
int update() {
key = getNetWorkKey();
GameState:: PressKey(key,myPlayerId);
}

class HumanPlayer : public Player {
int update() {
key = getKeyBoardState();
GameState:: PressKey(key,myPlayerId);
}


GameState:: PressKey(int key, int playerId)
{
Player* player = getPlayerById(playerId);
player->doKeyAction(key);
}




So, in short, program your gamestate like it only has to support players... nothing specific... in the end your AI, network and local players all use the same interface.
And if you want to add a new sort of player later... an AlienPlayer, you only have to make a new derived class. You don't have to do anything with your gamestate... neat huh...

But this goes much further than the topic is about...

[edited by - Structural on February 27, 2004 7:27:52 AM]
STOP THE PLANET!! I WANT TO GET OFF!!
I wish you the best of luck. It is possible, it''s just going to take a very long time

Also, you might want to check out this article about your thread question, just to give you a hint about using threads:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndllpro/html/msdn_threadli.asp

Particularly this exerpt:

quote:

Unless the application executes on a multiprocessor machine (in which subcomputations can truly execute in parallel), CPU-bound computations cannot possibly execute faster in multiple threads than in a single thread. This is because the single CPU must still execute all computations, be it in little pieces (in the multithreaded case) or in big chunks (as is the case when the computations are executed one after another in the same thread). As a rule, a given set of computations, when executed in multiple threads, will typically finish later than the same set of computations executed sequentially because there is an overhead incurred in creating the threads and switching the CPU between threads.

Tell him about the twinky...

This topic is closed to new replies.

Advertisement