2012-08-16 10 views
26

Al mio server, riceviamo messaggi autodescritti (come definito here ... che non era tutto così facile in quanto non ci sono esempi "buoni" di questo in C++).Come creare dinamicamente un nuovo protobuf da un insieme di descrittori già definiti?

A questo punto non ho problemi a creare messaggi da quelli descritti. Posso prendere il FileDescriptorSet, passare attraverso ogni FileDescriptorProto, aggiungendo ciascuno a un DescriptorPool (usando BuildFile, che mi dà anche ogni FileDescriptor definito).

Da qui posso creare uno dei messaggi che sono stati definiti nel FileDescriptorSet con un DynamicMessageFactory istanziato con il DP e chiamando GetPrototype (che è molto facile da fare come il nostro SelfDescribedMessage richiesto il FULL_NAME messaggi() e quindi possiamo chiamare il metodo FindMessageTypeByName del DP, che ci fornisce il Message Prototype correttamente codificato).

La domanda è: come posso prendere ciascun descrittore o messaggio già definito e COSTRUIRE dinamicamente un messaggio "principale" che contiene tutti i messaggi definiti come messaggi nidificati. Questo dovrebbe essere usato principalmente per salvare lo stato corrente dei messaggi. Attualmente stiamo gestendo questo semplicemente istanziando un tipo di ogni messaggio nel server (per mantenere uno stato centrale tra diversi programmi). Ma quando vogliamo "salvare" lo stato attuale, siamo costretti a riversarli su disco come definito here. Sono in streaming un messaggio alla volta (con un prefisso di dimensione). Ci piacerebbe avere UN messaggio (uno per dominarli tutti) invece del flusso costante di messaggi separati. Questo può essere usato per altre cose una volta elaborato (stato condiviso basato sulla rete con serializzazione ottimizzata e facile)

Dato che abbiamo già i Descrittori incrociati e definiti, si potrebbe pensare che ci sarebbe un modo semplice per costruire "nuovi" messaggi da quelli già definiti. Finora la soluzione ci ha alluso. Abbiamo provato a creare il nostro DescriptorProto e ad aggiungere nuovi campi del tipo dai nostri Descrittori già definiti ma ci siamo persi (non ci siamo ancora immersi profondamente in questo). Abbiamo anche cercato di aggiungerli come estensioni (attualmente sconosciuta come farlo). Abbiamo bisogno di creare il nostro DescriptorDatabase (anche sconosciuto al momento come farlo)?

Eventuali approfondimenti?


collegato example source su BitBucket.


Speriamo che questa spiegazione possa essere d'aiuto.

Sto tentando di creare dinamicamente un messaggio da un insieme di messaggi già definiti. L'insieme di messaggi già definiti viene creato usando il metodo "auto-descritto" spiegato (brevemente) nel tutorial ufficiale C++ protobuf (cioè questi messaggi non sono disponibili in forma compilata). Questo messaggio appena definito dovrà essere creato in fase di runtime.

Ho provato a utilizzare i descrittori lineari per ciascun messaggio e ho tentato di creare un FileDescriptorProto. Ho provato a guardare i metodi DatabaseDescriptor. Entrambi senza fortuna. Attualmente si sta tentando di aggiungere questi messaggi definiti come un'estensione a un altro messaggio (anche se in fase di compilazione quei messaggi definiti e il loro 'set di descrittori' non sono stati classificati come estensioni di qualcosa) che è il punto in cui inizia il codice di esempio.

+0

wow ... neanche in testa ... Ecco dove sono a finora. Questo è l'unico di cui ho una fonte pubblica ... ovviamente non viene compilato in questo momento (tutto va bene fino alla fine in cui viene creato per la prima volta ExtensionSet) ... Cercando di percorrere la rotta delle estensioni al momento mentre l'altra due mi hanno fallito fino ad ora. http://goo.gl/VJhnk – g19fanatic

+0

