我发现自己经常遇到一种情况,我需要通过TCP / IP连接发送一组消息。我从来没有找到一个很好的解决方案来设计消息类。我想有一个消息基类,其中所有消息都来自它。由于每条消息都有不同的字段,因此我可以通过成员变量或方法访问这些字段。有点像...
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;
};
这样我就可以创建一个message_control并访问action成员来分配和读取。我也可以在不写太多代码的情况下传递消息。
当我需要发送消息时出现问题。如果我覆盖运算符<<和运算符>>然后我可以一次发送一个变量的消息。该解决方案的问题在于,由于发送数据的调用次数过多,上下文切换将会淹没处理器。此外,流操作符结束了套接字类,而不是在我希望它存在的消息类中。
socket& socket::operator<<(message_control& message)
{
sock << type;
sock << action;
}
如果我将数据打包到缓冲区中,我就会远离C ++,进入C领域,并发现自己大量使用指针等。而且,修改代码很困难且容易出错。并且,流操作符仍然在套接字类中,而不是消息类。
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);
}
我的上一次尝试使用了一个中间类来处理打包和解压缩缓冲区中的成员。消息可以实现运算符&lt;&lt;和运算符&gt;&gt;到缓冲区类,然后将缓冲区类发送到套接字。这有效,但感觉不对。
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;
}
我不禁觉得这个问题有一个优雅的解决方案。我找不到任何符合我要完成的设计模式。有没有人遇到过这个问题,并提出了一个不会让你觉得你用旧的指针和一个字节数组会更好的设计?
更新
我在原帖中没有提到我经常处理很好的定义线协议。这就是为什么我通常需要推出自己的解决方案,而不能使用任何可用于通过网络连接进行消息传递的精彩工具包。
答案 0 :(得分:1)
“该解决方案的问题在于,如此多的调用发送数据,上下文切换将砰击处理器。此外,流操作符结束了套接字类,而不是在我希望它生活的消息类中。“
第二个问题的解决方案是将operator<<
定义为包含消息类的名称空间中的非成员函数,而不是作为套接字类的成员函数。 ADL会找到它。
第一个问题的解决方案是缓冲进程中的数据,然后在每条消息的末尾刷新。如果Nagle缓冲没有阻止上下文切换,那么你可能能够通过搞乱套接字实现这一点,我不知道。但是,您当然可以做的是在以更加C ++的方式发送之前准备每条消息。替换:
sock << type;
sock << action;
使用:
stringstream ss;
ss << type;
ss << action;
sock << ss.str();