2009-10-24 8 views
5

Necesito enviar una estructura C sobre el cable (usando sockets UDP, y posiblemente XDR en algún momento) a una tasa de actualización bastante alta, lo que puede causar muchos Tráfico redundante e innecesario a varios khz.Cómo delta codificar una estructura C/C++ para la transmisión a través de sockets

Esto se debe a que algunos de los datos en la estructura pueden no haber cambiado a veces, así que pensé que la codificación delta de la estructura C actual contra la estructura C anterior parecería una buena idea, más o menos como un " diff ".

Pero me pregunto, ¿cuál es el mejor enfoque para hacer algo como esto, idealmente de una manera portátil que también asegura que se mantenga la integridad de los datos? ¿Sería posible simplemente XOR los datos y proceder de esta manera?

Del mismo modo, sería importante que el enfoque siga siendo lo suficientemente extensible, de modo que los nuevos campos se puedan agregar a la estructura o reordenar si es necesario (relleno), que también suena como si requiriera información de versiones.

Cualquier idea o punteros (¿hay bibliotecas existentes?) Sería muy apreciada.

Gracias

EDIT: Gracias a todos los que proporcionó una respuesta, el nivel de detalle es muy apreciado, me doy cuenta de que probablemente no debería haber mencionado UDP embargo, debido a que no es de hecho el principal problema, porque ya existe un protocolo correspondiente implementado sobre UDP que da cuenta de las dificultades mencionadas, por lo que la pregunta fue realmente destinada a ser específica para los medios factibles de codificación delta de una estructura, y no tanto sobre el uso de UDP en particular como un mecanismo de transporte .

+0

Supongo que depende de lo mucho que la los datos van a cambiar (1%? 10%? 50%?) y cuán regulares son los cambios (¿están en los mismos lugares o en todas partes?) –

+0

Simplemente curioso: ¿por qué una estructura C en lugar de usar algo como XMLRPC, SOAP u otra comunicación mecanismos de unificación como DBUS? ¿Qué le pasará a la estructura cuando llegue al otro lado? – aneccodeal

Respuesta

4

UDP no garantiza que se haya recibido un paquete determinado, por lo que es problemático codificar lo que se transmite como una "diferencia de la última vez": no se puede saber que su contraparte tiene la misma idea que usted sobre lo que la "última vez" fue. Básicamente, tendría que crear una sobrecarga en la parte superior de UDP para verificar qué paquetes se han recibido (etiquetar cada paquete con una ID única): todos los que hayan intentado seguir esta ruta estarán de acuerdo en que, en la mayoría de los casos, se encuentran más o más menos duplicación de la infraestructura de transmisión TCP sobre UDP ... solo, muy probablemente, no tan sólida y bien desarrollada (aunque hay que admitir que a veces puede aprovechar características muy especiales de sus cargas útiles para obtener una ventaja modesta sobre el bien común) viejo TCP).

¿Su transmisión debe ser de un solo sentido, remitente al receptor? Si ese es el caso (es decir, no es aceptable que el receptor envíe acuses de recibo o retransmite), entonces realmente no hay mucho que pueda hacer en este sentido. Una cosa que me viene a la mente: si está bien que el receptor no esté sincronizado por un tiempo, entonces el emisor podría enviar dos tipos de paquetes: uno con una imagen completa del valor actual de la estructura y una identificación etiqueta única, que se enviará al menos cada (digamos) 5 minutos (de manera realista, el receptor puede estar fuera de sincronización por hasta 15 minutos si pierde dos de estos "paquetes grandes"); uno con solo una actualización (diff) del último "paquete grande", que incluye la etiqueta única identificativa del paquete grande y (por ejemplo) una versión codificada en longitud de ejecución del XOR que menciona.

Por supuesto, una vez preparada la versión con longitud de ejecución, el servidor comparará su tamaño con el tamaño de la estructura completa, y solo enviará el tipo delta del paquete si los ahorros son sustanciales, de lo contrario podría ser envíe bien el paquete grande un poco antes de lo necesario (ganancias en confiabilidad). El recibido hará un seguimiento de la última etiqueta única de paquete grande que ha recibido y solo aplicará los deltas que pertenecen a ella (ayuda a que falten paquetes y paquetes entregados desordenados, dependiendo de lo sofisticado que desee hacer a su cliente).

La necesidad de versionar & c, dependiendo de qué signifique exactamente (los remitentes y receptores con diferentes ideas sobre cómo debería verse el diseño C de la estructura deben comunicarse con regularidad? ¿Cómo se comunican acerca de qué versiones conocen ambos? etc.), agregará todo un universo adicional de complicaciones, pero esa es realmente otra pregunta, y su pregunta central, tal como se resume en el título, ya es lo suficientemente grande ;-).

