2009-08-31 16 views
7

Sto lavorando su un semplice stack di protocollo per un piccolo sistema embedded (roba di tipo multidrop, rs485). In questo stack, modelli losely dopo livelli OSI:Come gestire al meglio i buffer di grandi dimensioni in uno stack di protocolli con livelli?

  1. applicazione
  2. rete
  3. Datalink
  4. fisico (driver seriale)

Ogni strato ha la propria parte di intestazione/piè avvolge il carico utile dello strato sopra di esso.

Utilizzerò il mio pool di buffer di blocchi di dimensioni fisse allocati staticamente per archiviare i pacchetti binari. (No malloc/free in questa app.)

In altre API ho visto che i dati vengono solitamente passati come puntatore const con una lunghezza associata. In questo modo i dati necessiterebbero di un'operazione di copia su ciascun livello, in quanto il carico utile del livello precedente viene collocato in un buffer appena assegnato per il livello corrente.

Per uno stack a tre livelli ci sarebbero 2 operazioni di copia e 3 buffer allocati.

Esiste un modo migliore per eseguire questa operazione mantenendo una separazione netta dei livelli del protocollo?

Per ancorare meglio la discussione, diciamo che i pacchetti sono in genere intorno a 2k e il processore è un piccolo micro 8 bit che gira a 8Mhz.

+0

8bit micro @ 8Mhz ee 2kB pacchetto? Non hai menzionato la ram disponibile, ma immagino che il pacchetto lo riempia e il tuo chiaramente eseguendo un "singolo processo" credo non riesca a vedere il motivo per creare così tanti livelli e astrazioni per un sistema così semplice. infrangerlo in "trasmissione dati" e "applicazione" e passare il carico utile tramite un puntatore a un globale. – Mark

+1

@Mark, lo stack di protocollo deve essere utilizzato su piattaforme diverse, uno è un Atmega1281 con 8k ram. Può essere sincronizzato a 20 Mhz, ma non lo facciamo per motivi di potenza. Potrei rilassare la separazione delle preoccupazioni ma non è questo il punto della mia domanda. – JeffV

+0

@Mark, hai ragione riguardo al buffer 2k, molto probabilmente non sarò in grado di andare così grande, ma per questa app tanto più grande quanto migliore è il canale dati ad alta latenza (satellite) e non ho intenzione di aggiungere windowing (come si fa con TCP). – JeffV

risposta

7

si potrebbe evitare le copie avendo ciascuna richiesta strato un buffer vuoto dal successivo strato inferiore, piuttosto che l'attribuzione di un sé:

  • Application Layer richiede tampone lunghezza LA da Network Layer.
  • Il livello di rete richiede la lunghezza del buffer LA + LN dal livello Datalink.
  • Il livello di collegamento dati richiede la lunghezza del buffer LA + LN + LD dal livello fisico.
  • Physical Layer estrae un buffer dal pool di buffer.
  • Physical Layer restituisce buffer + phdr_len in livello Datalink.
  • Il livello di collegamento dati restituisce buffer + phdr_len + dhdr_len al livello di rete.
  • Il livello di rete restituisce buffer + phdr_len + dhdr_len + nhdr_len al livello applicazione.
  • Il livello applicazione compila i dati nel buffer fornito e chiama Network Layer per trasmettere.
  • Il livello di rete anteporre l'intestazione e chiama Datalink Layer da trasmettere.
  • Il livello di collegamento dati antepone l'intestazione e chiama il livello fisico da trasmettere.
  • Physical Layer prepara l'intestazione e passa all'hardware.
+0

Oppure, le intestazioni per i diversi livelli non devono essere contigue (in un singolo buffer): invece potrebbero essere in buffer differenti utilizzando un'API "scatter gather". – ChrisW

+0

Grazie a @ CAF, stavo pensando anche a questa come possibile soluzione. Al punto della chiamata get_buffer() il livello superiore si assumerebbe la responsabilità del buffer. Dovrebbe esserci un free_buffer() su ogni livello oltre a un send (pbuf) nel caso qualcosa vada storto, in modo che il buffer possa essere liberato correttamente. – JeffV

0

In altre API ho visto che i dati vengono solitamente passati come puntatore const con una lunghezza associata. In questo modo i dati necessiterebbero di un'operazione di copia su ciascun livello, in quanto il carico utile del livello precedente viene collocato in un buffer appena assegnato per il livello corrente.

Suppongo che tu stia fornendo un esempio di API per un buffer di trasmissione.

Penso che sia possibile mantenere la stessa API, se si aggiunge la restrizione che chiunque invochi questa API non può utilizzare o toccare nuovamente quel buffer fino a quando non ricevono una notifica successiva che l'operazione di trasmissione è stata completata: in modo che il richiamo l'API trasferisce implicitamente la proprietà di quel buffer.

4

Creare una struttura di buffer. Conoscenza della dimensione massima al livello inferiore, allocare uno spazio sufficiente del buffer sul livello superiore per anteporre ogni strato successivo mentre scende nello stack. Ogni livello sposta il puntatore nella struttura del buffer quando viene aggiunto un livello.

Sul livello inferiore, l'inizio del buffer viene registrato nel puntatore nella struttura del buffer. I dati da inviare si trovano in un buffer contiguo. Nessun dato è stato copiato su ogni livello.

Passando dal basso verso l'alto si staccano gli strati all'interno della struttura del buffer.

+0

Questo è l'approccio più semplice, in quanto richiede solo un buffer e nessuna copia. Per un dispositivo slave, il buffer viene in genere definito nel livello fisico, in quanto è lì che i messaggi hanno origine. –

+0

E se si hanno diversi tipi di pacchetti, basta ritorcere il puntatore di struttura di un altro tipo. –

+2

Il problema con questo è che lo strato superiore deve sapere quanto ha bisogno di ogni strato inferiore, che è l'accoppiamento stretto che l'OP sta tentando di evitare (credo che sia stato il riferimento alla "separazione pulita dei livelli del protocollo") . – caf

Problemi correlati