Archived

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

Zern

Implementing a Message Handler

Recommended Posts

Hello, First before anyone decides to let me know this would be better off in another fourm, I figured it would be best to ask in the networking forum as others scanning these threads might've already had a similar problem with a server of their own. So onto the question. Today I finished creating my I/O Completion Port server. Now I've hit a bump as how to create a MessageHandler for the data sent from the clients. Right now, my messages are formatted into a packet which I can extract a MessageID and the data that goes along with it, among other things but this is only the relavent information atm. Only problem is I'm not sure how to go about creating this MessageHandler. As I figured I could hard code the M.Handler into the Class or just add in a function prototype and then create the function elsewhere ... however, I don't want to recompile my project everytime I add in a new MessageHandler to handle MessageID: XXXX. Also at the same time I need to handler to have access to functions/classes as well. For example: The message Handler gets a message of "1000" which means a client is disconnecting, I would need to remove the clients information from an internal list, ( function called from within this handler ) and then update others with a notification or what not about their friend logging off or what not ( just an example ). Keeping in mind I don't want to recompile the whole project anytime I add in a new event handler, any thoughts of a way to go about this? Even if it's just theory and no code, will be very greatful. Thank you for your time. ~ Edit: typo [edited by - Zern on January 22, 2003 12:05:47 AM]

Share this post


Link to post
Share on other sites
Sages,

Looks promising, thanks. However seems like a bit too much at the moment to create a COM|COM+ object as I would have to learn the specific details of COM ( which does not look fun ... however I am reading in case there are no other options =/ as I know of no others ).


Anyone else have any other ideas?


~

Share this post


Link to post
Share on other sites
I''m not sure if I follow you 100%, but from the sounds of it you should check out an article here on gamedev called "Why Pluggable Factories Rock My Multiplayer World", by Mason McCuskey(The guy who wrote the SFX Programming w/ DirectX book)

http://www.gamedev.net/reference/articles/article841.asp

I haven''t implemented what he''s talking about myself yet, but it looks like a really cool way to handle plug-n-play style things. Even if it doesn''t address what you''re wanting to do, I think it''s worth checking out!

-John

Share this post


Link to post
Share on other sites
I can only guess at why you want this, but here''s something we did at a place I use to work:
Define the messages externally in XML. When the server (or the client) starts, they load the XML files that describe the messages to your application. Your application basically keeps an array of message descriptions and matches up incoming messages appropriately.

Share this post


Link to post
Share on other sites
Teknofreek - Good article thanks for pointing that out.


Fingh - After re-reading my initial post, I realized it might be a bit confusing to understand as I was not in such a sane state of mind.


The problem that I believe I am going to face with my I/O completion port server is that I spawn threads to handle the messages dealing with the connections. While programming an external message handler for specific IDs at this point might not seem so reasonable, as I would only have a handful of messages to handle, but later on in my game development, I might decide to handle a message a bit differently.

Say for example right now, if my message handler switches off the ID passed to the handler, and gets a message ID of ''1000'' a user wants to connect, for now I can just accept the socket, user name( account name - whichever ), and allow connection to my server. Later down the road I wish to implement a look-up validation for the username and now a password (username (account name) and password would be stored in the data going into the message handler), I don''t see it as a good thing to recompile the whole program just to add in a new validation check. Or any other message I wish to update or add after I release the game to peers/friends/etc.

Why re-download a 5mb + exe just to have a new and updated message handler when I can (I hope ) just send a new .dll that has the updated ( or added ) message handler?


The XML external messages sound good for the server, but on the client end wouldn''t want the messages to be so easily mucked with and deformed from their original idea, hence the .dll comment.


Hopefully this clears up any confusion

Share this post


Link to post
Share on other sites
Basically you''re saying that you don''t want to have to crack the message handler function / method every time you change a message.

Let''s use your example of adding a password to the logon packet. Ok, so you get the packet in your message handler, switch on the message id, see it''s a logon packet and launch a thread to deal with that (a comment on that in a sec). That about right?

I don''t see why your message handler function would have to change there, just change your logon packet definition and the function that your launched thread executes to check the new password field of the packet.

As for starting new threads for every request, you''re going to find that it''s slow. Maybe not slow for a few people, but it''s going to be slow for any larger amount of players. Threads are too expensive to be starting every time you get a packet. You might want to look into thread pools.

Share this post


