2009-08-31 3 views
7

Я работаю над простым стеком протокола для небольшой встроенной системы (многоточечный материал типа rs485). В этом стеке, losely модели после OSI слоев:Как лучше всего обрабатывать большие буферы в многоуровневом стеке протоколов?

  1. Применение
  2. Сеть
  3. Канальный
  4. физический (последовательный драйвер)

Каждый слой имеет свой собственный заголовок/нижнего колонтитула часть, которая обертывает полезная нагрузка слоя над ним.

Я буду использовать собственный буферный пул статически выделенных блоков фиксированного размера для хранения двоичных пакетов. (Нет malloc/free в этом приложении.)

В других API-интерфейсах я видел, что данные обычно передаются как указатель const со связанной длиной. Таким образом, данные потребуют операции копирования на каждом уровне, так как полезная нагрузка вышележащего уровня помещается в новый выделенный буфер для текущего слоя.

Для трехслойного стека это будет 2 операции копирования и 3 выделенных буфера.

Есть ли лучший способ сделать это и по-прежнему поддерживать чистое разделение уровней протокола?

Чтобы лучше зафиксировать обсуждение, скажем, что пакеты обычно составляют около 2 тыс., А процессор - это небольшой 8-битный микрофон, работающий на частоте 8 МГц.

+0

8bit micro @ 8Mhz и 2kB пакет? Вы не упомянули о доступном баре, но я бы предположил, что пакет в значительной степени заполняет его, и вы четко выполняете «единый процесс», я думаю, я не вижу причины создавать столько слоев и абстракций для такой простой системы. разбить его на «передачу данных» и «приложение» и передать полезную нагрузку с помощью указателя на глобальный. – Mark

+1

@Mark, стек протоколов должен использоваться на разных платформах, один из них - Atmega1281 с 8k RAM. Он может быть синхронизирован с частотой 20 МГц, но мы не делаем этого по соображениям мощности. Я мог бы расслабить разделение проблем, но это не вопрос моего вопроса. – JeffV

+0

@Mark, вы правы в отношении 2k-буфера, я, скорее всего, не смогу пройти так много, но для этого приложения тем лучше, так как это канал с высокой задержкой (спутник), и я не планирую добавлять windowing (как это делается с TCP). – JeffV

ответ

7

Вы могли бы избежать при наличии копий каждого запроса на слое пустой буфер из следующего нижнего слоя, а не выделение одного себя:

  • прикладного уровня запрашивает буфер длину LA от сетевого уровня.
  • Сетевой слой запрашивает длину буфера LA + LN из слоя Datalink.
  • Datalink Layer запрашивает длину буфера LA + LN + LD с физического уровня.
  • Физический уровень вытягивает буфер из пула буферов.
  • Физический уровень возвращает buffer + phdr_len в Datalink Layer.
  • Datalink Layer возвращает buffer + phdr_len + dhdr_len в сетевой уровень.
  • Сетевой слой возвращает buffer + phdr_len + dhdr_len + nhdr_len в прикладной уровень.
  • Application Layer заполняет данные в предоставленном буфере и вызывает сетевой уровень для передачи.
  • Сетевой слой добавляет заголовок и вызывает уровень Datalink Layer для передачи.
  • Datalink Layer добавляет заголовок и вызывает физический уровень для передачи.
  • Физический уровень добавляет заголовок и переходит к оборудованию.
+0

Или заголовки для разных слоев не обязательно должны быть смежными (в одном буфере): вместо этого они могут быть в разных буферах, используя API-интерфейс «собирать рассеяние». – ChrisW

+0

Спасибо @caf, я думал об этом как о возможном решении. В точке вызова get_buffer() верхний уровень берет на себя ответственность за буфер. В дополнение к отправке (pbuf) на каждый уровень должен быть добавлен free_buffer(), если что-то пойдет не так, чтобы буфер можно было правильно освободить. – JeffV

0

В других API-интерфейсах я видел, что данные обычно передаются как указатель const со связанной длиной. Таким образом, данные потребуют операции копирования на каждом уровне, так как полезная нагрузка вышележащего уровня помещается в новый выделенный буфер для текущего слоя.

Я предполагаю, что вы приводите пример API для буфера передачи.

Я думаю, что вы можете сохранить один и тот же API, если вы добавите ограничение того, что тот, кто вызывает этот API, не может использовать или касаться этого буфера снова, пока не получит последующее уведомление о завершении операции передачи: API неявно передает право собственности на этот буфер.

4

Создать структуру буфера. Со знанием максимального размера в нижнем слое выделите достаточное пространство буфера на верхнем уровне, чтобы добавить каждый последующий слой, когда он идет вниз по стеку. Каждый слой перемещает указатель в структуру буфера при добавлении слоя.

В нижнем слое начало буфера записывается в указателе в структуре буфера. Данные, которые нужно отправить, находятся в смежном буфере. На каждом слое не было скопировано никаких данных.

Идя снизу вверх, вы снимаете слои в структуре буфера.

+0

Это самый простой подход, так как он требует только одного буфера и копирования. Для подчиненного устройства буфер обычно определяется на физическом уровне, так как в этом случае возникают сообщения. –

+0

И если у вас разные типы пакетов, вы просто заново структурируете указатель структуры другого типа. –

+2

Проблема заключается в том, что верхний слой должен знать, сколько нужно каждому нижнему уровню, а именно тесная связь, которую пытается избежать OP (я считаю, что это была ссылка на «чистое разделение уровней протокола») , – caf

Смежные вопросы