如何确定通过套接字接收的(序列化和模板化)对象的类型是什么?

时间:2014-09-03 10:05:26

标签: c++ sockets protocol-buffers

我正在使用google protobuf来实现一个基于Request/Response的简单协议。

对等方可以通过socket RequestResponse(当然serialized)收到string

我正在使用我自己的c ++套接字实现,所以我以这种方式实现operator>>(同样适用于operator<<)从socket对象接收数据:

 ...
template<class M>
void operator>>(M& m) throw (socks::exception) {
    std::string str;
    if (!this->recv(str)) {
        throw socks::exception(">> failed to retrieve stream via socket");
        return;
    }

    if (!m.ParseFromString(str))
        throw socks::exception(
                "failed to parse the received stream via socket");
}

因此模板参数M可以是对象RequestResponse

// some lines from req_res.proto

message Request {
  required action_t action = 1; 
}

enum result_t {
   ...
}

message Response {
  required result_t result  = 1;
   ...
}

如何通过这种方式确定我是否使用Response收到Requestoperator>>

my_socket_object s;
 ...
for (;;) {
  Request|Response r;
  s >> r;
   ...
}
 ...

2 个答案:

答案 0 :(得分:2)

您可以拥有一个基本的Message对象,并扩展协议中使用的所有其他类型:

message Message {
    extensions 100 to max;
}

message Request {
    extends Message {
        optional Request request = 100;
    }
    required action_t action = 1; 
}

message Response {
    extends Message {
        optional Response response = 101;
    }
    required result_t result  = 1;
}

这比其他答案恕我直言中提出的鉴别器/联合解决方案更优雅,自包含且更容易扩展。


您可以进一步使用此技术进行构建,例如您的Request / Response消息

message Request {
    extends Message {
        optional Request request = 100;
    }

    extensions 100 to max;
}

message Action1 {
    extends Request {
        optional Action1 action1 = 100;
    }
    optional int32 param1 = 1;
    optional int32 param2 = 2;
}

message Action2 {
    extends Request {
        optional Action2 action2 = 101;
    }
    optional int32 param1 = 1;
    optional int32 param2 = 2;
}

答案 1 :(得分:1)

一种可能的方法是将任何可能的消息放在另一个高级消息中作为一种标记联合:

enum protocolmessage_t {
  Request = 1;
  Response = 2;
}

message ProtocolMessage {
  required protocolmessage_t type = 1; 

  optional Request request = 10;
  optional Response response = 11;
}

然后,您将此ProtocolMessage作为M参数提供给>>运算符,您可以检查类型并提取相应的值元素。

另一种方法是为每个消息添加1个字节的前缀,对该类型进行切换,然后使用相应的类型调用>>运算符。