套接字中的多个不同的 protobuf 消息

multiple different protobuf messages in a socket

我在我的 C++ 服务器上使用了 protobuf。但是我在套接字中遇到多个不同的 protobuf 消息的问题 我定义了很多proto消息,比如

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;
}
....

所以每次通过socket发送消息时,我都会添加8个字节,4个是总socket len,4个是opcode,opcode表示消息类型。

所以在服务器端,我收到消息,我读取前 4 个字节,得到消息的长度,然后我将读取另外 4 个字节来获取消息的类型,最后我读取了消息的长度字节。然后我会用message type to method map(比如404 => "sdkset", 405 => "sdksetret")来解码message.

我发现这种方式效果很好,但我想知道是否有任何优雅的方式来识别没有 4 字节消息类型的消息。 我看过留言历史,一种方法是把整个留言加到一个大留言里,像这样

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

由于我有40多种消息类型,我认为这种方式可能会影响性能,而且在我看来,这种方式很难看。

那你有什么好的建议吗..

Protobuf v2.6.0 为此引入了 the oneof keyword。示例:

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

oneof 确保恰好设置了一个字段,并让您 switch() 选择哪一个。

请注意,即使在 Protobuf 2.6.0 之前,最好的解决方案也是一系列可选字段,也许用一个枚举来指定要设置的字段:

message BigMessage {
  enum Type { HGETRET = 0, HPUT = 1, ... }
  required Type t = 1;
  optional SdkHGetRet hgetret = 2;
  optional SdkHPut hput = 3;
  ...
}