2009-08-31 10 views
7

Pracuję nad prostym stosem protokołów dla małego systemu wbudowanego (typu multidrop, rs485). W tym stosie, losely modele po OSI warstw:Jak najlepiej radzić sobie z dużymi buforami w warstwowym stosie protokołów?

  1. aplikacji
  2. Network
  3. Datalink
  4. fizyczne (sterownik szeregowy)

Każda warstwa ma swoją własną część nagłówka/stopki, która owija ładunek warstwy nad nim.

Będę korzystał z własnej puli buforów statycznie przydzielonych bloków o stałej wielkości do przechowywania pakietów binarnych. (Bez malloc/free w tej aplikacji.)

W innych interfejsach API widziałem, że dane są zwykle przekazywane jako wskaźnik stały o powiązanej długości. W ten sposób dane będą wymagały operacji kopiowania na każdej warstwie, ponieważ ładunek powyższej warstwy zostanie umieszczony w nowo przydzielonym buforze dla bieżącej warstwy.

Dla stosu trzywarstwowego będą to 2 operacje kopiowania i 3 alokowane bufory.

Czy istnieje lepszy sposób na zrobienie tego i utrzymanie czystego rozdzielenia warstw protokołów?

Aby lepiej zakotwiczyć dyskusję, powiedzmy, że pakiety mają zwykle około 2k, a procesor to małe 8-bitowe mikroprzedsiębiorstwo działające z prędkością 8 MHz.

+0

Pakiet 8bit micro @ 8Mhz i pakiet 2kB? Nie wspomniałeś o dostępnej pamięci RAM, ale zgaduję, że pakiet prawie ją wypełnia, a twój wyraźnie działający "pojedynczy proces", wydaje mi się, że nie widzę powodu, by tworzyć tak wiele warstw i abstrakcji dla tak prostego systemu. podziel go na "transmisję danych" i "aplikację" i przeprowadź ładunek przez wskaźnik do globalnego. – Mark

+1

@ Mark, stos protokołów ma być używany na różnych platformach, jeden to Atmega1281 z 8k ramą. Może być taktowany z częstotliwością 20 Mhz, ale nie robimy tego z powodów związanych z zasilaniem. Mógłbym rozluźnić separację obaw, ale nie o to pytam. – JeffV

+0

@ Mark, masz rację co do bufora 2k, najprawdopodobniej nie będę w stanie zrobić tak dużego, ale dla tej aplikacji im większy tym lepiej, ponieważ jest to kanał danych o dużym opóźnieniu (satelita) i nie planuję dodawać windowing (jak to ma miejsce w przypadku TCP). – JeffV

Odpowiedz

7

Można uniknąć kopie poprzez każde żądanie warstwa pustym buforem od najbliższej dolnej warstwy, zamiast przydzielania jednego się:

  • Zastosowanie warstwy żąda bufor długości LA z warstwy sieciowej.
  • Warstwa sieci żąda długości bufora LA + LN z warstwy łącza danych.
  • Warstwa łącza danych żąda długości bufora LA + LN + LD z warstwy fizycznej.
  • Fizyczna warstwa pobiera bufor z puli buforów.
  • Fizyczna warstwa powraca buffer + phdr_len do warstwy łącza Datalink.
  • Warstwa warstwy łącza danych zwraca buffer + phdr_len + dhdr_len na warstwę sieci.
  • Warstwa sieciowa zwraca buffer + phdr_len + dhdr_len + nhdr_len do warstwy aplikacji.
  • Warstwa aplikacji wypełnia dane w podanym buforze i wywołuje warstwę sieci do przesłania.
  • Warstwa sieciowa wysyła nagłówek i wywołuje warstwę łącza danych do transmisji.
  • Warstwa łącza Datalink przedkłada nagłówek i wywołuje warstwę fizyczną do przesłania.
  • Fizyczna warstwa rozpoczyna nagłówek i przechodzi do sprzętu.
+0

Albo, nagłówki dla różnych warstw nie muszą być ciągłe (w pojedynczym buforze): zamiast tego mogą znajdować się w różnych buforach za pomocą API "scatter gather". – ChrisW

+0

Dzięki @cel, myślałem o tym również jako możliwym rozwiązaniu. W momencie wywołania get_buffer() górna warstwa będzie odpowiedzialna za bufor. Na każdej warstwie musi istnieć funkcja free_buffer(), a także send (pbuf) na wypadek, gdyby coś poszło nie tak, aby bufor mógł zostać poprawnie uwolniony. – JeffV

0

W innych interfejsach API widziałem, że dane są zwykle przekazywane jako wskaźnik stały o powiązanej długości. W ten sposób dane będą wymagały operacji kopiowania na każdej warstwie, ponieważ ładunek powyższej warstwy zostanie umieszczony w nowo przydzielonym buforze dla bieżącej warstwy.

Zgaduję, że podajesz przykład API dla bufora transmisji.

Myślę, że możesz zachować ten sam interfejs API, jeśli dodasz ograniczenie, że ten, kto wywoła ten interfejs API, nie będzie mógł go użyć, lub ponownie dotknie tego bufora, dopóki nie otrzyma kolejnego powiadomienia, że ​​operacja przesyłania zakończyła się: tak, że wywołanie API pośrednio przenosi własność tego bufora.

4

Utwórz strukturę bufora. Znając maksymalny rozmiar w dolnej warstwie, przydziel wystarczającą przestrzeń buforową w górnej warstwie, aby przedłużyć każdą kolejną warstwę, gdy idzie ona w dół stosu. Każda warstwa przesuwa wskaźnik w strukturze bufora podczas dodawania warstwy.

W dolnej warstwie początek bufora jest zapisywany w wskaźniku w strukturze bufora. Dane do wysłania znajdują się w ciągłym buforze. Żadne dane nie zostały skopiowane na każdej warstwie.

Przechodzenie od dołu do góry powoduje odrywanie warstw w strukturze bufora.

+0

Jest to najprostsze podejście, ponieważ wymaga tylko jednego bufora i nie wymaga kopiowania. W przypadku urządzenia podrzędnego bufor jest zazwyczaj definiowany w warstwie fizycznej, ponieważ tam pochodzą wiadomości. –

+0

A jeśli masz różne typy pakietów, po prostu powracasz do wskaźnika struktury innego typu. –

+2

Problem polega na tym, że górna warstwa musi wiedzieć, ile potrzebuje każda dolna warstwa, co jest ścisłym sprzężeniem, którego OP próbuje uniknąć (uważam, że właśnie o to chodziło w odniesieniu do "czystej separacji warstw protokołów") . – caf

Powiązane problemy