Link to post
Share on other sites
quote:
Original post by JonStelly
Basically you''re saying that you don''t want to have to crack the message handler function / method every time you change a message.



-Correct, however every time I change or add in a new message is the goal i''m trying to get to.


quote:

Let''s use your example of adding a password to the logon packet. Ok, so you get the packet in your message handler, switch on the message id, see it''s a logon packet and launch a thread to deal with that (a comment on that in a sec). That about right?

I don''t see why your message handler function would have to change there, just change your logon packet definition and the function that your launched thread executes to check the new password field of the packet.



-Again, yes. Would be simple to do that but as first responce, not only do I want to update/modify existing messages, but I want to handle new ones I add in later.


quote:

As for starting new threads for every request, you''re going to find that it''s slow. Maybe not slow for a few people, but it''s going to be slow for any larger amount of players. Threads are too expensive to be starting every time you get a packet. You might want to look into thread pools.



-Yes I know =). The server is scalable as per the examples in the Platform SDK. I only create ( numofProcessers * 2 ) threads that are alive the whole time and handle all events from/related to the sockets ( server or client ).


I believe I''m just making a problem more complex than needed.


Thanks for the input though.

Share this post


Link to post
Share on other sites
As Teknofreek said, give pluggable factories a whirl. The nice thing about them is that you just create a new message class and instantly you have another message type ready for use. Creating a new class is easy, you only have to copy and paste the original message and rewrite it to contain the message structure you need. Nice, Easy, and Fast.

Christian

Share this post


Link to post
Share on other sites
One of the things that I have been thinking about and am in the process of testing is that of using XML to define my messages (both client and server side) and then generate the message classes source code. I’m using a slightly modified pluggable factory technique and one of the problems that we experienced was that of keeping up with all the messages, we have many and are going to have even more when we are finished (if you are ever finished with an MMO). Another benefit from using XML to define the messages is that we can create documentation rather easily and keep everyone up to date with regards to messages that have been defined. As the messages are defined we also document what the message is meant to do... then as we run XML to code conversion we also create documenation that can be read from or intranet web site.

I originally had worked on code that let me declare all of my messages within a DLL and as the client or the server came up the DLL was dynamically loaded. Essentially it exported the class factory... long story short, I found this method to be too prohibitive in terms of keeping up with the messages that had been created and we all became confused rather quickly.

All in all the XML definition approach is looking like it’s going to be a winner... that is, until I find a better method.



Dave "Dak Lozar" Loeser

Share this post


Link to post
Share on other sites
I''d go for the plugable factories method too. YOu could do something like this:

  
// Client & Server Header


struct WorldState
{
vector<Client> vClients;
// Other world info here

};

class IMessageHandler
{
public:
virtual void Release() = 0;
virtual bool HandleMessage(int nMsg, void* pMsgData) = 0;
};

IMessageHandler* Create(WorldState* pState);
typedef IMessageHandler* (*pfnCreate)(WorldState* pState);


  
// DLL Header

class CMessageHandler : public IMessageHandler
{
public:
CMessageHandler(WorldState* pState) :m_pState(pState) {}
virtual void Release() {delete this;}
virtual bool HandleMessage(int nMsg, void* pMsgData);

protected:
WorldState* m_pState;
// Usual member variables etc here

};

// DLL Source

IMessageHandler* Create(WorldState* pState)
{
return new CMessageHandler(pState);
}

bool CMessageHandler::HandleMessage(int nMsg, void* pMsgData)
{
User* pUser;

switch(nMsg)
{
case 1000:
pUser = (SUser*)pMsgData;
m_pState->listOfUsers.Remove(pUser->ID);
return true;

default:
return false;
}
}



  
// In the servers init code (server has variable m_pHandler)

// IMessageHandler* m_pHandler;


HMODULE hMod = LoadLibrary("Messages.dll");
pfnCreate func = (pfnCreate)GetProcAddress("Create");
m_pHandler = func(m_pState);

// When server recieves a message:

m_pHandler->HandleHessage(int nMsg, void* pData);


I haven''t tested that code at all, its just as an example. So you pass the message handler a state block, which should have information about all the users in it along with other information. If you use e.g. a vector, you''ll have to be careful not to allocate memory in the DLL and free it in the EXE (or vice-versa).
When you recieve a message, you pass it along to your message handler in your DLL. Maybe abstract classes is overkill, you could just as well go and have a function, and a global for the world state.

HTH

Share this post


Link to post
Share on other sites