2009-08-31 17 views
7

Estoy trabajando en una pila de protocolos simple para un pequeño sistema integrado (multidrop, tipo de cosas rs485). En esta pila, los modelos losely después de capas OSI:¿Cuál es la mejor manera de manejar buffers grandes en una pila de protocolos en capas?

  1. de aplicación
  2. Red
  3. Datalink
  4. física (controlador serie)

Cada capa tiene su propia parte de cabecera/pie de página que se envuelve la carga útil de la capa superior.

Usaré mi propio grupo de búferes de bloques de tamaño fijo asignados estáticamente para almacenar los paquetes binarios. (No malloc/gratis en esta aplicación)

En otras API he visto que los datos generalmente se pasan como un puntero de const con una longitud asociada. De esta manera, los datos necesitarían una operación de copia en cada capa, ya que la carga útil de la capa anterior se coloca en un búfer recién asignado para la capa actual.

Para una pila de tres capas esto sería de 2 operaciones de copia y 3 búferes asignados.

¿Hay una mejor manera de hacer esto y aún mantener una separación limpia de las capas de protocolo?

Para anclar mejor la discusión, digamos que los paquetes son típicamente alrededor de 2k y el procesador es un micro pequeño de 8 bits que se ejecuta a 8Mhz.

+0

8bit micro @ 8Mhz y un paquete de 2kB? No mencionaste el carnero disponible, pero supongo que el paquete lo llena bastante y claramente ejecutas un "proceso único", supongo que no veo la razón para crear tantas capas y abstracciones para un sistema tan simple. dividirlo en "transmisión de datos" y "aplicación" y pasar la carga a través de un puntero a un global. – Mark

+1

@Mark, la pila de protocolos se utilizará en diferentes plataformas, una es una Atmega1281 con 8 k ram. Se puede sincronizar a 20Mhz, pero no lo hacemos por razones de potencia. Podría relajar la separación de preocupaciones pero ese no es el punto de mi pregunta. – JeffV

+0

@Mark, tiene razón sobre el buffer 2k, probablemente no pueda ir tan grande, pero para esta aplicación cuanto más grande mejor, ya que es un canal de datos de alta latencia (satélite) y no planeo agregar ventanas (como se hace con TCP). – JeffV

Respuesta

7

podría evitar las copias haciendo que cada petición de la capa un búfer vacío de la capa inferior siguiente, en lugar de asignar uno mismo:

  • capa de aplicación solicita búfer longitud LA de capa de red.
  • La capa de red solicita la longitud del búfer LA + LN desde la capa de enlace de datos.
  • Datalink Layer solicita la longitud del búfer LA + LN + LD desde la capa física.
  • Capa física extrae un búfer del grupo de búferes.
  • Capa física devuelve buffer + phdr_len a Datalink Layer.
  • Datalink Layer devuelve buffer + phdr_len + dhdr_len a la Capa de red.
  • Capa de red devuelve buffer + phdr_len + dhdr_len + nhdr_len a Capa de aplicación.
  • La capa de aplicación completa los datos en el búfer proporcionado y llama a la capa de red para transmitir.
  • La capa de red prepara el encabezado y llama a Datalink Layer para transmitir.
  • Datalink Layer prepara el encabezado y llama a Physical Layer para transmitir.
  • La Capa física prepara el encabezado y lo pasa al hardware.
+0

O bien, los encabezados para las diferentes capas no necesitan estar contiguos (en un único búfer): en su lugar, podrían estar en diferentes búferes utilizando una API de "recopilación dispersa". – ChrisW

+0

Gracias @caf, estaba pensando en esto como una posible solución también. En el punto de la llamada get_buffer(), la capa superior se haría cargo del búfer. Tendría que haber un free_buffer() en cada capa además de un envío (pbuf) en caso de que algo salga mal para que el buffer pueda liberarse correctamente. – JeffV

0

En otras API he visto que los datos generalmente se pasan como un puntero de const con una longitud asociada. De esta manera, los datos necesitarían una operación de copia en cada capa, ya que la carga útil de la capa anterior se coloca en un búfer recién asignado para la capa actual.

Supongo que está dando un ejemplo de una API para un búfer de transmisión.

Creo que puede mantener la misma API, si agrega la restricción de que quien invoque esta API no puede usar o tocar ese búfer nuevamente hasta que reciba una notificación subsiguiente de que la operación de transmisión se ha completado: para invocar la API está transfiriendo implícitamente la propiedad de ese búfer.

4

Crear una estructura de búfer. Con el conocimiento del tamaño máximo en la capa inferior, asigne suficiente espacio de memoria intermedia en la capa superior para anteponer cada capa sucesiva a medida que desciende por la pila. Cada capa mueve el puntero en la estructura del búfer a medida que se agrega una capa.

En la capa inferior, el inicio del búfer se registra en el puntero de la estructura del búfer. Los datos que se enviarán están en un buffer contiguo. No se copiaron datos en cada capa.

Yendo de abajo hacia arriba se despegan las capas dentro de la estructura de la memoria intermedia.

+0

Este es el enfoque más simple, ya que solo requiere un búfer y no se puede copiar. Para un dispositivo esclavo, el búfer se define típicamente en la capa física, ya que es donde se originan los mensajes. –

+0

Y si tiene diferentes tipos de paquetes, solo necesita un puntero de estructura de otro tipo. –

+2

El problema con esto es que la capa superior necesita saber cuánto necesita cada capa inferior, que es el acoplamiento estrecho que OP intenta evitar (creo que eso era lo que hacía referencia a "separación limpia de las capas de protocolo") . – caf

Cuestiones relacionadas