Jump to content
  • Advertisement
Sign in to follow this  

Design Question

This topic is 3050 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

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
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_USER 3

Then in my client I have a pretty extensive if block

if(msgType == USER_JOINED) {
} else if(msgType == USER_LEAVE) {
} 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
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
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
Sign in to follow this  

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!