协议缓冲区多态性

时间:2010-08-11 17:00:33

标签: 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
}

我看了this question,但我不确定延伸是否是正确的方式。我们非常感谢一个简短的代码片段。关于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; 
}

我现在的问题是(1)如何知道事件消息包含哪个特定事件,以及(2)确保它只包含一个这样的事件(根据定义,它可以包含StatusEventDetectionEvent)。

1 个答案:

答案 0 :(得分:3)

我不会使用Protocol Buffers,但这可能是很少使用和其他习惯的组合。

无论如何,我想我会在这里使用一个抽象类来简化一般处理并包含路由信息。不使用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;
};

使用这种结构,您可以在手指尖处进行一般处理和特定处理:

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");
  }
}

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

  1. 对标题中发送的邮件类型进行编码
  2. 根据此类型
  3. 在接收和发送时仅解码标题
  4. 在静态已知类型的代码的一部分中解码protobuf消息