协议缓冲区多态

rec*_*ion 5 c++ protocol-buffers

我有一个C ++程序,可以将各种事件(例如StatusEventDetectionEvent具有不同的原型消息定义)发送到消息服务(当前为Active MQ,通过activemq-cpp APU)。我想编写一个消息侦听器,以接收这些消息,解析它们并将它们写入cout,以进行调试。侦听器具有status_event_pb.hdetection_event_pb.h链接。

我的问题是:如何在不知道事件类型的情况下解析它?我想做类似的事情(用伪代码)

receive event
type = parseEventType(event);
if( type == events::StatusEventType) { 
    events::StatusEvent se = parseEvent(event);
    // do stuff with se
}
else {
    // handle the case when the event is a DetectionEvent
}
Run Code Online (Sandbox Code Playgroud)

我看了这个问题,但是不确定扩展是否是正确的选择。简短的代码片段将为您提供帮助。关于protobuf的例子非常罕见!

谢谢!


似乎扩展确实是可行的方法,但是我还有最后一点要解决。这是我到目前为止的原型定义:

// A general event, can be thought as base Event class for other event types.
message Event {
    required int64 task_id = 1;     
    required string module_name = 2;    // module that sent the event

    extensions 100 to 199;               // for different event types
}

// Extend the base Event with additional types of events.
extend Event {
    optional StatusEvent statusEvent = 100;
    optional DetectionEvent detectionEvent = 101;
}

// Contains one bounding box detected in a video frame, 
// representing a region of interest.
message DetectionEvent {
    optional int64 frame = 2;   
    optional int64 time = 4;
    optional string label = 6;
}

// Indicate status change of current module to other modules in same service.
// In addition, parameter information that is to be used to other modules can
// be passed, e.g. the video frame dimensions.
message StatusEvent {
    enum EventType { 
        MODULE_START = 1; 
        MODULE_END = 2; 
        MODULE_FATAL = 3; 
    }
    required EventType type = 1;        
    required string module_name = 2;    // module that sent the event

    // Optional key-value pairs for data to be passed on.
    message Data {
        required string key = 1;
        required string value = 2;
    }
    repeated Data data = 3; 
}
Run Code Online (Sandbox Code Playgroud)

我现在的问题是(1)如何知道Event消息包含哪个特定事件,以及(2)确保它仅包含一个此类事件(根据定义,它可以同时包含a StatusEvent和a DetectionEvent)。

Mat*_* M. 3

我不会为此使用协议缓冲区,但这可能是很少使用和其他习惯的结合。

不管怎样,我想我会在这里使用一个抽象类,以简化一般处理并包含路由信息。不会使用 protobuf 定义的类,并且包含 protobuf 消息。

class Message
{
public:
  Type const& GetType() const;

  Origin const& GetOrigin() const;
  Destination const& GetDestination() const;

  // ... other informations

  template <class T>
  void GetContent(T& proto) const
  {
    proto.ParseFromIstream(&mContent); // perhaps a try/catch ?
  }

private:
  // ...

  std::stringstream mContent;
};
Run Code Online (Sandbox Code Playgroud)

通过这种结构,您可以轻松地进行一般和特定的处理:

void receive(Message const& message)
{
  LOG("receive - " << message.GetType() << " from " << message.GetOrigin()
                   << " to " << message.GetDestination());

  if (message.GetType() == "StatusEvent")
  {
    StatusEvent statusEvent;
    message.Decode(statusEvent);
    // do something
  }
  else if (message.GetType() == "DetectionEvent")
  {
    DetectionEvent detectionEvent;
    message.Decode(detectionEvent);
    // do something
  }
  else
  {
    LOG("receive - Unhandled type");
  }
}
Run Code Online (Sandbox Code Playgroud)

std::unordered_map<Type,Handler>当然,如果您使用 a而不是硬编码链,那会更漂亮if / else if + / else,但原理仍然相同:

  1. 对标头中发送的消息类型进行编码
  2. 基于此类型在接收和发送时仅解码标头
  3. 在静态已知类型的代码部分中解码 protobuf 消息