2010-08-11 6 views
4

J'ai un programme C++ qui envoie divers événements, par ex. StatusEvent et DetectionEvent avec différentes définitions de message proto à un service de messagerie (actuellement MQ active, via l'APU activemq-cpp). Je veux écrire un écouteur de message qui reçoit ces messages, les analyse et les écrit à cout, à des fins de débogage. L'écouteur a status_event_pb.h et detection_event_pb.h lié.Polymorphisme de tampon de protocole

Ma question est: Comment puis-je analyser l'événement reçu sans connaître son type? Je veux faire quelque chose comme (dans le code pseudo)

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 
} 

Je regardais this question mais je ne suis pas sûr si les extensions sont la bonne façon d'aller ici. Un extrait de code court pointant le chemin sera très apprécié. Les exemples sur protobuf sont si rares!

Merci! Il semble que les extensions sont effectivement la voie à suivre, mais j'ai un dernier point à éclaircir. Voici la définition proto que j'ai jusqu'à présent:

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

Mon problème est maintenant (1) comment savoir quel événement spécifique que le message de l'événement contient et (2) assurez-vous qu'il ne contient que un tel événement (selon la définition, il peut contenir à la fois un StatusEvent et un DetectionEvent).

+0

trouvé ce fil intéressant: http://markmail.org/ message/dgmf5iuhhgoe7keb # requête: protocole% 20buffer% 20polymorphisme + page: 1 + milieu: 73p5kddhvmokcpvo + état: résultats – recipriversexclusion

+1

Possible copie de [quelle est la bonne façon de faire du polymorphisme avec des tampons de protocole?] (http://stackoverflow.com/q/3018743/1468366) – MvG

Répondre

3

Je n'utiliserais pas de tampons de protocole pour cela, mais c'est peut-être une combinaison de peu d'utilisation et d'autres habitudes.

Quoi qu'il en soit, je pense que j'utiliserais ici une classe abstraite, pour faciliter le traitement général et pour contenir les informations de routage. Classe qui ne serait pas définie avec protobuf et qui contiendrait un message 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; 
}; 

Avec cette structure, vous avez à la fois la manipulation générale et spécifique à la pointe de vos doigts:

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

Bien sûr, ce serait plus joli si vous avez utilisé un std::unordered_map<Type,Handler> au lieu d'une chaîne if/else if +/else hardcoded , mais le principe reste identique:

  1. Encode le type de message envoyé dans l'en-tête
  2. Decode que l'en-tête à la réception et l'expédition en fonction de ce type
  3. Décoder le message protobuf dans une partie du code où le type est connu statiquement
+0

Merci pour votre réponse Matthieu. En raison d'autres contraintes sur le système, j'ai besoin de protobuf. Au fur et à mesure que j'apprends davantage sur cette technologie, le mieux c'est. Je le recommande fortement. – recipriversexclusion

+0

@recipriversexclusion: que serions-nous sans contraintes :)? Malheureusement, je ne suis pas au courant d'une «alternative» dans la grammaire elle-même. Je suppose que je contournerais simplement le problème en définissant des encodeurs/décodeurs qui ne permettent pas aux deux d'apparaître. –