Streaming over TCP / IP

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.

+4
source share
1 answer

β€œThe problem with this solution is that with so many data calls, context switches will crack the processor. In addition, the streaming operator ends the socket class, not the message class, where I would prefer it to live.”

The solution to the second problem is to define operator<< as a non-member function in the namespace that contains the message class, and not as a member function of the socket class. ADL will find it.

The solution to the first problem is to buffer the data in your process, and then clear it at the end of each message. If Nagle buffering does not prevent context switching, then you can achieve this by messing with the socket, I don't know. However, you can certainly make each message before sending more than C ++ - ish. Replace:

 sock << type; sock << action; 

with:

 stringstream ss; ss << type; ss << action; sock << ss.str(); 
+1
source

All Articles