2012-08-16 19 views
26

En mi servidor, recibimos mensajes autodescritos (como se define here ... que por cierto no fue tan fácil ya que no hay ningún "buen" ejemplo de esto en C++).¿Cómo construir dinámicamente un nuevo protobuf a partir de un conjunto de descriptores ya definidos?

En este punto, no tengo problemas para crear mensajes de estos autodescritos. Puedo tomar el FileDescriptorSet, ir a través de cada FileDescriptorProto, agregando cada uno a un DescriptorPool (usando BuildFile, que también me da cada FileDescriptor definido).

Desde aquí puedo crear cualquiera de los mensajes que se definieron en el FileDescriptorSet con un DynamicMessageFactory ejemplificada con la DP y llamando GetPrototype (que es muy fácil de hacer como nuestro SelfDescribedMessage requiere los mensajes FULL_NAME() y por lo tanto podemos llamar el método FindMessageTypeByName del DP, que nos da el prototipo de mensaje adecuadamente codificado).

La pregunta es cómo puedo tomar cada Descriptor o mensaje ya definido y construir dinámicamente un mensaje 'maestro' que contenga todos los mensajes definidos como mensajes anidados. Esto se usaría principalmente para guardar el estado actual de los mensajes. Actualmente estamos manejando esto simplemente instalando un tipo de cada mensaje en el servidor (para mantener un estado central en diferentes programas). Pero cuando queremos 'guardar' el estado actual, nos vemos obligados a transmitirlos al disco como se define en here. Se transmiten un mensaje a la vez (con un prefijo de tamaño). Nos gustaría tener UN MENSAJE (uno para gobernarlos a todos) en lugar de un flujo constante de mensajes separados. Esto se puede usar para otras cosas una vez que se resuelve (estado compartido basado en red con serialización optimizada y fácil)

Dado que ya tenemos los descriptores entrelazados y definidos, uno pensaría que habría una manera fácil de construir 'nuevos' mensajes de aquellos ya definidos. Hasta ahora, la solución nos ha aludido. Hemos intentado crear nuestro propio DescriptorProto y agregar nuevos campos del tipo de nuestros Descriptores ya definidos, pero nos hemos perdido (aún no nos hemos sumergido en este). También hemos analizado la posibilidad de agregarlos como extensiones (se desconoce en este momento cómo hacerlo). ¿Necesitamos crear nuestro propio DescriptorDatabase (también desconocido en este momento cómo hacerlo)?

¿Algún conocimiento?


Enlazado example source en BitBucket.


Afortunadamente esta explicación ayudará.

Estoy intentando crear dinámicamente un Mensaje a partir de un conjunto de Mensajes ya definidos. El conjunto de mensajes ya definidos se crea utilizando el método "autodescrito" explicado (brevemente) en el tutorial oficial de C++ protobuf (es decir, estos mensajes no están disponibles en forma compilada). Este mensaje recién definido deberá crearse en tiempo de ejecución.

He intentado utilizar los descriptores directos para cada mensaje e intenté crear un FileDescriptorProto. He intentado mirar los métodos DatabaseDescriptor. Ambos sin suerte. Actualmente, intenta agregar estos mensajes definidos como una extensión a otro mensaje (incluso en el momento de la compilación, esos mensajes definidos, y su 'conjunto de descriptores' no se clasificaron como extendiendo nada), que es donde comienza el código de ejemplo.

+0

vaya ... ni siquiera un comentario ... Aquí es donde estoy en tan lejos. Este es el único que tengo como fuente pública ... obviamente no compila en este momento (todo va bien hasta el final donde se creó por primera vez el ExtensionSet) ... Tratando de ir por la ruta de extensiones en este momento como el otro dos me han fallado por el momento. http://goo.gl/VJhnk – g19fanatic

+0

El problema que estoy teniendo en este momento es la inicialización del Identificador de extensión. Necesito una clase para señalar el MessageTypeTraits al de uno que describa el tipo de mensaje (¿podría tener que hacer mi propia magia de creación de plantillas?) Pero no ha tenido éxito hasta el momento ... – g19fanatic

+1

Honestamente, leí su pregunta 3 veces y todavía no entiendo lo que estás describiendo. Creo que esto le sucede a la mayoría de los lectores, es por eso que no obtuviste una respuesta. Necesitas simplificar cosas. Además, realmente parece que estás creando algo demasiado complicado, donde es posible una solución mucho más sencilla. – Codeguard

Respuesta

4

yo era capaz de resolver este problema mediante la creación de un archivo de forma dinámica y .proto cargando con un Importer.

El único requisito es que cada cliente envíe a través de su archivo proto (solo se necesita en init ... no durante la ejecución completa). El servidor luego guarda cada archivo proto en un directorio temporal. Una alternativa, si es posible, es simplemente apuntar el servidor a una ubicación central que contenga todos los archivos proto necesarios.

Esto se hizo usando primero un DiskSourceTree para mapear las ubicaciones reales de las rutas en las virtuales del programa. Luego construyendo el archivo .proto para importar cada archivo proto enviado a través Y definir un campo opcional en un 'mensaje maestro'.

Después de que el master.proto se haya guardado en el disco, lo importo con el importador. Ahora, usando Importers DescriptorPool y DynamicMessageFactory, puedo generar de manera confiable todo el mensaje en un solo mensaje. Voy a poner un ejemplo de lo que estoy describiendo más tarde esta noche o mañana.

Si alguien tiene alguna sugerencia sobre cómo mejorar este proceso o cómo hacerlo diferente, dígalo.

Dejaré esta pregunta sin respuesta hasta que la recompensa esté a punto de caducar en caso de que alguien más tenga una solución mejor.

+4

¿Tiene un ejemplo de cómo implementó esto? – Dave

1

¿Qué pasa con la serialización de todos los mensajes en cadenas, y hacer que el mensaje principal de una secuencia de cadenas (byte), a la

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

@ g19fanatic : Si esto no está en línea con lo que está buscando, ¿podría aclarar qué está tratando de lograr para que esto no funcione? – Managu

+0

Esta es exactamente la forma en que lo estamos haciendo actualmente, pero el problema radica en analizar ese conjunto de mensajes rápidamente. Debido a que no hay delimitadores inherentes entre los mensajes, almacenamos el tamaño de cada mensaje en un prefijo uint32. Usamos este prefijo para analizar individualmente cada mensaje. Lo que estamos tratando de hacer es tener solo un mensaje que luego serialicemos. Cuando es hora de analizarlo, es solo una llamada en lugar del repetitivo getnextsize, el siguiente mensaje de análisis, repita. – g19fanatic

+2

Correcto, entonces transfiera la parte de codificación a los búferes de protocolo, con 'serialized_sub_message' como' repeat'. Por lo tanto, sigue siendo un bucle ('dispatch_serialized_message (message_set.serialized_sub_message (i))'), pero no tiene que ocuparse de los detalles de la codificación en el cable. – Managu

5

se necesita 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; 
} 
Cuestiones relacionadas