Advertisement

High level message processing

Started by October 28, 2004 07:24 AM
3 comments, last by Wiggy McShades 20 years, 3 months ago
Hi, I'm trying to decide what is the "best" way to going about high-level processing of messages I have recieved from the network. A little background first. The raw data received from the network is unpacked into an object of type X, these messages are then sent to a controller class which will process the message. For messages I have this class hierarcy (going from left to right). CMessage -> CMessageGroupA -> CSpecifcMessageInGroupA Each message is reponsible for packing and unpacking itself, an object factory is used to create the specific message based on a type identifier in the packet before the message data. Once I have a specific message, with all its data formmated etc. This message is passed into a controller object (it expects an object of type CMessage). I can then query the message to see what group it belongs to, and what the specific message type is. What I'm trying to decide is the best method for passing this message off to another object/method for processing. I have a few ideas and thoughts, each with their own advantages/disadvantages. I'm trying to make the code as maintainable as possible as more features will no doubt be added further down the line and I won't be around to implement them (but I have the catch 22 where I don't have a lot of time!) The most obvious option appears just to use an if..else if statement block to determine the message group, then use a switch case for each message type. But I really don't like that idea, a maintence nightmare! Currently I have a one of the messages group being handle with what is essintially the stategy pattern (but I need to first use an if statement to see if it is a message in a specific group), the other message group is just implement as a switch case (as its just control messages) The other idea I had was to employ the strategy pattern. Creating a stategy for each message type. However, the problem of class explosion (I need a class for every message type...) arises, and also these message will need access to other objects which contain state data (currently in the controller), but not every stategy will necessarily need access to all state data objects. I could just wrap up the state data objects into a container object, and pass a reference to this object to each strategy . Or, another thought I had was in the controller object, create a std::map with the key as the message type, and the value as a function pointer to a private method in the controller object. It would elimante the problem of passing the revelenat state data objects to each method, but it means further methods have to be added to the controller object, rather than creating a new object - which seems to be the better approach (according to these books I've been reading...)? I'm leaning towards the strategy pattern, but I'm wondering if I'm going about it wrong? Has anyone else employed the strategy pattern for processing messages? Is there a more suitable approach? Did any of this make any sense what so ever? :) Your thoughts would be greatly apprecaited.
personally i would go with using a std::map which mapped an ID to a function pointer. i don't know what the strategy pattern is, but using this method you only have to write a new function for each message, rather then a class. right now im just using a switch statement, but if i decide to switch, im going to use a map of ID->function pointers. then when you add a new message just write the function and register the pointer with the map. the other alternative is using the pluggable factory pattern, which i think is similar to what your calling the strategy pattern, in that you write a class for each message type. theres a good article that exaplins this, check out the articles section for an article called "why pluggable factories rock my multiplayer world"
FTA, my 2D futuristic action MMORPG
Advertisement
Message maps would be great here. I'm using an integer ID as a lookup key to functors with great success. You are able to swap and change message handlers at runtime with little or no trouble, plus you get a nice standardised message interface that is shared by all objects that are capable of handling a message. The idea was developed from an article in Game Programming Gems (3 or 4, I think) and Oluseyi's article and was expanded to use functors instead of function pointers. I now have a flexible system that's capable of being applied to entities, GUI elements and other internal game systems with no real hassle. It also allows you to inherit from classes and override messages if needed.
Messages are usually targeted TO something. That something might be "the chat system" or "the avatar instance on your machine" or something else, but there's always a target for the message.

One way of dealing with messaging at the high level is to view it simply as transport. Each message has a length, and a target, and that's it. The message then gets delivered to the indicated target as "incoming message from X, size Y, data bytes Z" and the target can deal with unpacking the message. Typically, most targets will use the same code to unpack messages, but custom (or third-party) objects/targets may use custom code.

The challenge then is to come up with a way to compactly represent message length (because you don't want to send 2 bytes of length for a 5-byte message), and a good representation of what your targets are. Hint: the first target you'll need is the "target manager" of the other side, as other targets will have to be introduced into the packet stream using messaging to that target manager.
enum Bool { True, False, FileNotFound };
Thanks, lots of food for thought.

I think I'm leaning towards a message map (std::map< MessageGroup, std::map< MessageType, pFunction > > kind of thing, the quickest to implement and a better than a switch case :)), whether I go for function pointers or functors I'm still mulling over.

Unfortantly I don't think I can go along your route hplus0603, although I will keep it in mind for the future. I thought making the messages reponsible for themselves (packing/unpacking etc) seemed appropriate and the rest of the system is designed around that. :|

While I was looking over some of your suggestions I cam across something called the "Command Pattern" which may or may not give me the kind of flexability that I want - I'm still trying to get to trips with the concepts :) It seens to be along the right lines though? The incoming network message is the "invoker", which will force the correct "reciever" to be called to handle the messsage.

This topic is closed to new replies.

Advertisement