I constantly encounter a situation where I have a set of messages that I need to send over a TCP / IP connection. I have never found a good solution for designing a message class. I would like to have a base message class in which all messages are received from it. Since each message will have different fields, this will allow me to access the fields through member variables or methods. Sort of...
class message_base { public: message_base(); virtual ~message_base(); unsigned int type; }; class message_control : public message_base { public: message_control(); virtual ~message_control(); unsigned int action; };
That way, I can create a message_control and access the member actions for assignment and reading. I can also pass messages without writing too much code.
The problem occurs when I need to send messages. If I redefine the operator <<and operator β then I can send messages one variable at a time. The problem with this solution is that with so many calls to transfer data, context switches will crack the processor. Also, the streaming statement ends the socket class, rather than in the message class, where I would prefer it to live.
socket& socket::operator<<(message_control& message) { sock << type; sock << action; }
If I pack the data in the buffer, I will leave C ++ and more in the C area and end up generously using pointers and the like. And, code modification is complex and error prone. And the streaming operator is still in the socket class, and not in the message class.
socket& socket::operator<<(message_control& message) { byte* buffer = new byte[sizeof(message.type) + sizeof(message.action)]; memcpy(buffer, message.type, sizeof(message.type)); memcpy(buffer + sizeof(message.type), message.action, sizeof(message.action)); sock.send(buffer); }
My last attempt used an intermediate class to handle packing and unpacking items in a buffer. Messages could implement the <operator and the β operator into a buffer class, and then the buffer class is sent to the socket. This works, but does not seem to be correct.
class socket { public: socket(); ~socket(); socket& operator<<(buffer& buff); }; class buffer { public: buffer() {m_buffer = new byte[initial_size];} ~buffer() {delete [] m_buffer;} buffer& operator<<(unsigned int value); private: byte* m_buffer; }; void message_control::serialize(buffer& buff) { buff << type; buff << action; }
I cannot help but feel that there is an elegant solution to this problem. I cannot find design patterns that match what I'm trying to execute. Has anyone experienced this problem and came up with a go-ahead design that doesn't make you feel like you're better off with good old pointers and an array of bytes?
Update
In my original post, I did not mention that most often I deal with very clear protocols. That's why I usually need to minimize my own solution and cannot use any of the wonderful toolkits available for messaging over a network connection.