Reputation: 2064
I'm using google protobuf
to implement a simple Request/Response
based protocol.
A peer can receive via socket
both Request
and Response
, (of course serialized
) as string
.
I'm using my own c++ socket implementation, so I implemented operator>>
this way (the same is for operator<<
) to receive data from a socket
object:
...
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");
}
So template argument M
can be objects Request
and Response
.
// some lines from req_res.proto
message Request {
required action_t action = 1;
}
enum result_t {
...
}
message Response {
required result_t result = 1;
...
}
How can I determine whether I received a Response
or a Request
using operator>>
this way?
my_socket_object s;
...
for (;;) {
Request|Response r;
s >> r;
...
}
...
Upvotes: 4
Views: 109
Reputation: 1
You can have one basic Message
object and extend all other types used in your protocol from it:
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;
}
This is a bit more elegant, self contained and easier to extend, than the discriminator/union solution proposed in the other answer IMHO.
You can use this technique even further to structure e.g. your Request
/Response
messages like this
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;
}
Upvotes: 2
Reputation: 21194
One possible approach is to put any possible message inside another high level message as a kind of tagged-union:
enum protocolmessage_t {
Request = 1;
Response = 2;
}
message ProtocolMessage {
required protocolmessage_t type = 1;
optional Request request = 10;
optional Response response = 11;
}
Then you would provide this ProtocolMessage
as the M
parameter to the >>
operator and you can check the type and extract the corresponding value element.
An alternative way is to prefix every message with 1 byte for the type, make a switch on that type and then call your >>
operator with the corresponding type.
Upvotes: 1