2010-08-11 4 views
4

У меня есть программа на С ++, которая отправляет различные события, например. StatusEvent и DetectionEvent с различными определениями прото-сообщений для службы сообщений (в настоящее время Active MQ, через activumq-cpp APU). Я хочу написать прослушиватель сообщений, который получает эти сообщения, анализирует их и записывает в cout для целей отладки. У слушателя есть status_event_pb.h и detection_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, но я не уверен, если расширения являются правильный путь здесь. Короткие фрагменты кода, указывающие на способ, будут высоко оценены. Примеры на протобуфе настолько редки!

Спасибо!


Похоже, что расширения действительно подходят, но у меня есть один последний момент, чтобы прояснить ситуацию. Вот определение прото, что у меня до сих пор:

// 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), убедитесь, что он содержит только один такого события (согласно определению, он может содержать как StatusEvent, так и DetectionEvent).

+0

Найдено эту интересную тему: http://markmail.org/ message/dgmf5iuhhgoe7keb # query: protocol% 20buffer% 20polymorphism + страница: 1 + mid: 73p5kddhvmokcpvo + state: results – recipriversexclusion

+1

Возможный дубликат [правильный способ сделать полиморфизм с буферами протоколов?] (http://stackoverflow.com/q/3018743/1468366) – MvG

ответ

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

С этой структурой, у вас есть как общие, так и конкретные обращения на кончиках ваших пальцев:

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. Encode тип сообщения, отправленного в заголовке
  2. Decode только заголовок после приема и отправки на основе этого типа
  3. Расшифруйте Protobuf сообщение в части кода, где тип известен статически
+0

Спасибо за ваш ответ Маттиу. Из-за других ограничений в системе мне нужно протобуф. Поскольку я больше узнаю об этой технологии, тем лучше она выглядит. Я настоятельно рекомендую. – recipriversexclusion

+0

@recipriversexclusion: что бы мы без ограничений :)? К сожалению, я не знаю об «альтернативе» в самой грамматике. Полагаю, что я просто обойду проблему, определив кодировщики/декодеры, которые не позволят им появляться. –