Il problema che sto avendo al momento è nell'inizializzazione dell'identificatore di estensione. Ho bisogno di una classe per puntare i MessageTypeTraits a quella di uno che descrive il tipo di messaggio (potrebbe dover fare la mia magia di templateing) ma non ho ancora avuto successo ... – g19fanatic

+1

Onestamente, ho letto la tua domanda 3 volte, e ancora non riescono a capire cosa stai descrivendo. Penso che questo accada alla maggior parte dei lettori, ecco perché non hai ricevuto una risposta. Hai bisogno di semplificare le cose. Inoltre, sembra davvero che tu stia creando qualcosa di complicato, in cui è possibile una soluzione molto più semplice. – Codeguard

risposta

4

sono stato in grado di risolvere questo problema con la creazione di un file in modo dinamico e Proto caricandolo con un Importer.

L'unico requisito è che ciascun client invii il proprio proto file (necessario solo all'avvio ... non durante l'esecuzione completa). Il server salva quindi ciascun file di proto in una directory temporanea. Un'alternativa se possibile è solo puntare il server verso una posizione centrale che contiene tutti i file di proto necessari.

Questo è stato fatto utilizzando prima un DiskSourceTree per mappare le posizioni del percorso effettivo in quelle virtuali del programma. Quindi creare il file .proto per importare tutti i file di proto inviati attraverso E definire un campo facoltativo in un 'messaggio principale'.

Dopo aver salvato il disco master.proto, importarlo con l'utilità di importazione. Ora usando gli importatori DescriptorPool e DynamicMessageFactory, sono in grado di generare in modo affidabile l'intero messaggio sotto un unico messaggio. Metterò un esempio di ciò che sto descrivendo più avanti, stasera o domani.

Se qualcuno ha suggerimenti su come rendere questo processo migliore o su come farlo in modo diverso, si prega di dirlo.

Lascerò questa domanda senza risposta fino a quando la munificenza sta per scadere nel caso in cui qualcun altro abbia una soluzione migliore.

+4

Hai un esempio di come hai implementato questo? – Dave

1

Che dire di serializzare tutti i messaggi in stringhe, e rendendo il messaggio maestro una sequenza di byte() stringhe, alla

message MessageSet 
{ 
    required FileDescriptorSet proto_files = 1; 
    repeated bytes serialized_sub_message = 2; 
} 
+0

@ g19fanatic : Se questo non è in linea con le tue esigenze, potresti chiarire cosa stai cercando di ottenere che ciò non funzioni? – Managu

+0

Questo è esattamente il modo in cui lo stiamo attualmente facendo, ma il problema sta nell'analizzare rapidamente quell'insieme di messaggi. Perché non ci sono delimitatori intrinseci tra i messaggi, archiviamo la dimensione di ogni messaggio in un prefisso uint32. Usiamo questo prefisso per analizzare singolarmente ciascun messaggio. Quello che stiamo cercando di fare è avere un solo messaggio che poi serializziamo. Quando è il momento di analizzarlo, è solo una chiamata al posto del ripetitivo getnextsize, analizza il messaggio successivo, ripeti. – g19fanatic

+2

Esatto, quindi consegnare la parte di codifica ai buffer del protocollo, con 'serialized_sub_message' che viene' ripetuto'. Quindi è ancora un ciclo ('dispatch_serialized_message (message_set.serialized_sub_message (i))'), ma non si ha a che fare con i dettagli della codifica sul filo. – Managu

5

avete bisogno di un protobuf::DynamicMessageFactory:

{ 
    using namespace google; 

    protobuf::DynamicMessageFactory dmf; 
    protobuf::Message* actual_msg = dmf.GetPrototype(some_desc)->New(); 

    const protobuf::Reflection* refl = actual_msg->GetReflection(); 

    const protobuf::FieldDescriptor* fd = trip_desc->FindFieldByName("someField"); 
    refl->SetString(actual_msg, fd, "whee"); 

    ... 

    cout << actual_msg->DebugString() << endl; 
} 
Problemi correlati