Sign in to follow this  
reapz

Design Question

Recommended Posts

reapz    100
I am about to start a chat program (will be in Winsock), for a uni assignment and am currently thinking design. The client will be in Ogre using CEGUI, and we will be doing a networked environment for the next project, so I'd like to get a good messaging system setup now. For example, if a user joins the server, the server can send a USER_JOINED message to all the clients so they can update their lists etc. This is just an example but the main question is how would one structure this elegantly? I have a couple of idea but none seem very elegant: - Could send the type before the object and then use a switch statement or something based on this cast to that message type. - Implement a base message class that has a message type and a getData() function or something. Each base class would implement this getData function which could return a string of data to be used or parsed? (Very bad imo) - Could have one type of message that has the sender id and a string of text that could be parsed and used however. I cannot think of a more elegant way to do this, would be good to hear some opinions from people who have been down this path. [Edited by - reapz on March 10, 2010 8:17:03 PM]

Share this post


Link to post
Share on other sites
flodihn    281
I can reveal how I solved this in my server/client architecture.

I took a pretty simple path (KISS, Keep It Simple, Stupid).
For every type of message I have an id, something like this:


#define USER_JOINED 0
#define USER_LEAVE 1
#define USER_TO_CHANNEL 2
#define USER_TO_USER 3



Then in my client I have a pretty extensive if block

if(msgType == USER_JOINED) {
do_that();
} else if(msgType == USER_LEAVE) {
do_this();
} else {
debug("Unkown event %i", msgType);
}



I am sure there are much more "elegant" and more complex solutions to this. So far it this system has worked very well for me.
I am building an MMO which is quite complex and includes chat systems, if you going to stick with a chat-system only, I doubt you will gain much for doing a more complex system.

Share this post


Link to post
Share on other sites
Noggs    141
To avoid having to maintain a switch statement as well as a list of message IDs I use a registration method with callbacks to handle messages. A boiled down version might look like this:


typedef void (*MessageHandler)(Message*);
void HandleJoinReqMsg(Message* );
void HandleJoinMsg(Message* );

typedef unsigned long MessageID;

MessageID RegisterMessageType(const char* debugName, MessageHandler hnd );

MessageID USER_JOIN_REQ = RegisterMessageType("USER_JOIN_REQ", &HandleJoinReqMsg);
MessageID USER_JOINED = RegisterMessageType("USER_JOINED", &HandleJoinMsg);



Whenever a message arrives you should search through the list of registered message handlers and get a pointer to a function to handle that message type. Registering a new message type is as simple as creating a function to handle it and registering it.

You do need to ensure that the messages are registered in the same order on both the server and the client though. Alternatively you could handle the IDs by hand and _tell_ RegisterMessageType which ID to associate which message handler with.

Share this post


Link to post
Share on other sites
hplus0603    11347
It's common to structure a network protocol such that it contains a type code and length parameter, followed by that much of payload. Sometimes, there's also a "destination" in the header, and at other times, "destination" is part of the payload data when needed.

Thus, you end up with two layers of serialization:

struct {
unsigned short type;
unsigned short size;
unsigned char data[]; // size bytes of data
};


The nice thing about this approach is that it's easy to skip type codes you don't know about, or don't care about. It also doubles as a convenient packet delineation mechanism for packet-based protocols over a TCP stream.

To dispatch the packet "type" to the right handler, either use a fixed-size array (and do range checking on the 'type' value!) or use a registry hash table where type codes are tied to dispatching functors.

Some links that may be helpful:
Network API structure: http://www.enchantedage.com/node/167
Network buffer class: http://www.enchantedage.com/node/18
C++ reflection, applicable to marshaling: http://www.enchantedage.com/cpp-reflection

Share this post


Link to post
Share on other sites

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