协议缓冲区多态性 [英] Protocol buffer polymorphism

查看:174
本文介绍了协议缓冲区多态性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个C ++程序,发出各种事件,例如。 StatusEvent DetectionEvent 使用不同的proto消息定义到消息服务(当前活动MQ,通过activemq-cpp APU)。我想写一个消息侦听器接收这些消息,解析它们并将它们写入cout,用于调试目的。侦听器具有 status_event_pb.h detection_event_pb.h 链接。



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

 接收事件
type = parseEventType
if(type == events :: StatusEventType){
events :: StatusEvent se = parseEvent(event);
// do stuff with se
}
else {
//处理事件是DetectionEvent的情况
}

我看过这个问题,但我不知道扩展是否是正确的方式去这里。指向方式的短代码片段将是非常感谢。






看来扩展确实是要走的路,但我有最后一点要清除。这里是我迄今为止的proto定义:

  //一般事件,可以被认为是其他事件类型。 
message事件{
必需int64 task_id = 1;
required string module_name = 2; //发送事件的模块

extensions 100到199; //用于不同的事件类型
}

//使用其他类型的事件扩展基本事件。
extend Event {
可选StatusEvent statusEvent = 100;
optional DetectionEvent detectionEvent = 101;
}

//包含在视频帧中检测到的一个边界框,
//表示感兴趣的区域。
message DetectionEvent {
optional int64 frame = 2;
optional int64 time = 4;
optional string label = 6;
}

//指示当前模块对同一服务中其他模块的状态更改。
//另外,要用于其他模块的参数信息可以
//被传递,例如。视频帧尺寸。
message StatusEvent {
enum EventType {
MODULE_START = 1;
MODULE_END = 2;
MODULE_FATAL = 3;
}
必需EventType type = 1;
required string module_name = 2; //发送事件的模块

//可传递的数据的键值对。
message Data {
必需string key = 1;
必需string value = 2;
}
重复数据data = 3;
}

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

解决方案

我不会使用Protocol Buffers,这可能是一个小的使用和其他习惯的组合。



无论如何,我想在这里使用一个抽象类,以简化一般处理和包含路由信息。不会使用protobuf定义的类,并且将包含protobuf消息。

 类消息
{
public:
类型const& GetType()const;

来源const& GetOrigin()const;
Destination const& GetDestination()const;

// ...其他信息

模板< class T>
void GetContent(T& proto)const
{
proto.ParseFromIstream(& mContent); //也许一个try / catch?
}

private:
// ...

std :: stringstream mContent;
};

有了这种结构,你可以在手指尖处进行常规和特定的处理:

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

if(message.GetType()==StatusEvent)
{
StatusEvent statusEvent;
message.Decode(statusEvent);
// do something
}
else if(message.GetType()==DetectionEvent)
{
DetectionEvent detectionEvent;
message.Decode(detectionEvent);
//做某事
}
else
{
LOG(receive - Unhandled type);
}
}

当然,链接,而不是硬编码的如果/ else if / else 链接,但 c>


  1. 编码标题中发送的邮件类型

  2. 仅解码标题

  3. 在已知静态类型的代码部分中解码protobuf消息


I have a C++ program that sends out various events, e.g. StatusEvent and DetectionEvent with different proto message definitions to a message service (currently Active MQ, via activemq-cpp APU). I want to write a message listener that receives these messages, parses them and writes them to cout, for debugging purposes. The listener has status_event_pb.h and detection_event_pb.h linked.

My question is: How can I parse the received event without knowing its type? I want to do something like (in pseudo code)

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
}

I looked at this question but I'm not sure if extensions are the right way to go here. A short code snippet pointing the way will be much appreciated. Examples on protobuf are so rare!

Thanks!


It seems extensions are indeed the way to go but I've got one last point to clear up. Here's the proto definition that I have so far:

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

My problem now is (1) how to know which specific event that the Event message contains and (2) make sure that it contains only one such event (according to the definition, it can contain both a StatusEvent and a DetectionEvent).

解决方案

I would not use Protocol Buffers for that, but that's perhaps a combination of little use and other habits.

Anyway, I think I would use an abstract class here, to ease general handling and to contain routing information. Class that would not be defined using protobuf, and would contain a protobuf message.

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

With this structure, you have both general and specific handling at the tip of your fingers:

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

Of course, it would be prettier if you used a std::unordered_map<Type,Handler> instead of a hardcoded if / else if + / else chain, but the principle remains identical:

  1. Encode the type of message sent in the header
  2. Decode only the header upon reception and dispatch based on this type
  3. Decode the protobuf message in a part of the code where the type is known statically

这篇关于协议缓冲区多态性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