Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

multiple different protobuf messages in a socket

I use protobuf with my c++ server. But I have a problem with multiple different protobuf messages in a socket I define many proto messages, such as

message SdkHGetRet {
  required int32 opcode = 1;
  required bytes value = 2;
}

message SdkHPut {
  required bytes table = 1;
  required bytes hname = 2;
  required bytes key = 3;
  required bytes value = 4;
  optional int32 writesrc = 5 [default = 0];
}

message SdkSet {
  required bytes table = 1;
  required bytes key = 2;
  required bytes value = 3;
  optional int32 writesrc = 4 [default = 0];
}

message SdkSetRet {
  required bool status = 1;
  optional string master = 2;
}

message SdkInvalidOperation {
  required int32 what = 1;
  required bytes why = 2;
}
....

So every time I send the message by socket, I will add 8 bytes, 4 for the total socket len, 4 for the opcode, opcode mean the message type.

So in the server side, I receive the message, I read the first 4 byte, and I got the message's length, then I will read another 4 bytes to get the message's type, at last I read the message's length bytes. Then I will use message type to method map ( such as 404 => "sdkset", 405 => "sdksetret") to decode the message.

I find this way work well, but I wonder is there any elegance way to identify the message without the 4 byte message type. I have read the message history, one method is add the entire message in a big message, like this way

message BigMessage
{
enum Type { sdkset = 0, sdksetred = 1}
require Type t = 1,
optional  string key = 2,
...
}

Since I have more than 40 types of message, I think this way may affect performance, and in my opinion, this way looks ugly.

So can you give me any good suggestion..

like image 235
baotiao Avatar asked Jan 08 '23 17:01

baotiao


1 Answers

Protobuf v2.6.0 introduced the oneof keyword for this. Example:

message BigMessage {
  oneof message {
    SdkHGetRet hgetret = 1;
    SdkHPut hput = 2;
    ...
  }
}

oneof ensures that exactly one of the fields is set, and lets you switch() on which one.

Note that even before Protobuf 2.6.0, the best solution would have been a series of optional fields, perhaps with an enum to specify which one is set:

message BigMessage {
  enum Type { HGETRET = 0, HPUT = 1, ... }
  required Type t = 1;
  optional SdkHGetRet hgetret = 2;
  optional SdkHPut hput = 3;
  ...
}
like image 158
Kenton Varda Avatar answered Jan 27 '23 06:01

Kenton Varda