Si puede permitirse meta-mensajes ocasionales del receptor al remitente (acks o solicitudes de reenvío), entonces, dependiendo de los diversos parámetros numéricos en juego, puede diseñar diferentes estrategias. Sospecho que los ataques deberían ser bastante frecuentes para hacer mucho bien, así que una solicitud para reenviar un paquete grande (ya sea uno específicamente identificado o "lo que sea que tengas más fresco") puede ser la mejor meta-estrategia para eliminar el espacio de opciones (que de otra manera amenaza con explotar ;-). Si es así, entonces el remitente puede ignorar felizmente cualquier estrategia que el receptor esté utilizando para solicitar reenvíos de paquetes grandes, y usted puede experimentar en el lado del receptor con varias de esas estrategias sin necesidad de volver a desplegar el remitente también.

Es difícil ofrecer mucha más ayuda sin algunos detalles, es decir, al menos los números de bolas para todos los parámetros numéricos - tamaños de paquetes, frecuencias de envío, cuánto tiempo es tolerable para el emisor estar fuera de sincronización con el receptor, un conjunto de parámetros de red, etc., etc. Pero espero que este análisis y sugerencias algo genéricos sigan siendo útiles.

3

para codificar delta:

1) Enviar "fotogramas clave" periódicamente (por ejemplo una vez por segundo). Un fotograma clave es una copia completa (en lugar de un delta) por lo que si pierde las comunicaciones por cualquier motivo, solo perderá una pequeña cantidad de datos antes de poder "adquirir la señal" nuevamente. Use un encabezado de paquete simple que le permita detectar el inicio de un paquete y saber qué tipo de datos contiene.

2) Calcule el delta del paquete anterior y codifíquelo en una forma compacta. Al examinar el tipo de datos que está enviando y la forma en que generalmente cambia, debe poder diseñar un delta bastante compacto. Sin embargo, puede que necesite verificar el tamaño del delta, en algunos casos puede no ser una codificación eficiente, si es más grande que un fotograma clave, puede enviar otro fotograma clave. También puede decidir en este punto si sus deltas son con pérdidas o sin pérdidas.

3) Agregue una verificación CRC al paquete (busque CRC32). Esto permitirá que el receptor verifique que el paquete se haya recibido intacto, lo que le permite omitir paquetes no válidos.

NOTAS:

  • tener cuidado con hacer esto a través de UDP - no da ninguna garantía de que sus paquetes llegarán en el mismo orden en que los envió. Obviamente, un delta solo funcionará si los paquetes están en orden. En este caso, deberá agregar alguna forma de ID de secuencia a cada paquete (el primer paquete es "1", el segundo paquete es "2", etc.) para que pueda detectar la recepción fuera de orden. Incluso puede que necesite mantener un búfer de "n" paquetes en el receptor para que pueda volver a armarlos en el orden correcto cuando llegue a decodificarlos (pero, por supuesto, esto podría introducir algo de latencia). Probablemente también omita algunos paquetes en UDP, en cuyo caso tendrá que esperar hasta el siguiente fotograma clave antes de poder "volver a adquirir la señal", por lo que los fotogramas clave deben ser lo suficientemente frecuentes para evitar interrupciones catastróficas. en tus comunicaciones

  • Considere el uso de compresión (por ejemplo, zip, etc.). Puede encontrar que un paquete completo puede crearse de manera compatible con el zip (por ejemplo, reordenar datos para agrupar bytes que probablemente tengan valores similares (especialmente ceros) juntos) y luego comprimirlo tan bien que sea más pequeño que un delta sin comprimir, y no será necesario que haga todo el esfuerzo de los deltas (y no tendrá que preocuparse por el pedido de paquetes, etc.).

edición - Utilizar siempre un número de versión (o tipo de paquete) en sus paquetes para que pueda agregar nuevos campos o cambiar la codificación delta en el futuro! Lo necesitarás para diferenciar los fotogramas clave/delta de todos modos.

+0

¿No sería más concisa su primera nota escrita como "reinventar TCP"? –

+0

Solo para agregar, gracias por entrar en este nivel de detalle, es muy apreciado. – guest

+0

@guest - sin preocupaciones. Espero que haya sido esclarecedor/interesante incluso si no proporcionó la solución que buscabas. –

1

No estoy convencido de que la codificación delta de valores en UDP, que es intrínsecamente poco confiable y fuera de servicio, será particularmente fácil. En cambio, enviaría una identificación del campo que ha cambiado y su valor actual. Eso tampoco requiere que cambie nada si desea agregar campos adicionales a la estructura de datos que está enviando. Si quieres una forma estándar de hacerlo, mira SNMP; eso puede ser algo que puede caer, o puede ser un poco holgado para usted (califica los nombres de campo globalmente y usa ASN.1 - ambos dan la máxima interoperabilidad, pero a costa de algunos bytes en el paquete).

0

Utilice un RPC como CORBA o protocolo tampones

Uso DTLS con una opción de compresión

Utilice un formato empaquetado

repurposes una biblioteca de compresión de encabezado existente

Cuestiones relacionadas