Это команда ns-3-manual, которую можно запустить в бесплатном хостинг-провайдере OnWorks, используя одну из наших многочисленных бесплатных онлайн-рабочих станций, таких как Ubuntu Online, Fedora Online, онлайн-эмулятор Windows или онлайн-эмулятор MAC OS.
ПРОГРАММА:
ИМЯ
нс-3-мануал - нс-3 мануал
Это нс-3 Ручная. Первичная документация по проекту НС-3 имеется в пяти
формы:
· нс-3 Доксиген: Документация общедоступных API симулятора.
· Учебное пособие, руководство (этот документ), и Библиотека моделей для последний освободить и
способствовали дерево
· нс-3 Вики
СОДЕРЖАНИЕ
организация
В этой главе описывается общая нс-3 организация программного обеспечения и соответствующие
организация этого руководства.
нс-3 представляет собой симулятор сети с дискретными событиями, в котором ядро симуляции и модели
реализован на C ++. нс-3 построен как библиотека, которая может быть статической или динамической
связан с основной программой C ++, которая определяет топологию моделирования и запускает
Тренажер. нс-3 также экспортирует почти весь свой API в Python, позволяя программам Python
импортировать модуль "ns3" почти так же, как нс-3 библиотека связана исполняемыми файлами
в C ++.
[image] Программная организация нс-3.НЕИНДЕНТ
Исходный код для нс-3 в основном организована в SRC каталог и может быть описан
по диаграмме в ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ организация of нс-3. Мы будем работать снизу
вверх; как правило, модули зависят только от модулей, находящихся под ними на рисунке.
Сначала опишем суть симулятора; те компоненты, которые являются общими для всех
модели протокола, оборудования и окружающей среды. Ядро моделирования реализовано в
SRC / ядро. Пакеты являются фундаментальными объектами сетевого симулятора и реализуются в
SRC / сеть. Эти два модуля моделирования сами по себе предназначены для
общее ядро моделирования, которое может использоваться в различных типах сетей, а не только
Интернет-сети. Вышеупомянутые модули нс-3 не зависят от конкретной сети
и модели устройств, которые описаны в последующих частях данного руководства.
В дополнение к вышесказанному нс-3 ядро, мы вводим, также в начальной части
manual, два других модуля, которые дополняют основной API на основе C ++. нс-3 программы могут
доступ ко всему API напрямую или может использовать так называемый помощник API что обеспечивает
удобные оболочки или инкапсуляция низкоуровневых вызовов API. Дело в том, что нс-3 программы
может быть записан в два API (или их комбинацию) является фундаментальным аспектом
симулятор. Мы также описываем, как Python поддерживается в нс-3 прежде чем перейти к конкретным
модели, имеющие отношение к сетевому моделированию.
Остальная часть руководства посвящена документированию моделей и поддержке
возможности. Следующая часть посвящена двум фундаментальным объектам в нс-3: Узел и
NetDevice. Два специальных типа NetDevice предназначены для поддержки использования эмуляции сети.
случаи, и эмуляция описана далее. Следующая глава посвящена
Связанные с Интернетом модели, включая API-интерфейс сокетов, используемый Интернет-приложениями. В
в следующей главе рассматриваются приложения, а в следующей главе описывается дополнительная поддержка.
для моделирования, например аниматоров и статистики.
В проекте есть отдельное руководство, посвященное тестированию и валидации нс-3 код
(См нс-3 Тестирование и Проверка руководство).
Случайно Переменные
нс-3 содержит встроенный генератор псевдослучайных чисел (ГПСЧ). Это важно для
серьезные пользователи симулятора, чтобы понять функциональность, конфигурацию и использование
этого ГПСЧ и решить, достаточно ли этого для его или ее исследовательского использования.
САЙТ Обзор
нс-3 случайные числа предоставляются через экземпляры ns3 :: RandomVariableStream.
· по умолчанию, нс-3 в симуляциях используется фиксированное начальное число; если есть какая-то случайность в
моделирование, каждый запуск программы будет давать идентичные результаты, если только начальное и / или
номер прогона изменен.
· в нс-3.3 и раньше, нс-3 по умолчанию в симуляциях используется случайное начальное число; это знаменует собой
изменение политики, начиная с нс-3.4.
· в нс-3.14 и раньше, нс-3 при моделировании использовался другой класс-оболочка, называемый
ns3 :: RandomVariable, По состоянию на нс-3.15, этот класс был заменен на
ns3 :: RandomVariableStream; базовый генератор псевдослучайных чисел не
изменилось.
· Чтобы получить случайность в нескольких прогонах моделирования, вы должны либо установить начальное значение
по-другому или установите другой номер цикла. Чтобы установить семя, позвоните
ns3 :: RngSeedManager :: SetSeed () в начале программы; установить номер прогона с помощью
то же семя, позвони ns3 :: RngSeedManager :: SetRun () в начале программы; видеть
Создающий случайный переменные.
· Каждый RandomVariableStream, используемый в нс-3 связан с виртуальным генератором случайных чисел
с этим; все случайные переменные используют фиксированное или случайное начальное число в зависимости от использования
глобальное семя (предыдущий пункт);
· Если вы собираетесь выполнить несколько запусков одного и того же сценария с разными случайными
числа, обязательно прочтите раздел о том, как выполнять независимые репликации:
Создающий случайный переменные.
Читайте дальше, чтобы узнать больше о функции случайных чисел для нс-3.
проверка данных
В симуляциях используется много случайных чисел; одно исследование показало, что большинство сетевых симуляций
тратить до 50% ресурсов ЦП на генерацию случайных чисел. Пользователи моделирования должны быть
касается качества (псевдо) случайных чисел и независимости между
разные потоки случайных чисел.
Пользователям необходимо решить несколько вопросов, например:
· Заполнение генератора случайных чисел и определение того, является ли результат моделирования
детерминированный или нет,
· Как получить разные потоки случайных чисел, не зависящих от одного
другой, и
· Сколько времени требуется для циклического цикла потоков
Мы введем здесь несколько терминов: ГСЧ предоставляет длинную последовательность (псевдо) случайных
числа. Длина этой последовательности называется цикл or период, после которого
ГСЧ повторится. Эту последовательность можно разбить на непересекающиеся потоки,
поток ГСЧ является непрерывным подмножеством или блоком последовательности ГСЧ. Например, если
Период ГСЧ имеет длину N, и из этого ГСЧ поступают два потока, затем первый
поток может использовать первые значения N / 2, а второй поток может создавать вторые значения N / 2
ценности. Важным свойством здесь является то, что два потока некоррелированы. Так же,
каждый поток можно разделить несвязно на несколько некоррелированных субпотоки,
лежащий в основе ГСЧ, мы надеемся, производит псевдослучайную последовательность чисел с очень длинным
продолжительность цикла и эффективно разбивает его на потоки и подпотоки.
нс-3 использует тот же базовый генератор случайных чисел, что и нс-2: MRG32k3a
генератор от Pierre L'Ecuyer. Подробное описание можно найти в
http://www.iro.umontreal.ca/~lecuyer/myftp/papers/streams00.pdf. Генератор MRG32k3a
предоставляет 1.8x10 ^ {19} независимых потоков случайных чисел, каждый из которых состоит из
2.3x10 ^ {15} субпотоков. У каждого субпотока есть точка (т.е., количество случайных чисел
перед перекрытием) 7.6х10 ^ {22}. Период всего генератора составляет 3.1x10 ^ {57}.
Класс ns3 :: RandomVariableStream является общедоступным интерфейсом к этому базовому случайному числу
генератор. Когда пользователи создают новые случайные величины (например, ns3 :: UniformRandomVariable,
ns3 :: ExponentialRandomVariableи т. д.), они создают объект, использующий один из
отдельные, независимые потоки генератора случайных чисел. Следовательно, каждый объект
напишите ns3 :: RandomVariableStream концептуально имеет собственный «виртуальный» ГСЧ. Более того,
каждый ns3 :: RandomVariableStream может быть настроен для использования одного из набора нарисованных субпотоков
от основного потока.
Альтернативная реализация могла бы позволить каждой RandomVariable иметь свою собственную
(по-разному сеяны) ГСЧ. Однако мы не можем гарантировать, что разные
в таком случае последовательности будут некоррелированными; следовательно, мы предпочитаем использовать один ГСЧ и
потоки и подпотоки из него.
Создающий случайный переменные
нс-3 поддерживает ряд объектов случайных величин из базового класса
СлучайныйПеременныйПоток. Эти объекты происходят от ns3 :: Объект и обрабатываются умными
указатели.
Правильный способ создания этих объектов - использовать шаблонный CreateObject <> Метод,
, таких как:
Ptr x = CreateObject ();
тогда вы можете получить доступ к значениям, вызвав такие методы объекта, как:
myRandomNo = x-> GetInteger ();
Если вместо этого вы попытаетесь сделать что-то вроде этого:
myRandomNo = UniformRandomVariable (). GetInteger ();
ваша программа столкнется с ошибкой сегментации, потому что реализация полагается на
некоторая конструкция атрибута, которая возникает только тогда, когда CreateObject называется.
Большая часть остальной части этой главы теперь обсуждает свойства потока
псевдослучайные числа, сгенерированные из таких объектов, и как управлять раздачей таких
объекты.
Посев и независимые репликации
нс-3 моделирование можно настроить для получения детерминированных или случайных результатов. Если
нс-3 симуляция настроена на использование фиксированного, детерминированного начального числа с тем же номером прогона,
он должен выдавать один и тот же результат при каждом запуске.
По умолчанию нс-3 при моделировании используются фиксированные начальное число и номер прогона. Эти значения хранятся в
два ns3 :: GlobalValue экземпляры: g_rngSeed и g_rngRun.
Типичный вариант использования - запустить моделирование как последовательность независимых испытаний, чтобы
вычислять статистику по большому количеству независимых прогонов. Пользователь может либо изменить
глобальное семя и перезапустить симуляцию, или может продвинуть состояние субпотока ГСЧ, которое
называется увеличением номера цикла.
Класс ns3 :: RngSeedManager предоставляет API для управления раздачей и номером запуска
поведение. Эта настройка состояния заполнения и субпотока должна вызываться перед любым случайным
создаются переменные; например:
RngSeedManager :: SetSeed (3); // Изменяет начальное число со значения по умолчанию 1 на 3
RngSeedManager :: SetRun (7); // Изменяет номер прогона с 1 по умолчанию на 7
// Теперь создадим случайные переменные
Ptr x = CreateObject ();
Ptr y = CreateObject ();
...
Что лучше: установка нового начального числа или продвижение состояния подпотока? Здесь нет
гарантировать, что потоки, создаваемые двумя случайными начальными числами, не будут перекрываться. Единственный способ
гарантия того, что два потока не перекрываются, заключается в использовании возможности субпотока, предоставляемой
реализация ГСЧ. Следовательно, использование подпоток возможности в производит с разными
независимые работает of то же моделирование. Другими словами, более статистически строгие
способ настройки нескольких независимых репликаций - использовать фиксированное начальное число и продвигать
номер прогона. Эта реализация допускает максимум 2.3x10 ^ {15} независимых
репликации с использованием подпотоков.
Для простоты использования нет необходимости контролировать количество семян и количество прогонов изнутри
программа; пользователь может установить NS_GLOBAL_VALUE переменная окружения следующим образом:
$ NS_GLOBAL_VALUE = "RngRun = 3" ./waf --run имя-программы
Другой способ контролировать это - передать аргумент командной строки; так как это нс-3
GlobalValue, это делается примерно так:
$ ./waf --command-template = "% s --RngRun = 3" --run имя-программы
или, если вы запускаете программы непосредственно вне waf:
$ ./build/optimized/scratch/program-name --RngRun = 3
Вышеупомянутые варианты командной строки позволяют легко запускать множество различных запусков из оболочки.
скрипт, просто передав другой индекс RngRun.
Класс СлучайныйПеременныйПоток
Все случайные величины должны происходить из класса Случайная переменная. Этот базовый класс предоставляет
несколько методов глобальной настройки поведения генератора случайных чисел. Полученный
классы предоставляют API для отрисовки случайных значений из конкретного распределения, являющегося
поддерживается.
Каждому RandomVariableStream, созданному в симуляции, дается генератор, который является новым
RNGStream из базового ГПСЧ. Таким образом, реализация L'Ecuyer
позволяет использовать не более 1.8x10 ^ 19 случайных величин. Каждая случайная величина в одном
репликация может производить до 7.6x10 ^ 22 случайных чисел перед перекрытием.
Система исчисления класс что такое варган? API
Ниже приведены несколько публичных методов класса. СлучайныйПеременныйПоток которые имеют доступ к
следующее значение в подпотоке.
/ **
* \ short Возвращает случайное значение типа double из базового распределения.
* \ return Случайное значение с плавающей запятой
*/
двойной GetValue (недействительным) const;
/ **
* \ short Возвращает случайное целое число из базового распределения.
* \ return Целочисленное приведение :: GetValue ()
*/
uint32_t GetInteger (пусто) const;
Конфигурацию раздачи мы уже описывали выше. Другая случайная переменная
подклассы могут иметь дополнительный API.
Тип of Случайные переменные
Предусмотрены следующие типы случайных величин, которые задокументированы в нс-3
Doxygen или читая SRC / ядро / модель / случайная-переменная-stream.h. Пользователи также могут создавать
свои собственные произвольные случайные переменные, производные от класса СлучайныйПеременныйПоток.
· класс Равномерное Случайное Переменное
· класс КонстантаСлучайнаяПеременная
· класс Последовательная случайная переменная
· класс Экспоненциальная случайная переменная
· класс ПаретоСлучайная переменная
· класс WeibullСлучайнаяПеременная
· класс НормальныйСлучайныйПеременная
· класс ЖурналОбычныйСлучайнаяПеременная
· класс ГаммаСлучайнаяПеременная
· класс ErlangСлучайнаяПеременная
· класс ТреугольныйСлучайныйПеременный
· класс ZipfСлучайнаяПеременная
· класс ЗетаСлучайнаяПеременная
· класс ДетерминированнаяСлучайная переменная
· класс Эмпирическая случайная переменная
Семантика of СлучайныйПеременныйПоток объекты
Объекты RandomVariableStream являются производными от ns3 :: Объект и обрабатываются умными указателями.
Экземпляры RandomVariableStream также можно использовать в нс-3 атрибуты, что означает, что
значения могут быть установлены для них через нс-3 система атрибутов. Пример есть в
модели распространения для WifiNetDevice:
Идентификатор типа
RandomPropagationDelayModel :: GetTypeId (недействительно)
{
статический TypeId tid = TypeId ("ns3 :: RandomPropagationDelayModel")
.SetParent ()
.AddConstructor ()
.AddAttribute ("Переменная",
«Случайная величина, вызывающая случайные задержки.»,
StringValue ("ns3 :: UniformRandomVariable"),
MakePointerAccessor (& RandomPropagationDelayModel :: m_variable),
MakePointerChecker ())
;
вернуть tid;
}
Здесь нс-3 пользователь может изменить случайную переменную по умолчанию для этой модели задержки (которая
UniformRandomVariable в диапазоне от 0 до 1) через систему атрибутов.
. другими ПСЧ
В настоящее время нет поддержки для замены другого базового случайного числа.
генератор (например, Научная библиотека GNU или пакет Akaroa). Патчи приветствуются.
настройка поток номер
Базовый генератор MRG32k3a обеспечивает 2 ^ 64 независимых потока. В нс-3 это
назначаются последовательно, начиная с первого потока, как новые экземпляры RandomVariableStream
сделать свой первый вызов GetValue ().
В результате того, как эти объекты RandomVariableStream назначаются базовым потокам,
назначение чувствительно к возмущениям конфигурации моделирования. В
Следствием этого является то, что при изменении любого аспекта конфигурации моделирования отображение
of RandomVariables к потокам может (или не может) измениться.
В качестве конкретного примера, пользователь, выполняющий сравнительное исследование протоколов маршрутизации, может
обнаруживают, что при изменении одного протокола маршрутизации на другой будет замечено, что
основная модель мобильности также изменилась.
Начиная с ns-3.15, пользователям был предоставлен некоторый контроль, позволяющий пользователям
при необходимости исправить присвоение выбранных объектов RandomVariableStream базовым
потоки. Это Поток атрибут, часть базового класса RandomVariableStream.
Разделив существующую последовательность потоков из предыдущего:
<------------------------------------------------- ------------------------->
поток 0 поток (2 ^ 64-1)
на два набора одинакового размера:
<------------------------------------------------- ------------------------->
^ ^ ^ ^
| || |
поток 0 поток (2 ^ 63-1) поток 2 ^ 63 поток (2 ^ 64-1)
<- назначается автоматически -----------> <- назначается пользователем ----------------->
Первые 2 ^ 63 потока по-прежнему назначаются автоматически, а последние 2 ^ 63 -
заданные индексы потока от нуля до 2 ^ 63-1.
Назначение потоков фиксированному номеру потока необязательно; экземпляры
RandomVariableStream, которым не присвоено значение потока, будет назначен следующий
один из пула автоматических потоков.
Чтобы исправить RandomVariableStream конкретному базовому потоку, назначьте его Поток
атрибут к неотрицательному целому числу (значение по умолчанию -1 означает, что значение будет
автоматически выделяется).
Публикация Результаты
Когда вы публикуете результаты моделирования, ключевую информацию о конфигурации, которую вы
всегда следует указывать, как вы использовали генератор случайных чисел.
· Какие семена вы использовали,
· Какой ГСЧ вы использовали, если не по умолчанию,
· Как проводились независимые прогоны,
· Для больших симуляций, как вы проверяли, что вы не выполняете цикл.
Исследователь, публикующий результаты, должен включать в себя достаточно информации, чтобы
позволить другим воспроизвести его или ее результаты. Исследователь также обязан
убедить себя, что использованные случайные числа были статистически достоверными, и заявить в
документ, почему предполагается такая уверенность.
Итого
Давайте рассмотрим, что вам следует делать при создании симуляции.
· Решите, используете ли вы фиксированное или случайное начальное число; фиксированное семя - это
по умолчанию,
· Решите, как вы собираетесь управлять независимыми репликациями, если применимо,
· Убедите себя, что вы не рисуете больше случайных значений, чем длина цикла, если
вы запускаете очень долгое моделирование, и
· При публикации следуйте приведенным выше рекомендациям по документированию использования случайных
генератор чисел.
Hash функции
нс-3 предоставляет общий интерфейс для хэш-функций общего назначения. В простейшем
При использовании хеш-функция возвращает 32-битный или 64-битный хэш буфера данных или строки.
Базовая хеш-функция по умолчанию: шум3, выбрано, потому что у него хорошая хэш-функция
properties и предлагает 64-битную версию. Почтенный ФНВ1а также доступен хэш.
Существует простой механизм добавления (или предоставления во время выполнения) альтернативного хеша.
реализации функций.
Базовый Применение
Самый простой способ получить хеш-значение буфера данных или строки:
#include "ns3 / hash.h"
используя пространство имен ns3;
символ * буфер = ...
size_t buffer_size = ...
uint32_t buffer_hash = Hash32 (буфер, размер_буфера);
std :: string s;
uint32_t string_hash = Hash32 (s);
Эквивалентные функции определены для 64-битных хеш-значений.
Дополнительный хеширования
В некоторых ситуациях полезно вычислять хэш нескольких буферов, как если бы они
были объединены. (Например, вам может понадобиться хэш потока пакетов, но не
хотите собрать единый буфер с объединенным содержимым всех пакетов.)
Это почти так же просто, как и в первом примере:
#include "ns3 / hash.h"
используя пространство имен ns3;
char * буфер;
размер_t размер_буфера;
Хашер хешер; // Использовать хеш-функцию по умолчанию
за ( )
{
буфер = get_next_buffer ();
хешер (буфер, размер_буфера);
}
uint32_tcommon_hash = hasher.GetHash32 ();
По умолчанию мясорубка сохраняет внутреннее состояние для включения инкрементного хеширования. Если хотите
повторно использовать мясорубка объект (например, потому что он настроен с хешем не по умолчанию
функция), но не хотите добавлять к ранее вычисленному хешу, вам необходимо Чисто()
первый:
hasher.clear () .GetHash32 (буфер, размер_буфера);
Это повторно инициализирует внутреннее состояние перед хешированием буфера.
. an Альтернатива Hash Функция
Хеш-функция по умолчанию: шум3. ФНВ1а также доступен. Чтобы указать хеш
явно используйте этот конструктор:
Хашер хешер = Хашер (Создать ());
Добавление Новое Hash Функция Реализации
Чтобы добавить хеш-функцию Foo следуйте по хэш-мурмур3.ч/.cc шаблон:
· Создайте объявление класса (.h) и определение (.cc) наследование от
Хэш :: Реализация.
· включают декларация в хэш.ч (в точке, где хэш-мурмур3.ч Включено.
· В собственном коде создайте экземпляр мясорубка объект через конструктор мясорубка
(Птр ())
Если ваша хеш-функция является единственной функцией, например хэш, вам даже не нужно создавать
новый класс, производный от HashImplementation:
Хашер хешер =
Хашер (Создать (& hashf));
Для этого ваш хэш должен соответствовать одной из сигнатур указателя на функцию:
typedef uint32_t (* Hash32Function_ptr) (const char *, const size_t);
typedef uint64_t (* Hash64Function_ptr) (const char *, const size_t);
Источники для Hash функции
Источники для других реализаций хэш-функции включают:
· Питер Канковски: http://www.strchr.com
· Араш Партоу: http://www.partow.net/programming/hashfunctions/index.html
· СМХашер: http://code.google.com/p/smhasher/
· Санмейси: http://www.sanmayce.com/Fastest_Hash/index.html
Мероприятия и Симулятор
нс-3 представляет собой симулятор сети с дискретными событиями. Концептуально симулятор отслеживает
количество событий, которые запланированы для выполнения в указанное время моделирования. Работа
симулятор должен выполнять события в последовательном временном порядке. После завершения
происходит событие, симулятор перейдет к следующему событию (или выйдет, если нет
больше событий в очереди событий). Если, например, событие, запланированное на время моделирования
«100 секунд» выполняется, и следующее событие не планируется до «200 секунд»,
симулятор немедленно перескочит со 100 секунд на 200 секунд (времени симуляции), чтобы
выполнить следующее событие. Вот что подразумевается под симулятором "дискретных событий".
Чтобы все это произошло, симулятору нужно несколько вещей:
1. объект симулятора, который может получить доступ к очереди событий, в которой хранятся события, и который может
управлять исполнением событий
2. планировщик, отвечающий за вставку и удаление событий из очереди
3. способ представления времени моделирования
4. сами события
В этой главе руководства описаны эти фундаментальные объекты (симулятор, планировщик,
время, событие) и как они используются.
События
к be завершенный
Симулятор
Класс Simulator - это общедоступная точка входа для доступа к средствам планирования событий. Один раз
запланировано несколько событий для запуска симуляции, пользователь может начать
выполнить их, войдя в основной цикл симулятора (вызовите Симулятор :: Беги). Как только основной цикл
начинает работать, он будет последовательно выполнять все запланированные события в порядке от самого старого к
самое последнее, пока в очереди событий не останется событий или
Simulator :: Stop был вызван.
Чтобы запланировать события для выполнения основным циклом симулятора, класс Simulator предоставляет
Семейство функций Simulator :: Schedule *.
1. Обработка обработчиков событий с разными сигнатурами
Эти функции объявлены и реализованы как шаблоны C ++ для автоматической обработки
широкий спектр сигнатур обработчиков событий C ++, используемых в дикой природе. Например, чтобы запланировать
событие для выполнения 10 секунд в будущем и вызвать метод или функцию C ++ с
конкретные аргументы, вы можете написать это:
обработчик void (int arg0, int arg1)
{
std :: cout << "вызывается обработчик с аргументом arg0 =" << arg0 << "и
arg1 = "<< arg1 << std :: endl;
}
Симулятор :: Расписание (Секунд(10), & обработчик, 10, 5);
Что выведет:
обработчик вызывается с аргументом arg0 = 10 и arg1 = 5
Конечно, эти шаблоны C ++ также могут прозрачно обрабатывать методы-члены на C ++.
объекты:
к be завершенный: член метод пример
Ноты:
· Методы расписания ns-3 автоматически распознают функции и методы, только если они
взять менее 5 аргументов. Если вам нужно, чтобы они поддерживали больше аргументов, пожалуйста, отправьте
отчет об ошибке.
· Читатели, знакомые с термином «полностью связанные функторы», узнают
Simulator :: Schedule методы как способ автоматического создания таких объектов.
2. Общие операции планирования
Simulator API был разработан, чтобы упростить планирование большинства событий. Это
предоставляет три варианта для этого (в порядке от наиболее часто используемого до наименее часто используемого):
· Методы расписания, которые позволяют запланировать мероприятие в будущем, предоставляя
задержка между текущим временем моделирования и датой истечения целевого события.
· Методы ScheduleNow, которые позволяют запланировать событие для текущего моделирования
время: они будут выполняться _после_ выполнения текущего события, но _перед_
время моделирования изменено на следующее событие.
· Методы ScheduleDestroy, которые позволяют подключиться к процессу выключения Симулятора.
для очистки ресурсов моделирования: каждое событие «уничтожить» выполняется, когда пользователь вызывает
метод Simulator :: Destroy.
3. Поддержание контекста моделирования
Есть два основных способа запланировать события: с и без контекст, Что делает это
значит?
Simulator :: Schedule (Постоянная времени и время, MEM mem_ptr, OBJ obj);
против
Simulator :: ScheduleWithContext (контекст uint32_t, константа времени и время, MEM mem_ptr, OBJ obj);
Читатели, которые вкладывают время и силы в разработку или использование нетривиальной имитационной модели
будет знать значение фреймворка ns-3 для отладки простых и сложных симуляций
одинаково. Одной из важных функций, предоставляемых этой структурой ведения журналов, является
автоматическое отображение идентификатора сетевого узла, связанного с текущим запущенным событием.
Идентификатор текущего исполняемого сетевого узла фактически отслеживается Симулятором.
класс. Доступ к нему можно получить с помощью метода Simulator :: GetContext, который возвращает
«контекст» (32-битное целое число), связанный и хранящийся в текущем исполняемом событии. В
некоторые редкие случаи, когда событие не связано с конкретным сетевым узлом, его
'context' установлен в 0xffffffff.
Чтобы связать контекст с каждым событием, методы Schedule и ScheduleNow автоматически
повторно использовать контекст текущего выполняемого события в качестве контекста запланированного события
для исполнения позже.
В некоторых случаях, особенно при моделировании передачи пакета от узла к
во-вторых, такое поведение нежелательно, поскольку ожидаемый контекст события приема
узел-получатель, а не узел-отправитель. Чтобы избежать этой проблемы, Симулятор
класс предоставляет специальный метод расписания: ScheduleWithContext, который позволяет предоставлять
явно идентификатор узла принимающего узла, связанный с событием приема.
ХХХ: код пример
В некоторых очень редких случаях разработчикам может потребоваться изменить или понять, как контекст
(идентификатор узла) первого события устанавливается равным идентификатору связанного с ним узла. Это выполнено
классом NodeList: всякий раз, когда создается новый узел, класс NodeList использует
ScheduleWithContext, чтобы запланировать событие инициализации для этого узла. Событие инициализации
таким образом выполняется с контекстом, установленным для идентификатора узла, и может использовать обычное разнообразие
Способы расписания. Он вызывает метод Node :: Initialize, который передает "инициализировать"
событие, вызвав метод DoInitialize для каждого объекта, связанного с узлом. В
DoInitialize переопределен в некоторых из этих объектов (особенно в Application
базовый класс) будет планировать некоторые события (в первую очередь Application :: StartApplication), которые
в свою очередь будет планировать события генерации трафика, которые, в свою очередь, будут планировать
события сетевого уровня.
Ноты:
· Пользователи должны быть осторожны при распространении методов DoInitialize между объектами путем вызова
Явно инициализировать их объекты-члены
· Идентификатор контекста, связанный с каждым методом ScheduleWithContext, имеет другие применения помимо
регистрация: он используется экспериментальной ветвью ns-3 для выполнения параллельного моделирования на
многоядерные системы, использующие многопоточность.
Функции Simulator :: * не знают, каков контекст: они просто следят за тем, чтобы
любой контекст, который вы укажете с помощью ScheduleWithContext, доступен, когда соответствующий
событие выполняется с :: GetContext.
Реализованные поверх Simulator :: * модели должны интерпретировать значение контекста.
В ns-3 сетевые модели интерпретируют контекст как идентификатор узла, который
сгенерировал событие. Вот почему важно вызывать ScheduleWithContext в
ns3 :: Channel подклассы, потому что мы генерируем событие от узла i к узлу j, и мы
хотите убедиться, что событие, которое будет запускаться на узле j, имеет правильный контекст.
Время
к be завершенный
Планировщик
к be завершенный
Обратные вызовы
Некоторым новым пользователям нс-3 незнакомы с широко используемыми идиомами программирования
во всем коде: нс-3 Перезвони. В этой главе дается некоторая мотивация
обратный вызов, руководство по его использованию и подробные сведения о его реализации.
Обратные вызовы мотивация
Предположим, у вас есть две имитационные модели A и B, и вы хотите, чтобы они прошли
информация между ними во время моделирования. Один из способов сделать это -
может сделать так, чтобы A и B явно знали друг о друге, чтобы они могли вызывать
методы друг на друга:
класс А {
общественности:
void ReceiveInput (// параметры);
...
}
(в другом исходном файле :)
класс Б {
общественности:
недействительным DoSomething (недействительным);
...
частный:
A * a_instance; // указатель на A
}
аннулировать
B :: DoSomething ()
{
// Сообщаем a_instance, что что-то произошло
a_instance-> ReceiveInput (// параметры);
...
}
Это, безусловно, работает, но у него есть недостаток, заключающийся в зависимости от A и B.
знать о другом во время компиляции (это усложняет независимую
единицы компиляции в симуляторе) и не является обобщенным; если в более позднем сценарии использования,
B должен разговаривать с совершенно другим объектом C, исходный код для B должен быть
изменено, чтобы добавить c_instance и так далее. Легко понять, что это грубая сила
механизм коммуникации, который может привести к ошибкам программирования в моделях.
Это не означает, что объекты не должны знать друг о друге, если есть трудные
зависимости между ними, но часто модель можно сделать более гибкой, если ее
взаимодействия менее ограничены во время компиляции.
Это не абстрактная проблема для исследования сетевого моделирования, а скорее
источник проблем в предыдущих симуляторах, когда исследователи хотят расширить или изменить
система, чтобы делать разные вещи (как они склонны делать в исследованиях). Рассмотрим, например,
пользователь, который хочет добавить подуровень протокола безопасности IPsec между TCP и IP:
------------ -----------
| TCP | | TCP |
------------ -----------
| становится -> |
----------- -----------
| ИП | | IPsec |
----------- -----------
|
-----------
| ИП |
-----------
Если симулятор сделал предположения и жестко закодировал код, этот IP всегда говорит
к транспортному протоколу, указанному выше, пользователь может быть вынужден взломать систему, чтобы получить
желаемые взаимосвязи. Это явно не оптимальный способ создания универсального
Тренажер.
Обратные вызовы проверка данных
ПРИМЕЧАНИЕ:
Читатели, знакомые с программированием обратных вызовов, могут пропустить этот раздел руководства.
Основной механизм, позволяющий решить указанную выше проблему, известен как Перезвони.
Конечная цель - позволить одному фрагменту кода вызывать функцию (или метод в C ++).
без какой-либо конкретной межмодульной зависимости.
В конечном итоге это означает, что вам нужно какое-то косвенное обращение - вы обрабатываете адрес
называется функцией как переменной. Эта переменная называется переменной указателя на функцию.
Связь между функцией и указателем на функцию действительно не отличается
что у объекта и указателя на объект.
В C каноническим примером указателя на функцию является
указатель на возвращаемое целое число (PFI). Для PFI, принимающего один параметр int, это
можно было бы объявить как:
int (* pfi) (int arg) = 0;
В результате вы получите переменную с простым именем PFI который инициализируется значением 0.
Если вы хотите инициализировать этот указатель на что-то значимое, у вас должен быть
функция с соответствующей подписью. В таком случае:
int MyFunction (целый аргумент) {}
Если у вас есть эта цель, вы можете инициализировать переменную, чтобы она указывала на вашу функцию, например:
pfi = МояФункция;
Затем вы можете вызвать MyFunction косвенно, используя более понятную форму вызова:
int результат = (* pfi) (1234);
Это наводит на размышления, поскольку похоже, что вы просто разыменовываете указатель на функцию.
как если бы вы разыменовали любой указатель. Однако обычно люди пользуются
тот факт, что компилятор знает, что происходит, и просто будет использовать более короткую форму:
int результат = pfi (1234);
Обратите внимание, что указатель на функцию подчиняется семантике значения, поэтому вы можете передавать его, как любой другой.
другое значение. Обычно, когда вы используете асинхронный интерфейс, вы передаете некоторую сущность
как это к функции, которая будет выполнять действие и призывают назад чтобы вы знали это
завершенный. Он выполняет обратный вызов, следуя косвенному обращению и выполняя предоставленную функцию.
В C ++ добавлена сложность объектов. Аналогия с PFI выше означает, что вы
иметь указатель на функцию-член, возвращающую int (PMI) вместо указателя на
функция, возвращающая int (PFI).
Объявление переменной, обеспечивающей косвенное обращение, выглядит немного иначе:
int (MyClass :: * pmi) (int arg) = 0;
Это объявляет переменную с именем PMI так же, как в предыдущем примере объявлена переменная с именем
PFI. Поскольку будет вызывать метод экземпляра определенного класса, необходимо
объявить этот метод в классе:
класс MyClass {
общественности:
int MyMethod (целый аргумент);
};
Учитывая это объявление класса, затем можно инициализировать эту переменную следующим образом:
pmi = & MyClass :: MyMethod;
Это присваивает переменной адрес кода, реализующего метод, завершая
косвенное обращение. Чтобы вызвать метод, коду требуется этой указатель. Это в свою очередь,
означает, что должен существовать объект MyClass, на который можно ссылаться. Упрощенный пример этого - просто
косвенный вызов метода (подумайте о виртуальной функции):
int (MyClass :: * pmi) (int arg) = 0; // Объявить PMI
pmi = & MyClass :: MyMethod; // Указываем на код реализации
MyClass myClass; // Нужен экземпляр класса
(myClass. * pmi) (1234); // Вызов метода с объектом ptr
Как и в примере с C, вы можете использовать это в асинхронном вызове другого модуля.
который будет призывают назад используя метод и указатель на объект. Прямое расширение
можно подумать, это передать указатель на объект и переменную PMI. Модуль
просто сделал бы:
(* objectPtr. * pmi) (1234);
для выполнения обратного вызова на желаемом объекте.
В это время можно спросить: то, что точка? Вызываемый модуль должен будет понять
конкретный тип вызывающего объекта, чтобы правильно выполнить обратный вызов. Почему нет
просто примите это, передайте правильно напечатанный указатель объекта и выполните объект->Способ доставки(1234) in
код вместо обратного вызова? Это как раз проблема, описанная выше. Что
необходим способ полностью отделить вызывающую функцию от вызываемого класса. Этот
требование привело к разработке Функтор.
Функтор - это продукт изобретенного в 1960-х годах под названием замыкание. это
в основном просто вызов упакованной функции, возможно, с некоторым состоянием.
Функтор состоит из двух частей, определенной части и общей части, связанных посредством наследования.
Вызывающий код (код, выполняющий обратный вызов) выполнит общий перегруженный
оператор () универсального функтора, чтобы вызвать обратный вызов. Вызываемый код (
код, который требуется отозвать) должен будет предоставить специализированную реализацию
оператор () который выполняет специфичную для класса работу, которая вызвала тесную связь
проблема выше.
С конкретным функтором и его перегруженным оператор () создан, вызываемый код затем
предоставляет специализированный код модулю, который будет выполнять обратный вызов (вызывающий
код).
Вызывающий код примет в качестве параметра универсальный функтор, поэтому выполняется неявное приведение
в вызове функции для преобразования конкретного функтора в универсальный функтор. Это означает
что вызывающему модулю просто необходимо понимать общий тип функтора. Это развязано
из вызывающего кода полностью.
Информация, необходимая для создания конкретного функтора, - это указатель на объект и
адрес указателя на метод.
Суть того, что должно произойти, заключается в том, что система объявляет общую часть
функтор:
шаблон
класс Functor
{
общественности:
виртуальный оператор int () (T arg) = 0;
};
Вызывающий определяет конкретную часть функтора, которая действительно существует для реализации.
конкретный Оператор () Метод:
шаблон
class SpecificFunctor: общедоступный Functor
{
общественности:
SpecificFunctor (T * p, int (T :: * _ pmi) (ARG аргумент))
{
м_р = р;
м_пми = _пми;
}
виртуальный оператор int () (аргумент ARG)
{
(* m_p. * m_pmi) (аргумент);
}
частный:
int (T :: * m_pmi) (аргумент ARG);
Т * м_п;
};
Вот пример использования:
класс А
{
общественности:
A (int a0): a (a0) {}
int Привет (int b0)
{
std :: cout << "Привет от A, a =" << a << "b0 =" << b0 << std :: endl;
}
в а;
};
int main ()
{
A a(10);
SpecificFunctor sf (& a, & A :: Привет);
sf(5);
}
ПРИМЕЧАНИЕ:
Предыдущий код не является настоящим кодом ns-3. Это упрощенный пример кода, используемый только для
проиллюстрировать задействованные концепции и помочь вам лучше понять систему. Не надо
ожидайте найти этот код где угодно в дереве ns-3.
Обратите внимание, что в приведенном выше классе определены две переменные. Переменная m_p - это
указатель на объект, а m_pmi - это переменная, содержащая адрес функции для
выполнять.
Обратите внимание, когда Оператор () вызывается, он, в свою очередь, вызывает метод, предоставленный с
указатель на объект с использованием синтаксиса C ++ PMI.
Чтобы использовать это, можно затем объявить некоторый код модели, который принимает общий функтор как
Параметр:
void LibraryFunction (функтор Functor);
Код, который будет взаимодействовать с моделью, построит конкретный функтор и передаст его в
БиблиотекаФункция:
МойКласс мойКласс;
SpecificFunctor функтор (& myclass, MyClass :: MyMethod);
После появления БиблиотекаФункция выполнено, он выполняет обратный вызов, используя Оператор () на общий
функтор, который он был передан, и в этом конкретном случае предоставляет целочисленный аргумент:
аннулировать
LibraryFunction (функтор-функтор)
{
// Выполняем библиотечную функцию
функтор(1234);
}
Заметить, что БиблиотекаФункция полностью не привязан к конкретному типу клиента.
Связь осуществляется через полиморфизм Functor.
API обратного вызова в нс-3 реализует объектно-ориентированные обратные вызовы с использованием механизма функторов.
Этот API обратного вызова, основанный на шаблонах C ++, является типобезопасным; то есть он выполняет статические
проверки типов для обеспечения надлежащей совместимости подписей между вызывающими и вызываемыми объектами. это
поэтому они более безопасны для типов, чем традиционные указатели на функции, но синтаксис может
сначала выглядят внушительно. Этот раздел предназначен для ознакомления с системой обратного вызова.
чтобы вам было удобно использовать его в нс-3.
. Обратный звонок API
API обратного вызова довольно минимален и предоставляет только две службы:
1. объявление типа обратного вызова: способ объявить тип обратного вызова с заданной подписью,
а также,
2. Создание экземпляра обратного вызова: способ создания экземпляра обратного вызова переадресации, созданного с помощью шаблона.
который может перенаправлять любые вызовы другому методу члена класса C ++ или функции C ++.
Лучше всего это увидеть, пройдя через пример, основанный на образцы / main-callback.cc.
. Обратный звонок API статический Функции
Рассмотрим функцию:
статический двойной
CbOne (двойной a, двойной b)
{
std :: cout << "invoke cbOne a =" << a << ", b =" << b << std :: endl;
вернуть;
}
Рассмотрим также следующий основной фрагмент программы:
int main (int argc, char * argv [])
{
// возвращаемый тип: двойной
// первый тип аргумента: double
// второй тип аргумента: double
Перезвони один;
}
Это пример обратного вызова в стиле C, который не включает и не требует этой
указатель. Шаблон функции Обратный звонок по сути, это объявление переменной
содержащий указатель на функцию. В приведенном выше примере мы явно показали указатель
функции, которая вернула целое число и приняла одно целое число в качестве параметра,
Обратный звонок шаблонная функция является общей версией этого - она используется для объявления типа
обратного вызова.
ПРИМЕЧАНИЕ:
Читатели, незнакомые с шаблонами C ++, могут проконсультироваться
http://www.cplusplus.com/doc/tutorial/templates/.
" Обратный звонок для шаблона требуется один обязательный аргумент (возвращаемый тип функции
быть назначенным этому обратному вызову) и до пяти необязательных аргументов, каждый из которых определяет
тип аргументов (если ваша конкретная функция обратного вызова имеет более пяти аргументов,
тогда с этим можно справиться, расширив реализацию обратного вызова).
Итак, в приведенном выше примере у нас есть объявленный обратный вызов с именем «один», который в конечном итоге
удерживайте указатель на функцию. Сигнатура функции, которую он будет удерживать, должна возвращать
double и должен поддерживать два аргумента типа double. Если кто-то пытается передать функцию,
подпись не соответствует объявленному обратному вызову, произойдет ошибка компиляции. Кроме того, если
кто-то пытается назначить обратному вызову несовместимый, компиляция будет успешной, но
время выполнения NS_FATAL_ERROR будет поднят. Пример программы
SRC / ядро / примеры / main-callback.cc демонстрирует оба этих случая ошибок в конце
Основной () программу.
Теперь нам нужно связать этот экземпляр обратного вызова и фактическую целевую функцию.
(CbOne). Обратите внимание, что CbOne имеет те же типы сигнатур функций, что и обратный вызов:
это важно. Мы можем передать в этот обратный вызов любую такую правильно типизированную функцию.
Давайте посмотрим на это более внимательно:
статический двойной CbOne (двойной a, двойной b) {}
^ ^ ^
| | |
| | |
Перезвони один;
Вы можете привязать функцию к обратному вызову, только если у них есть соответствующая подпись. Первое
аргумент шаблона - это возвращаемый тип, а дополнительные аргументы шаблона - это типы
аргументов сигнатуры функции.
Теперь давайте свяжем наш обратный вызов "один" с функцией, которая соответствует его сигнатуре:
// создаем экземпляр обратного вызова, который указывает на функцию cbOne
one = MakeCallback (& CbOne);
Этот призыв к Обратный звонок по сути, создает один из специализированных функторов
упомянутый выше. Переменная, объявленная с использованием Обратный звонок функция шаблона собирается
играть роль типичного функтора. Назначение one = Обратный звонок (& CbOne) is
приведение, которое преобразует специализированный функтор, известный вызываемому, в общий функтор
известно звонящему.
Затем, позже в программе, если обратный вызов необходим, его можно использовать следующим образом:
NS_ASSERT (! One.IsNull ());
// вызов функции cbOne через экземпляр обратного вызова
двойной retOne;
retOne = один (10.0, 20.0);
Чек на Нулевой() гарантирует, что обратный вызов не равен нулю - что есть функция
чтобы позвонить после этого обратного вызова. Потом, один() выполняет общий Оператор () что на самом деле
перегружен конкретной реализацией Оператор () и возвращает тот же результат, что и если
CbOne () был вызван напрямую.
. Обратный звонок API член Функции
Как правило, вы не будете вызывать статические функции, а вместо этого будете вызывать общедоступные функции-члены
объект. В этом случае необходим дополнительный аргумент функции MakeCallback, чтобы
сообщить системе, для какого объекта должна быть вызвана функция. Рассмотрим этот пример,
также из main-callback.cc:
класс MyCb {
общественности:
int CbTwo (двойная а) {
std :: cout << "invoke cbTwo a =" << a << std :: endl;
возврат -5;
}
};
int main ()
{
...
// возвращаемый тип: int
// первый тип аргумента: double
Перезвони два;
MyCb cb;
// создаем экземпляр обратного вызова, который указывает на MyCb :: cbTwo
two = MakeCallback (& MyCb :: CbTwo, & cb);
...
}
Здесь мы передаем дополнительный указатель объекта на MakeCallback <> функция. Напомним из
фоновый раздел над этим Оператор () будет использовать указатель на синтаксис члена, когда он
выполняется на объекте:
виртуальный оператор int () (аргумент ARG)
{
(* m_p. * m_pmi) (аргумент);
}
Итак, нам нужно было предоставить две переменные (м_р и м_пми) когда мы сделали конкретный
функтор. Линия:
two = MakeCallback (& MyCb :: CbTwo, & cb);
делает именно это. В этом случае, когда два () вызывается:
int результат = два (1.0);
приведет к вызову CbTwo функция-член (метод) для объекта, на который указывает
& cb.
Здание Значение Null Обратные вызовы
Обратные вызовы могут быть нулевыми; следовательно, может быть целесообразно проверить их перед их использованием.
Для обратного вызова null существует специальная конструкция, которая предпочтительнее простой передачи
«0» в качестве аргумента; это MakeNullCallback <> построить:
two = MakeNullCallback ();
NS_ASSERT(два.IsNull());
Вызов нулевого обратного вызова аналогичен вызову указателя нулевой функции: он выйдет из строя в
время выполнения.
Граница Обратные вызовы
Очень полезным расширением концепции функтора является функция Bound Callback. Раньше это
было упомянуто, что замыкания изначально были вызовами функций, упакованными для более позднего использования.
исполнение. Обратите внимание, что во всех приведенных выше описаниях обратных вызовов нет возможности
упаковать любые параметры для использования позже - когда Обратный звонок вызывается через Оператор ().
Все параметры предоставляются вызывающей функцией.
Что, если нужно разрешить клиентской функции (той, которая обеспечивает обратный вызов)
предоставить какие-то параметры? Александреску вызывает процесс разрешения клиенту
укажите один из параметров "привязка". Один из параметров Оператор () было
связаны (фиксируются) клиентом.
Некоторые из наших кодов трассировки pcap являются хорошим примером этого. Есть функция, которая
должен вызываться всякий раз, когда получен пакет. Эта функция вызывает объект, который
фактически записывает пакет на диск в формате файла pcap. Подпись одного из этих
функции будут:
static void DefaultSink (Ptr файл, Ptr п);
Ключевое слово static означает, что это статическая функция, для которой не требуется этой указатель, так что
он будет использовать обратные вызовы в стиле C. Мы не хотим, чтобы код вызова знал о
что угодно, кроме Пакета. То, что мы хотим в вызывающем коде, - это просто вызов, который выглядит так:
m_promiscSnifferTrace (m_currentPkt);
Что мы хотим сделать, так это связывать Ptr файл к конкретному обратному вызову
реализация, когда он создается и организует Оператор () обратного звонка на
предоставьте этот параметр бесплатно.
Мы предоставляем Обратный вызов шаблонную функцию для этой цели. Требуется то же самое
параметры как Обратный звонок шаблонная функция, но также принимает параметры, которые должны быть
граница. В случае приведенного выше примера:
MakeBoundCallback (& DefaultSink, файл);
создаст конкретную реализацию обратного вызова, которая знает, как добавить дополнительную границу
аргументы. По сути, он расширяет конкретный функтор, описанный выше, одним или несколькими
связанные аргументы:
шаблон
class SpecificFunctor: общедоступный Functor
{
общественности:
SpecificFunctor (T * p, int (T :: * _ pmi) (ARG arg), BOUND_ARG boundArg)
{
м_р = р;
м_пми = пми;
m_boundArg = связанныйАрг;
}
виртуальный оператор int () (аргумент ARG)
{
(* m_p. * m_pmi) (m_boundArg, аргумент);
}
частный:
void (T :: * m_pmi) (аргумент ARG);
Т * м_п;
BOUND_ARG m_boundArg;
};
Вы можете видеть, что при создании конкретного функтора связанный аргумент сохраняется в
сам объект функтора / обратного вызова. Когда Оператор () вызывается с помощью сингла
параметр, например:
m_promiscSnifferTrace (m_currentPkt);
осуществление Оператор () добавляет связанный параметр в фактический вызов функции:
(* m_p. * m_pmi) (m_boundArg, аргумент);
Также можно связать два или три аргумента. Скажем, у нас есть функция с
подпись:
static void NotifyEvent (Ptr a, Ptr b, MyEventType e);
Можно создать привязку привязки обратного вызова для первых двух аргументов, например:
MakeBoundCallback (& NotifyEvent, a1, b1);
при условии, a1 и b1 объекты типа A и B соответственно. Аналогично для трех
аргументы у одной функции с подписью:
static void NotifyEvent (Ptr a, Ptr b, MyEventType e);
Связывание трех аргументов выполняется с помощью:
MakeBoundCallback (& NotifyEvent, a1, b1, c1);
снова предполагая a1, b1 и c1 объекты типа A, B и C соответственно.
Этот вид привязки может использоваться для обмена информацией между объектами моделирования;
в частности, связанные обратные вызовы могут использоваться как отслеживаемые обратные вызовы, которые будут описаны в
следующий раздел.
Проследить Обратные вызовы
Заполнитель подраздел
Обратный звонок места in нс-3
Где обратные вызовы часто используются в нс-3? Вот некоторые из наиболее заметных
типичные пользователи:
· API сокетов
· Layer-2 / Layer-3 API
· Подсистема слежения
· API между IP и подсистемами маршрутизации
Реализация детали
Приведенные выше фрагменты кода упрощены и предназначены только для иллюстрации механизма.
сам. Фактический код обратного вызова довольно сложен, содержит много шаблонов и
не требуется глубокого понимания кода. Если интересно, опытные пользователи могут найти
следующие полезные.
Первоначально код был написан на основе методов, описанных в
http://www.codeproject.com/cpp/TTLFunction.asp. Впоследствии он был переписан, чтобы следовать
архитектура, изложенная в Модерн C + + дизайн Общий Программирование и Дизайн Шаблоны
Применяемый, Александреску, глава 5, Обобщенные ФУНКТОРЫ.
В этом коде используются:
· Параметры шаблона по умолчанию, чтобы избавить пользователей от необходимости указывать пустые параметры, когда
количество параметров меньше максимального поддерживаемого числа
· Идиома pimpl: класс обратного вызова передается по значению и делегирует суть
работа к его указателю pimpl.
· Могут использоваться две реализации pimpl, производные от CallbackImpl FunctorCallbackImpl
с любым типом функтора, в то время как MemPtrCallbackImpl может использоваться с указателями на член
функции.
· Реализация списка ссылок для реализации семантики значения обратного вызова.
Этот код наиболее заметно отличается от реализации Александреску тем, что не
используйте списки типов, чтобы указать и передать типы аргументов обратного вызова. Конечно,
он также не использует семантику копирования-уничтожения и полагается на список ссылок, а не на
autoPtr, чтобы удерживать указатель.
объект модель
нс-3 по сути является объектной системой C ++. Объекты могут быть объявлены и созданы как
обычно, по правилам C ++. нс-3 также добавляет некоторые функции к традиционным объектам C ++, например
описано ниже, чтобы обеспечить большую функциональность и возможности. Эта глава руководства
призваны познакомить читателя с нс-3 объектная модель.
В этом разделе описывается дизайн класса C ++ для нс-3 объекты. Вкратце, несколько дизайнов
используемые шаблоны включают классический объектно-ориентированный дизайн (полиморфные интерфейсы и
реализации), разделение интерфейса и реализации, невиртуальная общедоступная
шаблон проектирования интерфейса, средство агрегирования объектов и подсчет ссылок для
управление памятью. Те, кто знаком с компонентными моделями, такими как COM или Bonobo, будут
распознавать элементы дизайна в нс-3 модель агрегирования объектов, хотя нс-3
дизайн не в строгом соответствии ни с одним.
Объектно-ориентированный поведение
Объекты C ++, как правило, предоставляют общие объектно-ориентированные возможности (абстракция,
инкапсуляция, наследование и полиморфизм), которые являются частью классических объектно-ориентированных
дизайн. нс-3 объекты используют эти свойства; например:
класс Адрес
{
общественности:
Адрес ();
Адрес (тип uint8_t, const uint8_t * buffer, uint8_t len);
Адрес (const Адрес и адрес);
Адрес & оператор = (const Адрес & адрес);
...
частный:
uint8_t м_тип;
uint8_t m_len;
...
};
объект Использование темпера с изогнутым основанием классов
Есть три специальных базовых класса, используемых в нс-3. Классы, наследующие от этой базы
классы могут создавать экземпляры объектов со специальными свойствами. Эти базовые классы:
· класс объект
· класс объектная база
· класс SimpleRefCount
Не требуется, чтобы нс-3 объекты наследуются от этого класса, но те, которые получают
особые свойства. Классы, производные от class объект получить следующие свойства.
· В нс-3 система типов и атрибутов (см. Атрибуты)
· Система агрегирования объектов
· Интеллектуальная система подсчета ссылок (класс Ptr)
Классы, производные от класса объектная база получить первые два свойства выше, но не
получить умные указатели. Классы, производные от класса SimpleRefCount: получить только
система подсчета ссылок с умным указателем.
На практике класс объект это вариант из трех вышеупомянутых, что нс-3 разработчик будет
чаще всего встречаются.
Память управление и класс Ptr
Управление памятью в программе на C ++ - сложный процесс, который часто выполняется неправильно или
непоследовательно. Мы остановились на схеме подсчета ссылок, описанной ниже.
Все объекты, использующие подсчет ссылок, поддерживают внутренний счетчик ссылок для определения
когда объект может безопасно удалить себя. Каждый раз, когда получается указатель на
интерфейс, счетчик ссылок на объект увеличивается путем вызова Ссылка (), Это
обязанность пользователя указателя явно Unref () указатель, когда закончите. Когда
счетчик ссылок падает до нуля, объект удаляется.
· Когда клиентский код получает указатель от самого объекта через создание объекта,
или через GetObject ему не нужно увеличивать счетчик ссылок.
· Когда клиентский код получает указатель из другого источника (например, копируя указатель), он должен
призывают Ссылка () для увеличения счетчика ссылок.
· Все пользователи указателя объекта должны вызывать Unref () освободить ссылку.
Бремя звонка Unref () несколько смягчается использованием подсчета ссылок
класс интеллектуального указателя, описанный ниже.
Пользователи, использующие низкоуровневый API, которые хотят явно выделить объекты без подсчета ссылок.
в куче, используя оператор new, отвечают за удаление таких объектов.
ID подсчет умный указатель (Птр)
призвание Ссылка () и Unref () все время было бы громоздко, поэтому нс-3 обеспечивает умный
класс указателя Ptr похож на Boost :: intrusive_ptr. Этот класс интеллектуального указателя предполагает, что
базовый тип предоставляет пару ссылка и Unref методы, которые, как ожидается,
увеличивать и уменьшать внутренний счетчик ссылок экземпляра объекта.
Эта реализация позволяет вам манипулировать интеллектуальным указателем, как если бы он был обычным
указатель: вы можете сравнить его с нулем, сравнить с другими указателями, присвоить ноль
это и т. д.
Из этого интеллектуального указателя можно извлечь необработанный указатель с помощью GetPointer ()
и PeekPointer () методы.
Если вы хотите сохранить новый объект в интеллектуальном указателе, мы рекомендуем вам использовать
Функции шаблона CreateObject для создания объекта и сохранения его в интеллектуальном указателе на
избегайте утечек памяти. Эти функции являются действительно небольшими удобными функциями, и их цель
просто чтобы сэкономить немного времени на вводе текста.
CreateObject и Создавай
Объекты в C ++ могут создаваться статически, динамически или автоматически. Это верно
для нс-3 также, но для некоторых объектов в системе доступны дополнительные фреймворки.
В частности, объекты с подсчетом ссылок обычно выделяются с помощью шаблонов Create или
CreateObject следующим образом.
Для объектов, производных от класса объект:
Ptr device = CreateObject ();
Пожалуйста, не создавайте такие объекты, используя оператор new; создать их, используя CreateObject ()
.
Для объектов, производных от класса SimpleRefCountили другие объекты, поддерживающие использование
класс интеллектуального указателя, доступна и рекомендуется использовать шаблонную вспомогательную функцию:
Ptr b = Create ();
Это просто оболочка для оператора new, которая правильно обрабатывает подсчет ссылок.
системы.
Таким образом, используйте Создавать если B не является объектом, а просто использует подсчет ссылок (например,
пакет) и используйте CreateObject если B происходит от ns3 :: Объект.
агрегирование
" нс-3 Система агрегирования объектов в значительной степени мотивирована признанием того, что
общий вариант использования для нс-2 было использование наследования и полиморфизма для расширения
модели протокола. Например, специализированные версии TCP, такие как RenoTcpAgent, производят
из (и переопределить функции из) класса TcpAgent.
Однако две проблемы, возникшие в нс-2 модели преуменьшены и "слабая база"
класс ". Понижающее значение относится к процедуре использования указателя базового класса на объект и
запрашивая его во время выполнения, чтобы узнать информацию о типе, используемую для явного приведения указателя
на указатель подкласса, чтобы можно было использовать API подкласса. Слабый базовый класс относится к
проблемы, возникающие, когда класс не может быть эффективно повторно использован (производным от), потому что он
не имеет необходимой функциональности, что заставляет разработчика изменять базовый класс и
вызывая распространение вызовов API базового класса, некоторые из которых могут не быть семантически
правильно для всех подклассов.
нс-3 использует версию шаблона проектирования интерфейса запроса, чтобы избежать этих проблем.
Этот дизайн основан на элементах Компонент объект Модель и GNOME Bonobo хотя
полная совместимость заменяемых компонентов на двоичном уровне не поддерживается, и у нас есть
попытался упростить синтаксис и повлиять на разработчиков моделей.
Примеры
агрегирование пример
Узел является хорошим примером использования агрегации в нс-3. Обратите внимание, что не производные
классы узлов в нс-3 например, класс Интернет-узел. Вместо этого компоненты (протоколы)
агрегированы в узел. Давайте посмотрим, как к узлу добавляются некоторые протоколы Ipv4:
статическая пустота
AddIpv4Stack (Ptr узел)
{
Ptr ipv4 = CreateObject ();
ipv4-> SetNode (узел);
узел-> AggregateObject (ipv4);
Ptr ipv4Impl = CreateObject ();
ipv4Impl-> SetIpv4 (ipv4);
узел-> AggregateObject (ipv4Impl);
}
Обратите внимание, что протоколы IPv4 создаются с использованием CreateObject (). Затем они агрегируются
к узлу. Таким образом, базовый класс Node не нужно редактировать, чтобы разрешить пользователям
с указателем узла базового класса для доступа к интерфейсу Ipv4; пользователи могут запросить у узла
указатель на его интерфейс Ipv4 во время выполнения. Как пользователь запрашивает узел, описано в
следующий подраздел.
Обратите внимание, что объединение более одного объекта одного типа в
an ns3 :: Объект. Так, например, агрегирование не является вариантом для хранения всех
активные сокеты узла.
ПолучитьОбъект пример
GetObject - это типобезопасный способ добиться безопасного понижающего преобразования и позволить интерфейсам быть
найдено на объекте.
Рассмотрим указатель узла м_узел который указывает на объект Node, имеющий реализацию
IPv4 ранее был объединен с ним. Код клиента хочет настроить маршрут по умолчанию. К
для этого он должен получить доступ к объекту в узле, который имеет интерфейс для пересылки IP.
конфигурация. Он выполняет следующее:
Ptr ipv4 = m_node-> GetObject ();
Если на самом деле узел не имеет агрегированного объекта Ipv4, тогда метод будет
вернуть null. Поэтому рекомендуется проверять возвращаемое значение такой функции.
вызов. В случае успеха пользователь теперь может использовать Ptr для объекта Ipv4, который ранее был
агрегированы к узлу.
Другой пример того, как можно использовать агрегирование, - это добавление дополнительных моделей к объектам. За
Например, существующий объект Node может иметь агрегированный объект «Модель энергии» в
время выполнения (без изменения и перекомпиляции класса узла). Существующая модель (например,
беспроводное сетевое устройство) может позже "GetObject" для модели энергопотребления и действовать соответствующим образом
если интерфейс был либо встроен в базовый объект Node, либо агрегирован в
это во время выполнения. Однако другим узлам не нужно ничего знать об энергетических моделях.
Мы надеемся, что этот режим программирования потребует от разработчиков гораздо меньше изменений.
базовые классы.
объект заводы
Типичный вариант использования - создание множества аналогичных сконфигурированных объектов. Можно многократно
призывают CreateObject () но в нс-3 системы.
Он активно используется в «вспомогательном» API.
Класс Фабрика объектов может использоваться для создания экземпляров объектов и настройки атрибутов на
эти объекты:
недействительным SetTypeId (TypeId tid);
void Set (std :: string name, const AttributeValue & value);
Ptr Create (void) const;
Первый способ позволяет использовать нс-3 Система TypeId для указания типа объектов
созданный. Второй позволяет устанавливать атрибуты на создаваемые объекты, а
третий позволяет создавать сами объекты.
Например:
фабрика ObjectFactory;
// Заставляем эту фабрику создавать объекты типа FriisPropagationLossModel
factory.SetTypeId ("ns3 :: FriisPropagationLossModel")
// Заставляем этот заводской объект изменить значение атрибута по умолчанию для
// созданные впоследствии объекты
factory.Set ("SystemLoss", DoubleValue (2.0));
// Создаем один такой объект
Ptr объект = factory.Create ();
factory.Set ("SystemLoss", DoubleValue (3.0));
// Создаем другой объект с другим SystemLoss
Ptr объект = factory.Create ();
понижающее приведение
Несколько раз возникал вопрос: «Если у меня есть указатель базового класса (Ptr) на
объект, и я хочу, чтобы указатель производного класса был понижен (с помощью динамического преобразования C ++) до
получить производный указатель, или мне следует использовать систему агрегации объектов для GetObject <> ()
найти Ptr для интерфейса API подкласса? "
Ответ на этот вопрос заключается в том, что во многих ситуациях работают оба метода. нс-3 обеспечивает
шаблонная функция для того, чтобы сделать синтаксис динамического приведения объектов гораздо более пользовательским
дружелюбно:
шаблон
Ptr
DynamicCast (Ptr const & p)
{
вернуть Ptr (dynamic_cast (PeekPointer (p)));
}
DynamicCast работает, когда программист имеет указатель базового типа и проверяет его на соответствие
указатель подкласса. GetObject работает при поиске различных агрегированных объектов, но также
работает с подклассами так же, как DynamicCast. Если не уверены, программист должен
используйте GetObject, так как он работает во всех случаях. Если программист знает иерархию классов
рассматриваемого объекта, проще просто использовать DynamicCast.
Конфигурация и Атрибуты
In нс-3 моделирования, есть два основных аспекта настройки:
· Топология моделирования и способы соединения объектов.
· Значения, используемые моделями, созданными в топологии.
В этой главе основное внимание уделяется второму пункту выше: сколько значений используется в нс-3
организованы, задокументированы и могут быть изменены нс-3 пользователи. нс-3 система атрибутов также
обоснование того, как трассировки и статистика собираются в симуляторе.
В ходе этой главы мы обсудим различные способы установки или изменения значений.
используется нс-3 объекты модели. В порядке возрастания специфичности это:
┌──────────────────────────────────┬──────────────── ───────────────────
│Метод │ Область применения │
├──────────────────────────────────┼──────────────── ───────────────────
│Установлены значения атрибутов по умолчанию │ Влияют на все экземпляры │
Когда атрибуты определены в │ классе. │
│GetTypeId (). │ │
└───────────────────────────────────┴──────────────── ────────────────────┘
│Командная строка │ Влияет на все будущие экземпляры. │
│Config :: SetDefault () │ │
│Магазин конфигураций │ │
├──────────────────────────────────┼──────────────── ───────────────────
│Фабрика объектов │ Влияет на все созданные экземпляры │
│ │ с завода. │
├──────────────────────────────────┼──────────────── ───────────────────
│XHelperSetAttribute () │ Влияет на все экземпляры, созданные │
│ │ помощник. │
├──────────────────────────────────┼──────────────── ───────────────────
│MyClass :: SetX () │ Изменяет этот конкретный экземпляр. │
│Object :: SetAttribute () │ Обычно это единственная форма │
│Конфиг :: Установить () │ которые можно изменить по расписанию │
│ │ экземпляр после моделирования │
│ │ работает. │
└───────────────────────────────────┴──────────────── ────────────────────┘
Под "специфичностью" мы подразумеваем, что методы в последующих строках таблицы переопределяют установленные значения.
и обычно влияют на меньшее количество экземпляров, чем более ранние методы.
Прежде чем углубляться в детали системы значений атрибутов, полезно рассмотреть некоторые
основные свойства класса объект.
объект Обзор
нс-3 по сути является объектно-ориентированной системой C ++. Под этим мы подразумеваем, что новые классы C ++
(типы) могут быть объявлены, определены и разделены на подклассы как обычно.
Много нс-3 объекты наследуются от объект базовый класс. У этих объектов есть дополнительные
свойства, которые мы используем для организации системы и улучшения управления памятью
наших объектов:
· Система «метаданных», которая связывает имя класса с большим количеством метаинформации о
объект, в том числе:
· Базовый класс подкласса,
· Набор доступных конструкторов в подклассе,
· Набор «атрибутов» подкласса,
· Может ли каждый атрибут быть установлен или доступен только для чтения,
· Допустимый диапазон значений для каждого атрибута.
· Реализация интеллектуального указателя подсчета ссылок для управления памятью.
нс-3 объекты, использующие систему атрибутов, происходят от объект or объектная база, Наиболее
нс-3 объекты, которые мы будем обсуждать, происходят от объект, но некоторые, которые находятся за пределами умных
структура управления памятью указателя происходит от объектная база.
Давайте рассмотрим несколько свойств этих объектов.
Smart Указатели
Как введено в нс-3 руководство, нс-3 объекты - это память, управляемая ссылка
подсчет умный указатель реализация, учебный класс Ptr.
Умные указатели широко используются в нс-3 API, чтобы избежать передачи ссылок на
объекты, размещенные в куче, которые могут вызвать утечку памяти. Для базового использования (синтаксиса) обработайте
умный указатель, такой как обычный указатель:
Ptr nd = ...;
nd-> CallSomeFunction ();
// так далее.
Итак, как получить умный указатель на объект, как в первой строке этого примера?
CreateObject
Как мы обсуждали выше в Memory-management-and-class-Ptr, на нижнем уровне API объекты
типа объект не создаются с использованием оператор new как обычно, но вместо этого с помощью шаблонного
функция называется CreateObject ().
Типичный способ создания такого объекта следующий:
Ptr nd = CreateObject ();
Вы можете думать об этом как о функциональном эквиваленте:
WifiNetDevice * nd = новый WifiNetDevice ();
Объекты, происходящие из объект должен быть размещен в куче с помощью CreateObject (), Те
вытекающий из объектная база, Такие, как нс-3 вспомогательные функции и заголовки и трейлеры пакетов,
могут быть размещены в стеке.
В некоторых скриптах вы можете не увидеть много CreateObject () вызывает код; это
потому что есть некоторые вспомогательные объекты, которые выполняют CreateObject () призывы
для вас.
Идентификатор типа
нс-3 классы, производные от класса объект может включать класс метаданных, называемый Идентификатор типа который
записывает метаинформацию о классе для использования в агрегировании объектов и компоненте
системы управления:
· Уникальная строка, идентифицирующая класс.
· Базовый класс подкласса в системе метаданных.
· Набор доступных конструкторов в подклассе.
· Список общедоступных свойств («атрибутов») класса.
объект Итого
Объединив все эти концепции, давайте рассмотрим конкретный пример: класс Узел.
Общедоступный файл заголовка узел.h имеет объявление, которое включает статический GetTypeId ()
вызов функции:
Узел класса: общедоступный объект
{
общественности:
статический TypeId GetTypeId (void);
...
Это определено в узел.cc файл следующим образом:
Идентификатор типа
Узел :: GetTypeId (недействительно)
{
статический TypeId tid = TypeId ("ns3 :: Node")
.SetParent ()
.AddConstructor ()
.AddAttribute ("Список устройств",
"Список устройств, связанных с этим узлом.",
ЗначениеВектораОбъекта(),
MakeObjectVectorAccessor (& Node :: m_devices),
MakeObjectVectorChecker ())
.AddAttribute ("Список приложений",
"Список приложений, связанных с этим узлом.",
ЗначениеВектораОбъекта(),
MakeObjectVectorAccessor (& Node :: m_applications),
MakeObjectVectorChecker ())
.AddAttribute ("Идентификатор",
"Идентификатор (уникальное целое число) этого узла.",
TypeId :: ATTR_GET, // разрешить только получение.
Целое значение (0),
MakeUintegerAccessor (& Node :: m_id),
MakeUintegerChecker ())
;
вернуть tid;
}
Рассмотрим один пример на платформе Идентификатор типа нс-3 объект класс как расширенная форма типа времени выполнения
информация (RTTI). Язык C ++ включает простой вид RTTI для поддержки
динамический_cast и TypeId операторы.
" SetParent () вызов в приведенном выше определении используется вместе с нашим
механизмы агрегации объектов для обеспечения безопасного преобразования с повышением и понижением в деревьях наследования
в течение ПолучитьОбъект (). Это также позволяет подклассам наследовать атрибуты своего родителя.
класса.
" AddConstructor () call используется вместе с нашей фабрикой абстрактных объектов
механизмы, позволяющие нам создавать объекты C ++, не заставляя пользователя знать
конкретный класс объекта, который она строит.
Три призыва к Добавить атрибут () связать данную строку со строго типизированным значением в
класс. Обратите внимание, что вы должны предоставить строку справки, которая может отображаться, например,
с помощью процессоры командной строки. Каждый Атрибут связан с механизмами доступа
базовая переменная-член в объекте (например, Макеуинтегераксессор () говорит
общий Атрибут код, как добраться до идентификатора узла выше). Также есть «Шашка»
методы, которые используются для проверки значений на соответствие ограничениям диапазона, таким как максимальное и
минимально допустимые значения.
Когда пользователи хотят создать узлы, они обычно вызывают некоторую форму CreateObject (),:
Ptr n = CreateObject ();
или, более абстрактно, используя фабрику объектов, вы можете создать Узел объект даже без
зная конкретный тип C ++:
фабрика ObjectFactory;
const std :: string typeId = "ns3 :: Node" ';
factory.SetTypeId (идентификатор типа);
Ptr node = factory.Create ();
Оба эти метода приводят к тому, что полностью инициализированные атрибуты доступны в
в результате объект экземпляров.
Далее мы обсудим, как атрибуты (значения, связанные с переменными-членами или функциями
класс) погружены в вышеупомянутый Идентификатор типа.
Атрибуты
Целью системы атрибутов является организация доступа к внутренним объектам-членам
моделирование. Эта цель возникает потому, что, как правило, при моделировании пользователи сокращают и
вставлять / изменять существующие сценарии моделирования или использовать конструкции моделирования более высокого уровня,
но часто будет интересоваться изучением или отслеживанием определенных внутренних переменных. За
Например, варианты использования, такие как:
· "I хотеть в прослеживать пакеты on беспроводной интерфейс Важно on первый доступ точка."
· "I хотеть в прослеживать ценностное of TCP скопление окно (каждый время it изменения) on a
особый TCP разъем."
· "I хотеть a дамп of ВСЕ ценности который были использовал in my моделирование ".
Точно так же пользователям может потребоваться детальный доступ к внутренним переменным в моделировании или
может захотеть широко изменить начальное значение, используемое для определенного параметра во всех
впоследствии созданные объекты. Наконец, пользователи могут захотеть узнать, какие переменные можно установить.
и извлекаемый в конфигурации моделирования. Это не только для прямого моделирования
взаимодействие в командной строке; рассмотрите также (будущий) графический пользовательский интерфейс, который
хотели бы иметь возможность предоставить возможность, с помощью которой пользователь мог бы щелкнуть правой кнопкой мыши узел на
холст и увидеть иерархический, организованный список параметров, которые можно настроить на
узла и составляющих его объектов-членов, а также текст справки и значения по умолчанию для каждого
Параметр.
Определяющий Атрибуты
Мы предоставляем пользователям возможность доступа к ценностям глубоко в системе без необходимости погружаться в глубину системы.
аксессоры (указатели) через систему и обходные цепочки указателей, чтобы добраться до них. Рассмотрим
класс DropTailQueue который имеет переменную-член, которая является беззнаковым целым числом m_maxПакетов;
эта переменная-член контролирует глубину очереди.
Если мы посмотрим на декларацию DropTailQueue, мы видим следующее:
class DropTailQueue: public Queue {
общественности:
статический TypeId GetTypeId (void);
...
частный:
std :: queue > m_packets;
uint32_t m_maxПакеты;
};
Давайте рассмотрим, что пользователь может захотеть сделать со значением m_maxПакетов:
· Установите для системы значение по умолчанию, чтобы при появлении нового DropTailQueue создано,
этот член инициализируется этим значением по умолчанию.
· Установить или получить значение в уже созданной очереди.
Вышеуказанные вещи обычно требуют предоставления Поставьте () и Получите () функции, и некоторые типы
глобальное значение по умолчанию.
В нс-3 система атрибутов, эти определения значений и регистрации функций доступа
перемещены в Идентификатор типа класс; например.:
NS_OBJECT_ENSURE_RIGN (DropTailQueue);
Идентификатор типа
DropTailQueue :: GetTypeId (недействительно)
{
статический TypeId tid = TypeId ("ns3 :: DropTailQueue")
.SetParent ()
.AddConstructor ()
.AddAttribute ("MaxPackets",
"Максимальное количество пакетов, принимаемых этой DropTailQueue.",
Целое значение (100),
MakeUintegerAccessor (& DropTailQueue :: m_maxPackets),
MakeUintegerChecker ())
;
вернуть tid;
}
" Добавить атрибут () метод выполняет ряд вещей для m_maxПакетов значение:
· Привязка (обычно закрытой) переменной-члена m_maxПакетов в публичную строку
«МаксПакетс».
· Предоставление значения по умолчанию (100 пакетов).
· Предоставление некоторого справочного текста, определяющего значение значения.
· Предоставление «средства проверки» (не используется в этом примере), которое можно использовать для установки границ на
допустимый диапазон значений.
Ключевым моментом является то, что теперь доступны значение этой переменной и ее значение по умолчанию.
в пространстве имен атрибутов, основанном на таких строках, как «МаксПакетс» и Идентификатор типа имя
струны. В следующем разделе мы предоставим пример сценария, который показывает, как пользователи могут
манипулировать этими ценностями.
Обратите внимание, что инициализация атрибута зависит от макроса NS_OBJECT_ENSURE_RIGN
(Очередь DropTail) быть вызванным; если вы оставите это вне своей реализации нового класса, ваш
атрибуты не будут правильно инициализированы.
Хотя мы описали, как создавать атрибуты, мы все еще не описали, как получить доступ
и управлять этими ценностями. Например, нет глобальные.h файл заголовка, где они
хранится; атрибуты хранятся вместе со своими классами. Естественно возникают вопросы: как
легко ли пользователи узнают обо всех атрибутах своих моделей и как пользователь
получить доступ к этим атрибутам или задокументировать их значения как часть записи их
симуляция?
Подробная документация по фактическим атрибутам, определенным для типа, и глобальный список
все определенные атрибуты доступны в документации API. Для всего остального
В документе мы собираемся продемонстрировать различные способы получения и установки атрибута
значения.
настройка По умолчанию Наши ценности
Config :: SetDefault и Командная строка
Давайте посмотрим, как пользовательский сценарий может получить доступ к определенному значению атрибута. Собирались
использовать SRC / точка-точка / примеры / main-attribute-value.cc сценарий для иллюстрации, с
некоторые детали удалены. В main функция начинается:
// Это базовый пример того, как использовать систему атрибутов для
// установить и получить значение в базовой системе; а именно, беззнаковый
// целое число от максимального количества пакетов в очереди
//
Int
main (int argc, char * argv [])
{
// По умолчанию атрибут MaxPackets имеет значение 100 пакетов
// (это значение по умолчанию можно наблюдать в функции DropTailQueue :: GetTypeId)
//
// Здесь мы устанавливаем 80 пакетов. Мы могли бы использовать один из двух типов значений:
// строковое значение или значение Uinteger
Config :: SetDefault ("ns3 :: DropTailQueue :: MaxPackets", StringValue ("80"));
// Приведенный ниже вызов функции является избыточным
Config :: SetDefault ("ns3 :: DropTailQueue :: MaxPackets", UintegerValue (80));
// Разрешить пользователю отменять любые значения по умолчанию и указанные выше
// SetDefaults () во время выполнения через аргументы командной строки
// Например, через "--ns3 :: DropTailQueue :: MaxPackets = 80"
Командная строка командной строки;
// Это дает еще один способ установить значение из командной строки:
cmd.AddValue ("maxPackets", "ns3 :: DropTailQueue :: MaxPackets");
cmd.Parse(argc, argv);
Главное, на что следует обратить внимание, - это два эквивалентных вызова Config :: SetDefault
(). Вот как мы устанавливаем значение по умолчанию для всех создаваемых впоследствии экземпляров.
DropTailQueueс. Мы проиллюстрируем, что два типа Значение классы, Строковое значение и еще один
Uцелое значение class, может использоваться для присвоения значения атрибуту, названному
"ns3 :: DropTailQueue :: MaxPackets".
Также можно управлять атрибутами с помощью Командная строка; мы видели несколько примеров
в начале учебника. В частности, просто добавить сокращенный аргумент
имя, например --maxPacketsдля атрибута, который особенно важен для вашей модели,
в таком случае "ns3 :: DropTailQueue :: MaxPackets". Это имеет дополнительную функцию, которую
Строка справки для атрибута будет напечатана как часть сообщения об использовании скрипта.
Для получения дополнительной информации см. Командная строка Документация по API.
Теперь мы создадим несколько объектов, используя низкоуровневый API. Наши вновь созданные очереди будут
нет m_maxПакетов инициализировано до 100 пакетов, как определено в
DropTailQueue :: GetTypeId () функция, но до 80 пакетов, из-за того, что мы сделали выше с
значения по умолчанию.:
Ptr n0 = CreateObject ();
Ptr net0 = CreateObject ();
n0-> AddDevice (net0);
Ptr q = CreateObject ();
net0-> AddQueue (q);
На данный момент мы создали единый Узел (n0) и один PointToPointNetDevice
(net0) и добавил DropTailQueue (q), Чтобы net0.
Конструкторы, Помощники и Фабрика объектов
Произвольные комбинации атрибутов могут быть установлены и извлечены из помощника и низкоуровневого
API; либо от самих конструкторов:
Ptr p =
CreateObjectWithAttributes
("MinX", DoubleValue (-100.0),
«MinY», DoubleValue (-100.0),
«DeltaX», DoubleValue (5.0),
"DeltaY", DoubleValue (20.0),
"GridWidth", UintegerValue (20),
«LayoutType», StringValue («RowFirst»));
или из вспомогательных API более высокого уровня, таких как:
мобильность.SetPositionAllocator
("ns3 :: GridPositionAllocator",
"MinX", DoubleValue (-100.0),
«MinY», DoubleValue (-100.0),
«DeltaX», DoubleValue (5.0),
"DeltaY", DoubleValue (20.0),
"GridWidth", UintegerValue (20),
«LayoutType», StringValue («RowFirst»));
Мы не иллюстрируем это здесь, но вы также можете настроить Фабрика объектов с новыми ценностями
для определенных атрибутов. Экземпляры, созданные Фабрика объектов будут те
атрибуты, установленные во время строительства. Это очень похоже на использование одного из вспомогательных API
для класса.
Чтобы проверить, есть несколько способов установить значения атрибутов для экземпляров класса. в be
создали in будущее:
· Config :: SetDefault ()
· CommandLine :: AddValue ()
· CreateObjectWithAttributes <> ()
· Различные вспомогательные API
Но что, если вы уже создали экземпляр и хотите изменить значение
атрибут? В этом примере, как мы можем манипулировать m_maxПакетов ценность уже
проиллюстрированный DropTailQueue? Вот несколько способов сделать это.
Изменение Наши ценности
Умный указатель
Предположим, что умный указатель (Ptr) к соответствующему сетевому устройству в руке; в текущем
Например, это net0 указатель.
Один из способов изменить значение - получить доступ к указателю на соответствующую очередь и изменить ее
атрибутов.
Сначала мы замечаем, что можем получить указатель на (базовый класс) Очередь с помощью
PointToPointNetDevice атрибуты, где это называется "TxQueue":
значение указателя tmp;
net0-> GetAttribute ("TxQueue", tmp);
Ptr txQueue = tmp.GetObject ();
Посмотрите на график ПолучитьОбъект () функции, мы можем выполнить безопасное приведение к DropTailQueue, Где
«МаксПакетс» это атрибут:
Ptr dtq = txQueue-> GetObject ();
NS_ASSERT (dtq! = 0);
Затем мы можем получить значение атрибута в этой очереди. Мы ввели обертку
Значение классы для базовых типов данных, аналогичные Java-оболочкам для этих типов,
поскольку система атрибутов хранит значения, сериализованные в строки, а не разрозненные типы.
Здесь значение атрибута присваивается Uцелое значение, и Получите () метод на этом
значение производит (развернутый) uint32_t.:
предел UintegerValue;
dtq-> GetAttribute ("MaxPackets", лимит);
NS_LOG_INFO ("1. лимит dtq:" << limit.Get () << "пакеты");
Обратите внимание, что приведенное выше понижающее значение в действительности не требуется; мы могли бы получить атрибут
ценность непосредственно от txQueue, который является объект:
txQueue-> GetAttribute ("MaxPackets", лимит);
NS_LOG_INFO ("2. txQueue limit:" << limit.Get () << "пакеты");
Теперь установим другое значение (60 пакетов):
txQueue-> SetAttribute ("MaxPackets", UintegerValue (60));
txQueue-> GetAttribute ("MaxPackets", лимит);
NS_LOG_INFO ("3. Предел txQueue изменен:" << limit.Get () << "пакеты");
Конфиг Пространство имен Тропа
Альтернативный способ получить атрибут - использовать пространство имен конфигурации. Здесь,
этот атрибут находится на известном пути в этом пространстве имен; этот подход полезен, если один
не имеет доступа к указателям, лежащим в основе, и хотел бы настроить конкретный
атрибут с одним заявлением .:
Config :: Set ("/ NodeList / 0 / DeviceList / 0 / TxQueue / MaxPackets",
Uцелое значение (25));
txQueue-> GetAttribute ("MaxPackets", лимит);
NS_LOG_INFO ("4. Предел txQueue изменен через пространство имен:"
<< limit.Get () << "пакеты");
Путь конфигурации часто имеет вид "... /
имя> / /.../ / " для ссылки на конкретный экземпляр по индексу
объект в контейнере. В этом случае первый контейнер - это список всех УзелS;
второй контейнер - это список всех NetDevices на выбранном Узел, Наконец,
путь конфигурации обычно заканчивается последовательностью атрибутов-членов, в данном случае
«МаксПакетс» атрибут "TxQueue" избранных NetDevice.
Мы также могли бы использовать подстановочные знаки, чтобы установить это значение для всех узлов и всех сетевых устройств.
(который в этом простом примере имеет тот же эффект, что и предыдущий Конфиг :: Установить ()):
Config :: Set ("/ NodeList / * / DeviceList / * / TxQueue / MaxPackets",
Uцелое значение (15));
txQueue-> GetAttribute ("MaxPackets", лимит);
NS_LOG_INFO ("5. Предел txQueue изменен через пространство имен с подстановочными знаками:"
<< limit.Get () << "пакеты");
объект ФИО Услуга
Другой способ получить атрибут - использовать службу имени объекта. В
служба имен объектов позволяет нам добавлять элементы в пространство имен конфигурации под
"/ Имена /" путь с определяемой пользователем строкой имени. Этот подход полезен, если вы не
имеют доступ к указателям, лежащим в основе, и трудно определить требуемые
конкретный путь к пространству имен конфигурации.
Names :: Add ("сервер", n0);
Имена :: Добавить ("сервер / eth0", net0);
...
Config :: Set ("/ Имена / сервер / eth0 / TxQueue / MaxPackets", UintegerValue (25));
Здесь мы добавили элементы пути "сервер" и "eth0" под "/ Имена /" пространство имен, тогда
использовал полученный путь конфигурации для установки атрибута.
См. Объектные имена для более полной обработки нс-3 пространство имен конфигурации.
Реализация Подробнее
Значение Классы
Читатели отметят ТипЗначение классы, которые являются подклассами Значение атрибута Использование темпера с изогнутым основанием
класс. Их можно рассматривать как промежуточные классы, которые используются для преобразования из сырых
типы в Значение атрибутаs, которые используются системой атрибутов. Напомним, что это
база данных содержит объекты многих типов, сериализованные в строки. Конверсии в этот тип
может быть выполнено с использованием промежуточного класса (например, Целое значениеили Двойное значение для
числа с плавающей запятой) или с помощью струны. Прямое неявное преобразование типов в
Значение атрибута не совсем практично. Итак, в приведенном выше примере у пользователей есть выбор использовать
строки или значения:
p-> Set ("cwnd", StringValue ("100")); // сеттер на основе строк
p-> Set ("cwnd", IntegerValue (100)); // сеттер на основе целых чисел
Система предоставляет некоторые макросы, которые помогают пользователям объявлять и определять новое значение AttributeValue.
подклассы для новых типов, которые они хотят ввести в систему атрибутов:
· ATTRIBUTE_HELPER_HEADER
· ATTRIBUTE_HELPER_CPP
См. Документацию по API для этих конструкций для получения дополнительной информации.
Инициализация Оформить заказ
Атрибуты в системе не должны зависеть от состояния любого другого атрибута в этом
система. Это связано с тем, что порядок инициализации атрибутов не указан, ни
принудительно, системой. Конкретный пример этого можно увидеть в автоматизированной настройке.
такие программы, как Магазин конфигураций. Хотя данная модель может организовать это так, что Атрибуты
инициализируются в определенном порядке, другой автоматический конфигуратор может решить
самостоятельно изменять Атрибуты, например, в алфавитном порядке.
Из-за этого неспецифического упорядочивания ни один атрибут в системе не может иметь зависимости
по любому другому атрибуту. Как следствие, установщики атрибутов никогда не должны выходить из строя из-за состояния
другого атрибута. Ни один установщик атрибутов не может изменять (устанавливать) любое другое значение атрибута в качестве
результат изменения его значения.
Это очень сильное ограничение, и в некоторых случаях атрибуты должны устанавливать
последовательно, чтобы обеспечить правильную работу. С этой целью мы разрешаем проверку согласованности
когда атрибут is использовал (cf. НС_АССЕРТ_МСГ or NS_ABORT_MSG).
В общем, код атрибута для присвоения значений базовым переменным-членам класса
выполняется после создания объекта. Но что, если вам нужны присвоенные значения
перед выполнением тела конструктора, потому что они вам нужны в логике
конструктор? Есть способ сделать это, например, в классе Магазин конфигураций: вызов
ObjectBase :: ConstructSelf () следующим образом:
ConfigStore :: ConfigStore ()
{
ObjectBase :: ConstructSelf (AttributeConstructionList ());
// продолжаем с конструктором.
}
Помните, что объект и все его производные классы также должны реализовывать GetInstanceTypeId
() метод. В противном случае ObjectBase :: ConstructSelf () не сможет прочитать
атрибутов.
Добавление Атрибуты
" нс-3 система поместит ряд внутренних значений под систему атрибутов, но
несомненно, пользователи захотят расширить это, чтобы выбрать те, которые мы пропустили, или добавить свои
собственные классы в системе.
Есть три типичных варианта использования:
· Обеспечение доступа к существующему члену данных класса в качестве атрибута, когда он еще не был.
· Создание нового класса, способного отображать некоторые члены данных как атрибуты, путем присвоения ему TypeId.
· Создание Значение атрибута подкласс для нового класса, чтобы к нему можно было получить доступ как
Атрибут.
Существующий Член Технология
Рассмотрим эту переменную в TCPSocket:
uint32_t m_cWnd; // Окно перегрузки
Предположим, что кто-то, работающий с TCP, хотел получить или установить значение этой переменной.
с использованием системы метаданных. Если это еще не было предоставлено нс-3, пользователь может объявить
следующее дополнение в системе метаданных времени выполнения (к GetTypeId () определение для
TCPSocket):
.AddAttribute ("Окно перегрузки",
"Окно перегрузки TCP (в байтах)",
Целое значение (1),
MakeUintegerAccessor (& TcpSocket :: m_cWnd),
MakeUintegerChecker ())
Теперь пользователь с указателем на TCPSocket экземпляр может выполнять такие операции, как
установка и получение значения без явного добавления этих функций.
Кроме того, могут применяться элементы управления доступом, такие как разрешение чтения параметра и
не записано, или может применяться проверка границ допустимых значений.
Новое Класс Идентификатор типа
Здесь мы обсуждаем влияние на пользователя, который хочет добавить новый класс в нс-3. Что
что нужно сделать, чтобы он мог хранить атрибуты?
Предположим, наш новый класс с именем ns3 :: MyMobility, это тип модели мобильности. Первый,
класс должен наследовать от своего родительского класса, ns3 :: MobilityModel. В моя-мобильность.h
заголовочный файл:
пространство имен ns3 {
класс MyClass: общедоступная MobilityModel
{
Для этого необходимо объявить GetTypeId () функция. Это общедоступная однострочная функция
декларация:
общественности:
/ **
* Зарегистрируйте этот тип.
* \ return Объект TypeId.
*/
статический TypeId GetTypeId (void);
Мы уже рассказали, что такое Идентификатор типа определение будет выглядеть в my-mobility.cc
файл реализации:
NS_OBJECT_ENSURE_RIGN (MyMobility);
Идентификатор типа
MyMobility :: GetTypeId (недействительно)
{
статический TypeId tid = TypeId ("ns3 :: MyMobility")
.SetParent ()
.SetGroupName ("Мобильность")
.AddConstructor ()
.AddAttribute ("Границы",
"Границы местности для круиза.",
RectangleValue (Прямоугольник (0.0, 0.0, 100.0, 100.0)),
MakeRectangleAccessor (& MyMobility :: m_bounds),
MakeRectangleChecker ())
.AddAttribute ("Время",
"Измените текущее направление и скорость после движения в течение этой задержки.",
TimeValue (секунды (1.0)),
MakeTimeAccessor (& MyMobility :: m_modeTime),
MakeTimeChecker ())
// и т.д. (дополнительные параметры).
;
вернуть tid;
}
Если мы не хотим создавать подкласс от существующего класса, в файле заголовка мы просто наследуем
от ns3 :: Объект, а в объектном файле мы устанавливаем родительский класс на ns3 :: Объект
.SetParent ().
Типичные ошибки здесь включают:
· Не звонит NS_OBJECT_ENSURE_RIGN ()
· Не звонить SetParent () метод или вызвав его с неправильным типом.
· Не звонить ДобавитьКонструктор () метод или вызвав его с неправильным типом.
· Опечатка в названии Идентификатор типа в его конструкторе.
· Не использовать полное имя типа C ++ включающего класса C ++ в качестве имени
Идентификатор типа, Обратите внимание, что "ns3 ::" не требуется.
Ни одна из этих ошибок не может быть обнаружена нс-3 кодовая база, поэтому пользователям рекомендуется проверять
тщательно несколько раз, чтобы они поняли это правильно.
Новое Значение атрибута Тип
С точки зрения пользователя, который пишет новый класс в системе и хочет, чтобы он был
доступный как атрибут, в основном это вопрос записи преобразований в / из
строки и значения атрибутов. Большая часть этого может быть скопирована / вставлена с помощью макро-кода. За
Например, рассмотрим объявление класса для Прямоугольные в SRC / мобильность / модель каталог:
заголовок Файл
/ **
* \ сократить 2d прямоугольник
*/
класс Rectangle
{
...
двойной хмин;
двойной xMax;
двойной yMin;
двойной yMax;
};
Один вызов макроса и два оператора должны быть добавлены под объявлением класса, чтобы
превратить Rectangle в значение, используемое Атрибут система:
std :: ostream & operator << (std :: ostream & os, const Rectangle & rectangle);
std :: istream & оператор >> (std :: istream & is, прямоугольник & прямоугольник);
ATTRIBUTE_HELPER_HEADER (прямоугольник);
Реализация Файл
В определении класса (.cc файл) код выглядит так:
ATTRIBUTE_HELPER_CPP (прямоугольник);
std :: ostream &
оператор << (std :: ostream & os, const Rectangle и rectangle)
{
os << rectangle.xMin << "|" << rectangle.xMax << "|" << rectangle.yMin << "|"
<< rectangle.yMax;
вернуть ОС;
}
std :: istream &
оператор >> (std :: istream & is, Прямоугольник и прямоугольник)
{
символы с1, с2, с3;
равно >> rectangle.xMin >> c1 >> rectangle.xMax >> c2 >> rectangle.yMin >> c3
>> rectangle.yMax;
если (c1! = '|' ||
c2! = '|' ||
c3! = '|')
{
is.setstate (std :: ios_base :: failbit);
}
возврат есть;
}
Эти операторы потока просто конвертируют из строкового представления прямоугольника
(«xMin | xMax | yMin | yMax») в базовый прямоугольник. Разработчик модели должен указать эти
операторы и строковое синтаксическое представление экземпляра нового класса.
Магазин конфигураций
Ценности для нс-3 атрибуты могут быть сохранены в текстовом файле ASCII или XML и загружены в
будущий запуск моделирования. Эта функция известна как нс-3 ConfigStore. В Магазин конфигураций is
специализированная база данных для значений атрибутов и значений по умолчанию.
Хотя это отдельный модуль в SRC / config-магазин / каталог, мы
задокументируйте его здесь из-за его единственной зависимости от нс-3 основной модуль и атрибуты.
Мы можем изучить эту систему на примере из
SRC / хранилище конфигурации / примеры / config-store-save.cc.
Во-первых, все пользователи Магазин конфигураций должен включать следующее заявление:
#include "ns3 / config-store-module.h"
Затем эта программа добавляет образец объекта Пример конфигурации чтобы показать, как расширяется система:
class ConfigExample: общедоступный объект
{
общественности:
статический TypeId GetTypeId (пустой) {
статический TypeId tid = TypeId ("ns3 :: A")
.SetParent ()
.AddAttribute ("TestInt16", "текст справки",
Целое значение (-2),
MakeIntegerAccessor (& A :: m_int16),
MakeIntegerChecker ())
;
вернуть tid;
}
int16_t m_int16;
};
NS_OBJECT_ENSURE_RIGN (ConfigExample);
Затем мы используем подсистему Config для переопределения значений по умолчанию двумя способами:
Config :: SetDefault ("ns3 :: ConfigExample :: TestInt16", IntegerValue (-5));
Ptr a_obj = CreateObject ();
NS_ABORT_MSG_UNLESS (a_obj-> m_int16 == -5,
«Невозможно установить целочисленный атрибут ConfigExample через Config :: SetDefault»);
Ptr a2_obj = CreateObject ();
a2_obj-> SetAttribute ("TestInt16", IntegerValue (-3));
Целое значение iv;
a2_obj-> GetAttribute ("TestInt16", iv);
NS_ABORT_MSG_UNLESS (iv.Get() == -3,
«Невозможно установить целочисленный атрибут ConfigExample через SetAttribute»);
Следующее утверждение необходимо, чтобы убедиться, что (один из) созданных объектов является корневым.
в пространстве имен конфигурации как экземпляр объекта. Обычно это происходит, когда вы
агрегировать объекты в ns3 :: Узел or ns3 :: Channel например, но здесь, поскольку мы работаем
на уровне ядра нам нужно создать новый объект корневого пространства имен:
Config :: RegisterRootNamespaceObject (a2_obj);
Writing
Далее мы хотим вывести хранилище конфигурации. На примерах показано, как это сделать за два
форматы, XML и необработанный текст. На практике этот шаг следует выполнять непосредственно перед вызовом
Симулятор :: Беги () чтобы сохранить окончательную конфигурацию непосредственно перед запуском моделирования.
Есть три атрибута, которые управляют поведением ConfigStore: "Режим",
"Имя файла"и "Формат файла". Режим (по умолчанию "Никто") настраивает, нс-3 должен
загрузить конфигурацию из ранее сохраненного файла (указать "Mode = Load") или сохраните его в файл
(указать «Режим = Сохранить»). Имя файла (по умолчанию "") - это то место, где должно быть прочитано хранилище ConfigStore, или
напишите свои данные. Формат файла (по умолчанию "RawText") определяет, будет ли формат ConfigStore
это обычный текст или Xml ("FileFormat = Xml")
Пример показывает:
Config :: SetDefault ("ns3 :: ConfigStore :: Filename", StringValue ("output-attributes.xml"));
Config :: SetDefault ("ns3 :: ConfigStore :: FileFormat", StringValue ("Xml"));
Config :: SetDefault ("ns3 :: ConfigStore :: Mode", StringValue ("Сохранить"));
ConfigStore outputConfig;
выводConfig.ConfigureDefaults ();
выводConfig.ConfigureAttributes ();
// Вывести хранилище конфигурации в формат txt
Config :: SetDefault ("ns3 :: ConfigStore :: Filename", StringValue ("output-attributes.txt"));
Config :: SetDefault ("ns3 :: ConfigStore :: FileFormat", StringValue ("RawText"));
Config :: SetDefault ("ns3 :: ConfigStore :: Mode", StringValue ("Сохранить"));
ConfigStore выводConfig2;
выводConfig2.ConfigureDefaults ();
выводConfig2.ConfigureAttributes ();
Симулятор :: Беги ();
Симулятор :: Уничтожить ();
Обратите внимание на размещение этих операторов непосредственно перед Симулятор :: Беги () заявление.
Этот вывод регистрирует все значения на месте непосредственно перед запуском моделирования (т.е..
после того, как все настройки были выполнены).
После запуска вы можете открыть выходные-атрибуты.txt файл и посмотрите:
по умолчанию ns3 :: RealtimeSimulatorImpl :: SynchronizationMode "BestEffort"
по умолчанию ns3 :: RealtimeSimulatorImpl :: HardLimit "+ 100000000.0ns"
по умолчанию ns3 :: PcapFileWrapper :: CaptureSize "65535"
по умолчанию ns3 :: PacketSocket :: RcvBufSize "131072"
по умолчанию ns3 :: ErrorModel :: IsEnabled "true"
по умолчанию ns3 :: RateErrorModel :: ErrorUnit "EU_BYTE"
по умолчанию ns3 :: RateErrorModel :: ErrorRate "0"
по умолчанию ns3 :: RateErrorModel :: RanVar "Uniform: 0: 1"
по умолчанию ns3 :: DropTailQueue :: Режим "Пакеты"
по умолчанию ns3 :: DropTailQueue :: MaxPackets "100"
по умолчанию ns3 :: DropTailQueue :: MaxBytes "6553500"
по умолчанию ns3 :: Application :: StartTime "+ 0.0ns"
по умолчанию ns3 :: Application :: StopTime "+ 0.0ns"
по умолчанию ns3 :: ConfigStore :: Mode "Сохранить"
по умолчанию ns3 :: ConfigStore :: Filename "output-attributes.txt"
по умолчанию ns3 :: ConfigStore :: FileFormat "RawText"
по умолчанию ns3 :: ConfigExample :: TestInt16 "-5"
глобальный RngSeed "1"
global RngRun "1"
global SimulatorImplementationType "ns3 :: DefaultSimulatorImpl"
global SchedulerType "ns3 :: MapScheduler"
global ChecksumEnabled "false"
значение / $ ns3 :: ConfigExample / TestInt16 "-3"
Выше показаны все значения по умолчанию для атрибутов основного модуля.
Затем все значения для нс-3 записываются глобальные значения. Наконец, значение
экземпляр Пример конфигурации который был внедрен в пространство имен конфигурации. В
реальные нс-3 программа, будет показано гораздо больше моделей, атрибутов и значений по умолчанию.
Версия XML также существует в выходные-атрибуты.xml:
Этот файл можно заархивировать с вашим сценарием моделирования и выходными данными.
Reading
Далее мы обсудим настройку моделирования. с помощью сохраненный файл конфигурации ввода. Есть
пара ключевых отличий по сравнению с написанием окончательной конфигурации моделирования.
Во-первых, нам нужно разместить такие операторы в начале программы, перед
Записываются операторы конфигурации моделирования (поэтому значения регистрируются перед тем, как
используется при строительстве объекта).
Config :: SetDefault ("ns3 :: ConfigStore :: Filename", StringValue ("input-defaults.xml"));
Config :: SetDefault ("ns3 :: ConfigStore :: Mode", StringValue ("Загрузить"));
Config :: SetDefault ("ns3 :: ConfigStore :: FileFormat", StringValue ("Xml"));
ConfigStore inputConfig;
inputConfig.ConfigureDefaults ();
Затем обратите внимание, что загрузка входных данных конфигурации ограничена атрибутом по умолчанию (т.е..
не экземпляр) значения и глобальные значения. Значения экземпляра атрибута не поддерживаются
потому что на этом этапе моделирования, до создания каких-либо объектов, нет
такие экземпляры объектов вокруг. (Обратите внимание, что будущие улучшения в хранилище конфигураций могут измениться
это поведение).
Во-вторых, при выводе Магазин конфигураций состояние перечислит все в базе данных,
входной файл должен содержать только определенные значения, которые нужно переопределить. Итак, один из способов использования
этот класс для конфигурации входного файла предназначен для генерации начальной конфигурации с использованием
выход ("Сохранить") "Режим" описанный выше, извлеките из этого файла конфигурации только
элементы, которые нужно изменить, и переместите эти минимальные элементы в новый файл конфигурации
которые затем можно безопасно редактировать и загружать в последующем прогоне моделирования.
Когда Магазин конфигураций объект создается, его атрибуты "Имя файла", "Режим"и
"Формат файла" должен быть установлен, либо с помощью командная строка или с помощью программные операторы.
Чтение / запись Пример
В качестве более сложного примера предположим, что мы хотим читать в конфигурации
значения по умолчанию из входного файла с именем ввод-defaults.xml, и выпишите полученный
атрибуты в отдельный файл с именем выходные-атрибуты.xml.:
#include "ns3 / config-store-module.h"
...
основной (...)
{
Config :: SetDefault ("ns3 :: ConfigStore :: Filename", StringValue ("input-defaults.xml"));
Config :: SetDefault ("ns3 :: ConfigStore :: Mode", StringValue ("Загрузить"));
Config :: SetDefault ("ns3 :: ConfigStore :: FileFormat", StringValue ("Xml"));
ConfigStore inputConfig;
inputConfig.ConfigureDefaults ();
//
// Разрешить пользователю переопределить любые значения по умолчанию и указанную выше Bind () в
// время выполнения, через аргументы командной строки
//
Командная строка командной строки;
cmd.Parse(argc, argv);
// настраиваем топологию
...
// Вызов непосредственно перед входом в Simulator :: Run ()
Config :: SetDefault ("ns3 :: ConfigStore :: Filename", StringValue ("output-attributes.xml"));
Config :: SetDefault ("ns3 :: ConfigStore :: Mode", StringValue ("Сохранить"));
ConfigStore outputConfig;
выводConfig.ConfigureAttributes ();
Симулятор :: Беги ();
}
Магазин конфигураций Графический интерфейс пользователя
Для ConfigStore существует интерфейс на основе GTK. Это позволяет пользователям использовать графический интерфейс для
доступ и изменение переменных. Скриншоты этой функции доступны в | ns3 |
Обзор презентация.
Чтобы использовать эту функцию, необходимо установить библиотека libgtk и libgtk-dev; пример Ubuntu
команда установки:
$ sudo apt-get установить libgtk2.0-0 libgtk2.0-dev
Чтобы проверить, настроен он или нет, проверьте вывод шага:
$ ./waf настроить --enable-examples --enable-tests
---- Обзор дополнительных функций NS-3:
Привязки Python: включены
Поддержка сканирования Python API: включена
Интеграция NS-3 Click: включена
GtkConfigStore: не включен (библиотека 'gtk + -2.0> = 2.12' не найдена)
В приведенном выше примере он не был включен, поэтому его нельзя использовать, пока не будет установлена подходящая версия.
установлен и:
$ ./waf настроить --enable-examples --enable-tests
$ ./ваф
повторяется.
Использование почти такое же, как и в версии, не основанной на GTK, но нет Магазин конфигураций
задействованные атрибуты:
// Вызов непосредственно перед входом в Simulator :: Run ()
Конфигурация GtkConfigStore;
config.ConfigureDefaults ();
config.НастроитьАтрибуты();
Теперь, когда вы запускаете скрипт, должен появиться графический интерфейс, позволяющий открывать меню
атрибуты на разных узлах / объектах, а затем запустить выполнение моделирования, когда вы
сделано.
Будущее работает
Есть несколько возможных улучшений:
· Сохраните уникальный номер версии с датой и временем в начале файла.
· Сохраните где-нибудь начальное семя rng.
· Заставьте каждую переменную RandomVariable сериализовать свое собственное начальное семя и перечитайте его позже.
объект имена
Заполнитель глава
Запись
" нс-3 средство ведения журнала может использоваться для отслеживания или отладки процесса моделирования
программы. Вывод журнала может быть включен с помощью программных операторов в вашем Основной () программа или
с помощью НС_ЛОГ переменная среды.
Операторы ведения журнала не компилируются в оптимизированные сборки нс-3. Чтобы использовать ведение журнала, нужно
должен построить (по умолчанию) отладочную сборку нс-3.
Проект не дает никаких гарантий относительно того, останется ли вывод журнала неизменным в течение
время. Предупреждаем пользователей о том, что нельзя создавать фреймворки результатов моделирования поверх ведения журналов.
код, так как вывод и способ включения вывода могут со временем меняться.
Обзор
нс-3 операторы регистрации обычно используются для регистрации различных событий выполнения программы, таких как
как возникновение симуляционных событий или использование определенной функции.
Например, этот фрагмент кода взят из Ipv4L3Protocol :: IsDestinationAddress ():
если (адрес == iaddr.GetBroadcast ())
{
NS_LOG_LOGIC («Для меня (широковещательный адрес интерфейса)»);
возвращает истину;
}
Если для Протокол IPv4L3 компонент с серьезностью LOGIC or
выше (см. ниже о важности журнала), выписка будет распечатана; в противном случае это
будут подавлены.
Включение Результат
Пользователи обычно управляют выводом журнала двумя способами. Во-первых, установив
НС_ЛОГ переменная окружения; например:
$ NS_LOG = "*" ./waf - выполнить сначала
будет запускать первый обучающая программа со всеми выводами журнала. (Специфика НС_ЛОГ
формат будет рассмотрен ниже.)
Это можно сделать более детализированным, выбрав отдельные компоненты:
$ NS_LOG = "Ipv4L3Protocol" ./waf - сначала выполнить
Вывод можно дополнительно настроить с помощью параметров префикса.
Второй способ включить ведение журнала - использовать явные операторы в вашей программе, например, в
первый обучающая программа:
Int
main (int argc, char * argv [])
{
LogComponentEnable («UdpEchoClientApplication», LOG_LEVEL_INFO);
LogComponentEnable ("UdpEchoServerApplication", LOG_LEVEL_INFO);
...
(Значение LOG_LEVEL_INFO, и другие возможные значения будут рассмотрены ниже.)
НС_ЛОГ Синтаксис
" НС_ЛОГ переменная среды содержит список компонентов и параметров журнала. Бревно
компоненты разделяются символами ":":
$ NS_LOG = " : ... "
Параметры для каждого компонента журнала указаны в виде флагов после каждого компонента журнала:
$ NS_LOG = " знак равно | ...: ... "
Параметры контролируют серьезность и уровень для этого компонента, а также то, является ли он необязательным.
должна быть включена информация, такая как время моделирования, узел моделирования, функция
имя и символическая серьезность.
Журнал Компоненты
Обычно компонент журнала относится к одному исходному коду. .cc файл и включает в себя
весь файл.
У некоторых помощников есть специальные методы, позволяющие вести журнал всех компонентов в модуле,
охватывающих разные единицы компиляции, но логически сгруппированных вместе, например нс-3
код Wi-Fi:
WifiHelper
wifiHelper.EnableLogComponents();
" НС_ЛОГ Подстановочный знак компонента журнала `* 'включает все компоненты.
Чтобы узнать, какие компоненты журнала определены, подойдет любой из них:
$ NS_LOG = "список печати" ./waf --run ...
$ NS_LOG = "foo" # токен не соответствует ни одному компоненту журнала
Первая форма напечатает имя и включенные флаги для всех компонентов журнала, которые
связано в; попробуйте это с скретч-симулятор. Вторая форма распечатывает весь зарегистрированный журнал
компоненты, а затем выйдите с ошибкой.
Строгость и Уровень Возможности
Отдельные сообщения принадлежат к одному «классу серьезности», установленному макросом, создающим
сообщение. В приведенном выше примере NS_LOG_LOGIC (..) создает сообщение в LOG_LOGIC
класс серьезности.
Следующие классы серьезности определены как перечисление константы:
┌───────────────┬─────────────────────────────────── ─┐
│Класс жесткости │ Значение │
├───────────────┼─────────────────────────────────── ─┤
│LOG_NONE │ По умолчанию, без регистрации │
├───────────────┼─────────────────────────────────── ─┤
│ЛОГ_ОШИБКА │ Только сообщения о серьезных ошибках │
├───────────────┼─────────────────────────────────── ─┤
│ЛОГ_ВАРН │ Предупреждающие сообщения │
├───────────────┼─────────────────────────────────── ─┤
│LOG_DEBUG │ Для использования при отладке │
├───────────────┼─────────────────────────────────── ─┤
│ЛОГ_ИНФО │ Информационное │
├───────────────┼─────────────────────────────────── ─┤
│ЛОГ_ФУНКЦИЯ │ Трассировка функций │
├───────────────┼─────────────────────────────────── ─┤
│LOG_LOGIC │ Отслеживание потока управления внутри │
│ │ функции │
└───────────────┴─────────────────────────────────── ─┘
Обычно нужно видеть сообщения с заданным классом серьезности. и высший, Это сделано
определение «уровней» инклюзивного ведения журнала:
┌───────────────────┬─────────────────────────────── ─────┐
│Уровень │ Значение │
├────────────────────┼────────────────────────────── ─────┤
│LOG_LEVEL_ERROR │ Только ЛОГ_ОШИБКА класс серьезности │
│ │ сообщения. │
├────────────────────┼────────────────────────────── ─────┤
│LOG_LEVEL_WARN │ ЛОГ_ВАРН и выше. │
├────────────────────┼────────────────────────────── ─────┤
│LOG_LEVEL_DEBUG │ LOG_DEBUG и выше. │
├────────────────────┼────────────────────────────── ─────┤
│LOG_LEVEL_INFO │ ЛОГ_ИНФО и выше. │
├────────────────────┼────────────────────────────── ─────┤
│LOG_LEVEL_FUNCTION │ ЛОГ_ФУНКЦИЯ и выше. │
├────────────────────┼────────────────────────────── ─────┤
│LOG_LEVEL_LOGIC │ LOG_LOGIC и выше. │
├────────────────────┼────────────────────────────── ─────┤
│LOG_LEVEL_ALL │ Все классы серьезности. │
├────────────────────┼────────────────────────────── ─────┤
│LOG_ALL │ Синоним для LOG_LEVEL_ALL │
└────────────────────┴────────────────────────────── ─────┘
Параметры класса и уровня серьезности могут быть указаны в НС_ЛОГ переменная окружения
эти жетоны:
┌──────────────────────────
│Класс │ Уровень │
├──────────────────────────
│ошибка │ уровень_ошибка │
├──────────────────────────
│предупреждать │ level_warn │
├──────────────────────────
│отлаживать │ level_debug │
├──────────────────────────
│info │ level_info │
├──────────────────────────
│функция │ уровень_функция │
├──────────────────────────
│логика │ level_logic │
├──────────────────────────
│ │ level_all │
│ │ ВСЕ │
│ │ * │
└──────────────────────────
Использование токена класса серьезности позволяет регистрировать сообщения журнала только с этой серьезностью. Например,
NS_LOG = "* = предупреждать" не будет выводить сообщения с серьезностью ошибка. NS_LOG = "* = level_debug" предусматривает
выводить сообщения с уровнями серьезности отлаживать и выше.
Классы и уровни серьезности могут быть объединены с помощью символа `| ' оператор:
NS_LOG = "* = предупреждение_уровня | логика" будет выводить сообщения с уровнями серьезности ошибка, предупреждать и логика.
" НС_ЛОГ подстановочный знак уровня серьезности `* 'и ВСЕ являются синонимами для level_all.
Для компонентов журнала, просто упомянутых в НС_ЛОГ
$ NS_LOG = " : ... "
серьезность по умолчанию LOG_LEVEL_ALL.
Префикс Возможности
Ряд префиксов может помочь определить, где и когда было отправлено сообщение, и в чем
строгость.
Доступные варианты префикса (как перечисление константы) являются
┌─────────────────┬───────────────────────────────── ───┐
│Символ префикса │ Значение │
├─────────────────┼───────────────────────────────── ───┤
│LOG_PREFIX_FUNC │ Префикс имени звонящего │
│ │ функция. │
├─────────────────┼───────────────────────────────── ───┤
│LOG_PREFIX_TIME │ Введите время моделирования. │
├─────────────────┼───────────────────────────────── ───┤
│LOG_PREFIX_NODE │ Префикс идентификатора узла. │
├─────────────────┼───────────────────────────────── ───┤
│LOG_PREFIX_LEVEL │ Префикс уровня серьезности. │
├─────────────────┼───────────────────────────────── ───┤
│LOG_PREFIX_ALL │ Включить все префиксы. │
└─────────────────┴───────────────────────────────── ───┘
Параметры префикса кратко описаны ниже.
Параметры можно указать в НС_ЛОГ переменная окружения этими токенами:
┌─────────────┬────────────┐
│Token │ Альтернативный │
├─────────────┼────────────┤
│prefix_func │ FUNC │
├─────────────┼────────────┤
│префикс_время │ время │
└─────────────┴────────────┘
│префикс_узел │ узел │
├─────────────┼────────────┤
│префикс_уровень │ уровень │
├─────────────┼────────────┤
│префикс_все │ ВСЕ │
│ │ * │
└─────────────┴────────────┘
Для компонентов журнала, просто упомянутых в НС_ЛОГ
$ NS_LOG = " : ... "
параметры префикса по умолчанию: LOG_PREFIX_ALL.
Строгость Префикс
Класс серьезности сообщения может быть включен с параметрами префикс_уровень or уровень.
Например, это значение НС_ЛОГ включает ведение журнала для всех компонентов журнала (`* ') и всех
классы серьезности (= все) и ставит перед сообщением префикс класса серьезности (| prefix_level).
$ NS_LOG = "* = all | prefix_level" ./waf - запустить симулятор царапин
Симулятор царапин
[ERROR] сообщение об ошибке
[WARN] предупреждающее сообщение
[DEBUG] сообщение отладки
[INFO] информационное сообщение
[FUNCT] функциональное сообщение
[LOGIC] логическое сообщение
Время Префикс
Время моделирования может быть включено с опциями префикс_время or время. Это печатает
время моделирования в секундах.
Узел Префикс
Идентификатор узла моделирования может быть включен в параметры префикс_узел or узел.
Функция Префикс
Имя вызывающей функции может быть включено в параметры prefix_func or FUNC.
НС_ЛОГ Wildcards
Подстановочный знак компонента журнала `* 'включает все компоненты. Чтобы включить все компоненты в
использование определенного уровня серьезности знак равно.
Подстановочный знак параметра уровня серьезности `* 'является синонимом ВСЕ. Это должно произойти до того, как
`| ' варианты разделения символов. Чтобы включить все классы серьезности, используйте знак равно,
or = * |.
Подстановочный знак опции `* 'или токен ВСЕ включает все параметры префикса, но должно произойти после a
`| ' персонаж. Чтобы включить определенный класс или уровень серьезности и все префиксы, используйте
знак равно | *.
Подстановочный знак комбинированного варианта ** включает все уровни серьезности и все префиксы; Например,
знак равно.
Убер-подстановочный знак включает все уровни серьезности и все префиксы для всех компонентов журнала.
Все они эквивалентны:
$ NS_LOG = "***" ... $ NS_LOG = "* = все | *" ... $ NS_LOG = "* = * | все" ...
$ NS_LOG = "* = **" ... $ NS_LOG = "* = level_all | *" ... $ NS_LOG = "* = * | prefix_all" ...
$ NS_LOG = "* = * | *" ...
Имейте в виду: даже тривиальные скретч-симулятор производит более 46 тыс. строк вывода с
NS_LOG = "***"!
Как в каротаж в код
Добавить логирование в ваш код очень просто:
1. Вызовите NS_LOG_COMPONENT_DEFINE (...); макрос внутри Пространство имен ns3.
Создайте уникальный строковый идентификатор (обычно на основе имени файла и / или класса
определены в файле) и зарегистрируйте его с помощью макроса, например:
пространство имен ns3 {
NS_LOG_COMPONENT_DEFINE ("Протокол Ipv4L3");
...
Это регистрирует Протокол IPv4L3 как компонент журнала.
(Макрос был тщательно написан, чтобы разрешить включение как внутри, так и вне
Пространство имен ns3, и использование будет варьироваться в зависимости от кодовой базы, но первоначальная цель заключалась в том, чтобы
зарегистрируйте это внешнюю пространства имен ns3 в глобальной области видимости файла.)
2. Добавьте операторы ведения журнала (вызовы макросов) в свои функции и тела функций.
Запись Макрос
Макросы регистрации и связанные с ними уровни серьезности:
┌───────────────┬──────────────────────────
│Класс жесткости │ Макрос │
├───────────────┼──────────────────────────
│LOG_NONE │ (не требуется) │
├───────────────┼──────────────────────────
│ЛОГ_ОШИБКА │ NS_LOG_ERROR (...); │
├───────────────┼──────────────────────────
│ЛОГ_ВАРН │ NS_LOG_WARN (...); │
├───────────────┼──────────────────────────
│LOG_DEBUG │ NS_LOG_DEBUG (...); │
├───────────────┼──────────────────────────
│ЛОГ_ИНФО │ NS_LOG_INFO (...); │
├───────────────┼──────────────────────────
│ЛОГ_ФУНКЦИЯ │ NS_LOG_FUNCTION (...); │
├───────────────┼──────────────────────────
│LOG_LOGIC │ NS_LOG_LOGIC (...); │
└───────────────┴──────────────────────────
Макросы работают как выходные стримеры, поэтому все, что вы можете отправить std :: coutприсоединился
by << операторов, допускается:
void MyClass :: Check (значение типа int, char * item)
{
NS_LOG_FUNCTION (этот << аргумент << элемент);
если (аргумент> 10)
{
NS_LOG_ERROR ("обнаружено неверное значение" << значение <
"при проверке" << name << "!");
}
...
}
Обратите внимание, что NS_LOG_FUNCTION автоматически вставляет `,'(запятая-пробел) разделитель между
каждый из своих аргументов. Это упрощает регистрацию аргументов функции; просто объедините
их с << как в примере выше.
Безусловный Запись
Для удобства NS_LOG_UNCOND (...); макрос всегда будет записывать свои аргументы, даже если
связанный компонент журнала не включен ни при какой степени серьезности. Этот макрос не использует никаких
вариантов префикса. Обратите внимание, что ведение журнала включено только в отладочных сборках; этот макрос
не будет выводить данные в оптимизированных сборках.
Инструкции
· Начинайте каждый метод класса с NS_LOG_FUNCTION (этот << аргументы ...); Это позволяет легко
отслеживание вызовов функций.
· За исключением: не регистрировать операторы или явные конструкторы копирования, поскольку они вызовут
бесконечная рекурсия и переполнение стека.
· Для методов без аргументов используйте ту же форму: NS_LOG_FUNCTION (это);
· Для статических функций:
· С аргументами используйте NS_LOG_FUNCTION (...); как обычно.
· Без аргументов использовать NS_LOG_FUNCTION_NOARGS ();
· Использовать NS_LOG_ERROR для серьезных ошибок, которые, вероятно, делают моделирование недействительным
выполнение.
· Использовать NS_LOG_WARN для необычных условий, которые можно исправить. Пожалуйста, дайте несколько подсказок
относительно характера проблемы и того, как ее можно исправить.
· NS_LOG_DEBUG обычно используется в ad Специальная способ понять исполнение модели.
· Использовать NS_LOG_INFO для получения дополнительной информации о казни, такой как размер
структура данных при добавлении / удалении из нее.
· Использовать NS_LOG_LOGIC для отслеживания важных логических ветвей внутри функции.
· Убедитесь, что ваши изменения в журнале не нарушают код. Запустите несколько примеров программ с
все компоненты журнала включены (например, NS_LOG = "***").
трассировка
Подсистема трассировки - один из важнейших механизмов, которые необходимо понимать в нс-3. В
большинство случаев, нс-3 у пользователей будет блестящая идея для новых и улучшенных сетей
особенность. Чтобы убедиться, что эта идея работает, исследователь внесет изменения в
существующей системы, а затем проведите эксперименты, чтобы увидеть, как новая функция ведет себя, собирая
статистика, которая фиксирует поведение функции.
Другими словами, весь смысл запуска моделирования состоит в том, чтобы генерировать выходные данные для дальнейшего
учиться. В нс-3, подсистема, которая позволяет исследователю сделать это, - трассировка
подсистема.
трассировка мотивация
Есть много способов получить информацию из программы. Самый простой способ -
чтобы просто напрямую распечатать информацию на стандартный вывод, например,
#включать
...
int main ()
{
...
std :: cout << "Значение x равно" << x << std :: endl;
...
}
Это работает в небольших средах, но по мере того, как ваше моделирование становится все больше и больше
усложняется, вы получаете все больше и больше отпечатков, а также задачу синтаксического анализа и выполнения
вычисления на выходе становятся все труднее и труднее.
Еще одна вещь, которую следует учитывать, заключается в том, что каждый раз, когда требуется новый лакомый кусочек, программное ядро
необходимо отредактировать и ввести другой отпечаток. Не существует стандартного способа контролировать все
этого выпуска, поэтому объем выпуска имеет тенденцию неограниченно расти. В конце концов,
пропускная способность, необходимая для простого вывода этой информации, начинает ограничивать время работы
моделирования. Выходные файлы разрастаются до огромных размеров, и их анализ становится непростой задачей.
проблемы.
нс-3 предоставляет простой механизм для регистрации и обеспечения некоторого контроля над выводом через
Журнал Компоненты, но уровень контроля вообще не очень мелкий. Регистрация
модуль - относительно тупой инструмент.
Желательно иметь средство, позволяющее проникнуть в основную систему и только
получить необходимую информацию без изменения и перекомпиляции основной системы. Четное
лучше была бы система, которая уведомляла пользователя об изменении интересующего элемента или
произошло интересное событие.
" нс-3 система отслеживания предназначена для работы в этом направлении и хорошо интегрирована с
подсистемы Attribute и Config, обеспечивающие относительно простые сценарии использования.
Обзор
Подсистема трассировки во многом зависит от нс-3 Механизмы обратного вызова и атрибутов. Ты
следует прочитать и понять соответствующие разделы руководства, прежде чем пытаться
понимать систему отслеживания.
" нс-3 система слежения построена на концепциях независимых источников слежения и
отслеживание раковин; вместе с единым механизмом подключения источников к мойкам.
Источники трассировки - это объекты, которые могут сигнализировать о событиях, происходящих при моделировании, и обеспечивать
доступ к интересным базовым данным. Например, источник трассировки может указывать, когда
пакет принимается сетевым устройством и обеспечивает доступ к содержимому пакета для
интересует след мойки. Источник трассировки также может указывать, когда интересное состояние
изменение происходит в модели. Например, окно перегрузки модели TCP является основным
кандидат в источник следов.
Источники трассировки сами по себе бесполезны; они должны быть связаны с другими частями кода
которые действительно делают что-то полезное с информацией, предоставленной источником. В
объекты, которые потребляют информацию трассировки, называются приемниками трассировки. Источники следов:
генераторы событий и приемники трассировки являются потребителями.
Такое явное разделение позволяет разбросать большое количество источников трассировки.
система в тех местах, которые, по мнению авторов модели, могут быть полезны. Если пользователь не подключит
Приемник трассировки к одному из этих источников, ничего не выводится. Такое расположение позволяет относительно
неискушенные пользователи присоединяют новые типы приемников к существующим источникам трассировки без
требующие редактирования и перекомпиляции ядра или моделей симулятора.
Может быть ноль или более потребителей событий трассировки, генерируемых источником трассировки. Можно
Считайте источник трассировки своего рода информационным каналом многоточечного соединения.
«Транспортный протокол» для этой концептуальной многоточечной связи является нс-3 Обратный звонок.
Напомним из раздела «Обратный вызов», что функция обратного вызова - это способ разрешить два модуля в
система для связи через вызовы функций, в то же время разъединяя вызов
функция из вызываемого класса полностью. Это такое же требование, как указано выше.
для системы отслеживания.
По сути, источник следа is обратный вызов, для которого могут быть зарегистрированы несколько функций.
Когда приемник трассировки выражает заинтересованность в получении событий трассировки, он добавляет обратный вызов к
список обратных вызовов, содержащихся в источнике трассировки. Когда происходит интересное событие, след
источник ссылается на свой Оператор () предоставление нуля или более параметров. Это сообщает источнику
просмотреть его список обратных вызовов, вызывая каждый из них по очереди. Таким образом, параметр (ы)
передаются приемникам трассировки, которые являются просто функциями.
" самый простой Пример
Будет полезно пройти небольшой пример, чтобы подкрепить сказанное:
#include "ns3 / object.h"
#include "ns3 / uinteger.h"
#include "ns3 / traced-value.h" "
#include "ns3 / trace-source-accessor.h"
#включать
используя пространство имен ns3;
Первое, что нужно сделать, это включить необходимые файлы. Как уже упоминалось выше, система трассировки
активно использует системы объектов и атрибутов. Первые два включают в себя
декларации для этих систем. Файл, трассируемое-значение.h вносит необходимые
объявления для отслеживания данных, которые подчиняются семантике значений.
В общем, семантика значений просто означает, что вы можете передавать объект, а не
адрес. Чтобы вообще использовать семантику значений, у вас должен быть объект с
связанный конструктор копирования и оператор присваивания доступны. Расширяем требования
чтобы поговорить о наборе операторов, которые предопределены для типов простых старых данных (POD).
Оператор =, оператор ++, оператор--, оператор +, оператор == и т. Д.
Все это означает, что вы сможете отслеживать изменения объекта, сделанные с помощью
эти операторы:
класс MyObject: публичный объект
{
общественности:
статический TypeId GetTypeId (недействительный)
{
статический TypeId tid = TypeId ("MyObject")
.SetParent (Объект :: GetTypeId ())
.AddConstructor ()
.AddTraceSource ("MyInteger",
"Целочисленное значение для отслеживания.",
MakeTraceSourceAccessor (& MyObject :: m_myInt))
;
вернуть tid;
}
МойОбъект () {}
TracedValue m_myInt;
};
Поскольку система трассировки интегрирована с атрибутами, а атрибуты работают с объектами,
должен быть нс-3 объект для источника трассировки, чтобы жить в. Две важные линии
код .AddTraceSource и трассируемое значение декларация.
" .AddTraceSource предоставляет "крючки", используемые для подключения источника трассировки к
внешний мир. В трассируемое значение декларация предоставляет инфраструктуру, которая перегружает
упомянутые выше операторы и управляют процессом обратного вызова:
аннулировать
IntTrace (Int oldValue, Int новое значение)
{
std :: cout << "Traced" << oldValue << "to" << newValue << std :: endl;
}
Это определение приемника следа. Он напрямую соответствует функции обратного вызова.
Эта функция будет вызываться всякий раз, когда один из операторов трассируемое значение is
выполнен .:
Int
main (int argc, char * argv [])
{
Ptr myObject = CreateObject ();
myObject-> TraceConnectWithoutContext ("MyInteger", MakeCallback (& IntTrace));
myObject-> m_myInt = 1234;
}
В этом фрагменте первое, что нужно сделать, - это создать объект, в котором
источник трассировки жив.
Следующий шаг, Трассеконнектвисаутконтекст, образует связь между следом
источник и приемник трассировки. Обратите внимание на Обратный звонок шаблонная функция. Напомним из
Раздел обратного вызова, который создает специализированный функтор, отвечающий за предоставление
перегруженный Оператор () используется для "запуска" обратного вызова. Перегруженные операторы (++, - и т. Д.)
будет использовать это Оператор () чтобы фактически вызвать обратный вызов. В Трассеконнектвисаутконтекст,
принимает строковый параметр, который предоставляет имя атрибута, назначенного трассировке
источник. Давайте пока проигнорируем немного о контексте, поскольку это еще не важно.
Наконец, строка:
myObject-> m_myInt = 1234;
следует интерпретировать как обращение к оператор = на переменной-члене m_myInt
целое число 1234 передано в качестве параметра. Оказывается, этот оператор определяется (
трассируемое значение) для выполнения обратного вызова, который возвращает void и принимает два целых значения как
параметры - старое значение и новое значение для рассматриваемого целого числа. Это точно
сигнатура функции для функции обратного вызова, которую мы предоставили - ИнтТрейс.
Подводя итог, можно сказать, что источник трассировки - это, по сути, переменная, содержащая список обратных вызовов. А
приемник трассировки - это функция, используемая в качестве цели обратного вызова. Атрибут и тип объекта
информационные системы используются для обеспечения способа подключения источников трассировки к приемникам трассировки. В
акт "попадания" в источник трассировки - это выполнение оператора на источнике трассировки, который запускает
обратные вызовы. Это приводит к тому, что обратные вызовы приемника трассировки регистрируют интерес к источнику.
вызывается с параметрами, предоставленными источником.
. Конфиг подсистема в Связаться в Прослеживать Источники
" Трассеконнектвисаутконтекст вызов, показанный выше в простом примере, на самом деле очень
редко используется в системе. Чаще Конфиг подсистема используется для выбора
источник трассировки в системе, использующий то, что называется конфиг путь.
Например, можно найти в системе что-то похожее на следующее (взято
от примеры / tcp-large-transfer.cc):
void CwndTracer (uint32_t старое значение, uint32_t новое значение) {}
...
Config :: ConnectWithoutContext (
"/ NodeList / 0 / $ ns3 :: TcpL4Protocol / SocketList / 0 / CongestionWindow",
MakeCallback (& CwndTracer));
Это должно выглядеть очень знакомо. Это то же самое, что и в предыдущем примере, за исключением того, что
статическая функция-член класса Конфиг вызывается вместо метода на объект;
и вместо Атрибут имя, путь предоставляется.
Первое, что нужно сделать, это прочитать путь в обратном направлении. Последний отрезок пути должен быть
an Атрибут из объект. Фактически, если бы у вас был указатель на объект это имеет
"Окно скопления" Атрибут удобно (назовите это объект), вы можете написать это так же, как
предыдущий пример:
void CwndTracer (uint32_t старое значение, uint32_t новое значение) {}
...
theObject-> TraceConnectWithoutContext ("CongestionWindow", MakeCallback (& CwndTracer));
Оказывается, код для Config :: ConnectWithoutContext делает именно это. Этот
функция берет путь, который представляет собой цепочку объект указатели и следует за ними, пока не
доходит до конца пути и интерпретирует последний сегмент как Атрибут на последнем
объект. Давайте разберемся, что происходит.
Начальный символ «/» в пути относится к так называемому пространству имен. Один из
предопределенным пространством имен в системе конфигурации является «NodeList», который представляет собой список всех
узлов в моделировании. Элементы в списке упоминаются индексами в списке, поэтому
«/ NodeList / 0» относится к нулевому узлу в списке узлов, созданном симуляцией.
Этот узел на самом деле Ptr и это подкласс ns3 :: Объект.
Как описано в разделе "Объектная модель", нс-3 поддерживает модель агрегирования объектов. В
следующий сегмент пути начинается с символа «$», который указывает ПолучитьОбъект звонок должен быть
сделал поиск следующего типа. Когда узел инициализируется
Интернет-технологии ряд интерфейсов объединены с узлом. Один из них -
Протокол TCP четвертого уровня. Тип среды выполнения этого объекта протокола: ns3 :: TcpL4Protocol ''.
После появления `` GetObject выполняется, он возвращает указатель на объект этого типа.
" Протокол TcpL4 класс определяет атрибут под названием "SocketList", который представляет собой список
Розетки. Каждый сокет на самом деле ns3 :: Объект с собственными Атрибуты. Пункты в
список сокетов упоминается по индексу так же, как в NodeList, поэтому "SocketList / 0"
относится к нулевому сокету в списке сокетов на нулевом узле в NodeList -
первый узел, построенный в моделировании.
Эта розетка, тип которой оказывается ns3 :: TcpSocketImpl определяет атрибут
называется "CongestionWindow", который является TracedValue,
Config :: ConnectWithoutContext теперь делает:
объект-> TraceConnectWithoutContext ("CongestionWindow", MakeCallback (& CwndTracer));
используя указатель объекта из "SocketList / 0", который устанавливает связь между трассировкой
источник, определенный в сокете для обратного вызова - CwndTracer.
Теперь, когда в TracedValue представляющий скопление
в TCP-сокете, будет выполнен зарегистрированный обратный вызов и функция
CwndTracer будет вызываться печать старых и новых значений перегрузки TCP
окно.
. трассировка API
Существует три уровня взаимодействия с системой отслеживания:
· Начинающий пользователь может легко контролировать, какие объекты участвуют в трассировке;
· Пользователи среднего уровня могут расширить систему трассировки, чтобы изменить создаваемый выходной формат.
или использовать существующие источники трассировки по-разному, не изменяя ядро
симулятор;
· Опытные пользователи могут модифицировать ядро симулятора, добавляя новые источники и приемники трассировки.
. Прослеживать Помощники
" нс-3 помощники по трассировке предоставляют богатую среду для настройки и выбора различных
отслеживать события и записывать их в файлы. В предыдущих разделах, в первую очередь, «Строительство
Топологии ", мы видели несколько разновидностей вспомогательных методов трассировки, предназначенных для использования
внутри других помощников (устройства).
Возможно, вы помните, что видели некоторые из этих вариаций:
pointToPoint.EnablePcapAll («второй»);
pointToPoint.EnablePcap («второй», p2pNodes.Get (0) -> GetId (), 0);
csma.EnablePcap ("третий", csmaDevices.Get (0), истина);
pointToPoint.EnableAsciiAll (ascii.CreateFileStream ("myfirst.tr"));
Что может быть неочевидным, так это то, что существует последовательная модель для всех
методы, связанные с трассировкой, найденные в системе. Сейчас мы уделим немного времени и взглянем
на «общую картину».
В настоящее время существует два основных варианта использования помощников по трассировке в нс-3: Помощники устройств
и помощники протокола. Помощники по устройствам решают проблему указания, какие трассировки следует
быть включенным через узел, пару устройств. Например, вы можете указать, что pcap
трассировка должна быть включена на определенном устройстве на определенном узле. Это следует из
нс-3 концептуальная модель устройства, а также концептуальные модели различных устройств
помощники. Естественно, следуя этому, созданные файлы следуют
- - соглашение об именовании.
Помощники протокола рассматривают проблему указания, какие трассировки должны быть включены через
пара протокола и интерфейса. Это следует из нс-3 концептуальная модель стека протоколов,
а также концептуальные модели помощников интернет-стека. Естественно, файлы трассировки
должен следовать - - соглашение об именовании.
Таким образом, помощники трассировки естественным образом попадают в двухмерную таксономию. Есть
тонкости, которые мешают всем четырем классам вести себя одинаково, но мы стремимся к тому, чтобы
сделать так, чтобы все они работали как можно схоже; и по возможности есть аналоги для
все методы во всех классах.
┌────────────────┬──────┬───────
│ │ pcap │ ascii │
├────────────────┼──────┼───────
│Помощник по устройству │ │ │
├────────────────┼──────┼───────
│Программный помощник │ │ │
└────────────────┴──────┴───────
Мы используем подход, называемый Mixin чтобы добавить функцию трассировки в наши вспомогательные классы. А
Mixin - это класс, который обеспечивает функциональность, наследуемую подклассом.
Наследование от миксина не считается формой специализации, но на самом деле является способом
собрать функционал.
Давайте кратко рассмотрим все четыре случая и их соответствующие Примеси.
ПКП трассировка Устройство Помощники
Цель этих помощников - упростить добавление единообразного средства трассировки pcap в
нс-3 устройство. Мы хотим, чтобы все разновидности трассировки pcap одинаково работали
все устройства, поэтому методы этих помощников наследуются помощниками устройств. Посмотри
at SRC / сеть / помощник / трассировка-помощник.h если вы хотите следить за обсуждением, глядя на
реальный код.
Класс Пкахелперфордевице - это Mixin обеспечивает функциональность высокого уровня для использования
трассировка pcap в нс-3 устройство. Каждое устройство должно реализовывать один виртуальный метод
унаследован от этого класса .:
virtual void EnablePcapInternal (префикс std :: string, Ptr nd, булево беспорядочные) = 0;
Сигнатура этого метода отражает аппаратно-ориентированный взгляд на ситуацию на данном этапе.
уровень. Все общедоступные методы, унаследованные от класса Пкапусерхелперфордевице сократить до
вызов этого единственного метода реализации, зависящего от устройства. Например, самый низкий уровень
pcap метод ,:
void EnablePcap (префикс std :: string, Ptr nd, bool promiscuous = false, bool explicitFilename = false);
вызовет реализацию устройства EnablePcapInternal напрямую. Все остальные общедоступные pcap
методы трассировки основаны на этой реализации, чтобы обеспечить дополнительный уровень пользователя
функциональность. Для пользователя это означает, что все помощники устройств в системе будут
иметь все доступные методы трассировки pcap; и все эти методы будут работать в одном
путь через устройства, если устройство реализует EnablePcapInternal правильно.
ПКП трассировка Устройство Помощник методы
void EnablePcap (префикс std :: string, Ptr nd,
логическое значение promiscuous = false, логическое явное имя_файла = false);
void EnablePcap (префикс std :: string, std :: string ndName,
логическое значение promiscuous = false, логическое явное имя_файла = false);
void EnablePcap (префикс std :: string, NetDeviceContainer d,
логическое беспорядочное = ложное);
void EnablePcap (префикс std :: string, NodeContainer n,
логическое беспорядочное = ложное);
void EnablePcap (std :: string prefix, uint32_t nodeid, uint32_t deviceid,
логическое беспорядочное = ложное);
void EnablePcapAll (префикс std :: string, bool promiscuous = false);
В каждом из методов, показанных выше, есть параметр по умолчанию, называемый разнородный который
по умолчанию - false. Этот параметр указывает, что трассировку не следует собирать в
беспорядочный режим. Если вы хотите, чтобы ваши трассировки включали весь трафик, видимый устройством
(и если устройство поддерживает неразборчивый режим) просто добавьте истинный параметр к любому из
звонки выше. Например,:
Ptr nd;
...
helper.EnablePcap («префикс», nd, истина);
включит неразборчивый режим захвата на NetDevice указано nd.
Первые два метода также включают параметр по умолчанию, называемый явное имя файла что будет
обсуждается ниже.
Предлагаем вам ознакомиться с Doxygen для занятий Пкахелперфордевице чтобы узнать подробности
этих методов; но подведем итог ...
Вы можете включить трассировку pcap для конкретной пары узел / сетевое устройство, предоставив
Ptr к ВключитьPcap метод. Ptr неявно, поскольку сетевое устройство
должен принадлежать ровно одному Узел. Например,:
Ptr nd;
...
helper.EnablePcap («префикс», nd);
Вы можете включить трассировку pcap для конкретной пары узел / сетевое устройство, предоставив
станд :: строка представление служебной строки имени объекта для ВключитьPcap метод.
Ptr ищется из строки имени. Опять же, неявно, поскольку
названное сетевое устройство должно принадлежать ровно одному Узел. Например,:
Names :: Add ("сервер" ...);
Имена :: Добавить ("server / eth0" ...);
...
helper.EnablePcap («префикс», «сервер / ath0»);
Вы можете включить трассировку pcap для коллекции пар узел / сетевое устройство, предоставив
NetDeviceContainer, Для каждого NetDevice в контейнере проверяется тип. Для каждого
устройство правильного типа (того же типа, которым управляет помощник устройства), трассировка
включено. Опять же, неявно, поскольку найденное сетевое устройство должно принадлежать точно
one Узел. Например,:
NetDeviceContainer d = ...;
...
helper.EnablePcap («префикс», d);
Вы можете включить трассировку pcap для коллекции пар узел / сетевое устройство, предоставив
Нодконтейнер, Для каждого Узел в Нодконтейнер это прикреплено Сетевые устройства повторяются.
Для каждого NetDevice прикрепленный к каждому узлу в контейнере, тип этого устройства
проверил. Для каждого устройства соответствующего типа (того же типа, которым управляет устройство
помощник), трассировка включена .:
Контейнер узлов n;
...
helper.EnablePcap («префикс», n);
Вы можете включить трассировку pcap на основе идентификатора узла и идентификатора устройства, а также с явным
Ptr. Каждый Узел в системе есть целочисленный идентификатор узла и каждое устройство, подключенное к узлу
имеет целочисленный идентификатор устройства .:
helper.EnablePcap («префикс», 21, 1);
Наконец, вы можете включить трассировку pcap для всех устройств в системе с тем же типом, что и
который управляется помощником устройства .:
helper.EnablePcapAll («префикс»);
ПКП трассировка Устройство Помощник Имя файла Выбор
В приведенных выше описаниях методов подразумевается построение полного имени файла с помощью
способ реализации. По соглашению, трассировки pcap в нс-3 системы имеют вид
- id> - id> .pcap
Как упоминалось ранее, каждому узлу в системе будет назначен идентификатор узла; и
каждое устройство будет иметь индекс интерфейса (также называемый идентификатором устройства) относительно его узла.
По умолчанию файл трассировки pcap создается в результате включения трассировки на первом этапе.
устройство узла 21 с использованием префикса «префикс» будет префикс-21-1.pcap.
Вы всегда можете использовать нс-3 служба имен объектов, чтобы прояснить это. Например, если
вы используете службу имен объектов, чтобы присвоить имя "server" узлу 21, в результате чего pcap
имя файла трассировки автоматически станет, префикс-сервер-1.pcap и если вы также назначите
имя "eth0" на устройство, ваше имя файла pcap автоматически подберет это и будет
под названием префикс-сервер-eth0.pcap.
Наконец, два метода, показанных выше:
void EnablePcap (префикс std :: string, Ptr nd, bool promiscuous = false, bool explicitFilename = false);
void EnablePcap (std :: string prefix, std :: string ndName, bool promiscuous = false, bool explicitFilename = false);
иметь параметр по умолчанию, называемый явное имя файла. Если установлено значение true, этот параметр
отключает механизм автоматического завершения имени файла и позволяет создавать явное
имя файла. Эта опция доступна только в методах, которые включают трассировку pcap на
одиночное устройство.
Например, чтобы организовать помощник устройства для создания единого беспорядочного pcap
файл захвата с определенным именем (мой-pcap-file.pcap) на данном устройстве можно было:
Ptr nd;
...
helper.EnablePcap ("my-pcap-file.pcap", nd, true, true);
Первый правда параметр включает трассировку беспорядочного режима, а второй сообщает помощнику
интерпретировать префикс параметр как полное имя файла.
ASCII трассировка Устройство Помощники
Поведение помощника по трассировке ascii Mixin по существу похож на версию pcap.
Взгляни на SRC / сеть / помощник / трассировка-помощник.h если вы хотите следить за обсуждением
глядя на реальный код.
Класс AsciiTraceHelperForDevice добавляет функциональность высокого уровня для использования ascii
трассировка до вспомогательного класса устройства. Как и в случае с pcap, каждое устройство должно реализовывать
единственный виртуальный метод, унаследованный от трассировки ascii Mixin.:
виртуальная пустота EnableAsciiInternal (Ptr поток, префикс std :: string, Ptr nd) = 0;
Сигнатура этого метода отражает аппаратно-ориентированный взгляд на ситуацию на данном этапе.
уровень; а также тот факт, что помощник может писать в общий выходной поток. Все
общедоступные методы, связанные с ascii-trace, унаследованные от класса AsciiTraceHelperForDevice
сократить до вызова этого единственного метода реализации, зависящего от устройства. Например,
методы трассировки ascii самого низкого уровня:
void EnableAscii (префикс std :: string, Ptr nd);
void EnableAscii (Ptr поток, Ptr nd);
вызовет реализацию устройства ВключитьAsciiInternal напрямую, обеспечивая либо
действительный префикс или поток. Все другие общедоступные методы трассировки ascii будут основываться на этих
низкоуровневые функции для обеспечения дополнительных функций пользовательского уровня. Что это значит для
Пользователь, чтобы у всех помощников устройств в системе были все методы трассировки ascii
доступный; и эти методы будут работать одинаково на всех устройствах, если устройства
осуществлять EnablAsciiВнутренний правильно.
ASCII трассировка Устройство Помощник методы
void EnableAscii (префикс std :: string, Ptr nd);
void EnableAscii (Ptr поток, Ptr nd);
void EnableAscii (префикс std :: string, std :: string ndName);
void EnableAscii (Ptr поток, std :: string ndName);
void EnableAscii (префикс std :: string, NetDeviceContainer d);
void EnableAscii (Ptr поток, NetDeviceContainer d);
void EnableAscii (префикс std :: string, NodeContainer n);
void EnableAscii (Ptr поток, NodeContainer n);
void EnableAscii (std :: string prefix, uint32_t nodeid, uint32_t deviceid);
void EnableAscii (Ptr поток, uint32_t nodeid, uint32_t deviceid);
void EnableAsciiAll (префикс std :: string);
void EnableAsciiAll (Ptr ручей);
Предлагаем вам ознакомиться с Doxygen для занятий Трассехелперфордевице найти
подробности этих методов; но подведем итог ...
Для трассировки ascii доступно в два раза больше методов, чем для pcap.
отслеживание. Это потому, что в дополнение к модели в стиле pcap, где следы от каждого
уникальная пара узел / устройство записывается в уникальный файл, мы поддерживаем модель, в которой трассировка
информация для многих пар узел / устройство записывается в общий файл. Это означает, что
- - механизм генерации имени файла заменен механизмом
обратиться к общему файлу; а количество методов API увеличено вдвое, чтобы все
комбинации.
Как и в случае с трассировкой pcap, вы можете включить трассировку ascii для конкретной пары узел / сеть-устройство.
предоставив Ptr к Включить Ascii метод. Ptr неявно, поскольку
сетевое устройство должно принадлежать ровно одному Узел. Например,:
Ptr nd;
...
helper.EnableAscii ("префикс", nd);
В этом случае контексты трассировки не записываются в файл трассировки ascii, поскольку они будут
избыточный. Система выберет имя файла для создания по тем же правилам, что и
описан в разделе pcap, за исключением того, что файл будет иметь суффикс ".tr" вместо
".pcap".
Если вы хотите включить трассировку ascii на более чем одном сетевом устройстве и отправить все трассировки
в один файл, вы также можете сделать это, используя объект для ссылки на один файл:
Ptr nd1;
Ptr nd2;
...
Ptr stream = asciiTraceHelper.CreateFileStream ("имя-файла-трассировки.tr");
...
helper.EnableAscii (поток, nd1);
helper.EnableAscii (поток, nd2);
В этом случае контексты трассировки записываются в файл трассировки ascii, поскольку они необходимы
для устранения неоднозначности следов от двух устройств. Обратите внимание: поскольку пользователь полностью
при указании имени файла строка должна включать ".tr" для единообразия.
Вы можете включить трассировку ascii для конкретной пары узел / сетевое устройство, предоставив
станд :: строка представление служебной строки имени объекта для ВключитьPcap метод.
Ptr ищется из строки имени. Опять же, неявно, поскольку
названное сетевое устройство должно принадлежать ровно одному Узел. Например,:
Names :: Add ("клиент" ...);
Имена :: Добавить ("client / eth0" ...);
Names :: Add ("сервер" ...);
Имена :: Добавить ("server / eth0" ...);
...
helper.EnableAscii («префикс», «клиент / eth0»);
helper.EnableAscii («префикс», «сервер / eth0»);
Это приведет к появлению двух файлов с именем префикс-клиент-eth0.tr и префикс-сервер-eth0.tr
трассировки для каждого устройства в соответствующем файле трассировки. Поскольку все EnableAscii
функции перегружены, чтобы принять оболочку потока, вы также можете использовать эту форму:
Names :: Add ("клиент" ...);
Имена :: Добавить ("client / eth0" ...);
Names :: Add ("сервер" ...);
Имена :: Добавить ("server / eth0" ...);
...
Ptr stream = asciiTraceHelper.CreateFileStream ("имя-файла-трассировки.tr");
...
helper.EnableAscii (поток, «клиент / eth0»);
helper.EnableAscii (поток, «сервер / eth0»);
Это приведет к созданию единственного файла трассировки с именем имя-файла-трассировки.tr который содержит все
события трассировки для обоих устройств. События будут устранены контекстом трассировки
строки.
Вы можете включить трассировку ascii для коллекции пар узел / сетевое устройство, предоставив
NetDeviceContainer, Для каждого NetDevice в контейнере проверяется тип. Для каждого
устройство правильного типа (того же типа, которым управляет помощник устройства), трассировка
включено. Опять же, неявно, поскольку найденное сетевое устройство должно принадлежать точно
one Узел. Например,:
NetDeviceContainer d = ...;
...
helper.EnableAscii ("префикс", d);
Это приведет к созданию ряда файлов трассировки ascii, каждый из которых следует
в - - .tr соглашение. Объединение всех следов в
single file выполняется аналогично приведенным выше примерам:
NetDeviceContainer d = ...;
...
Ptr stream = asciiTraceHelper.CreateFileStream ("имя-файла-трассировки.tr");
...
helper.EnableAscii (поток, d);
Вы можете включить трассировку ascii для коллекции пар узел / сетевое устройство, предоставив
Нодконтейнер, Для каждого Узел в Нодконтейнер это прикреплено Сетевые устройства повторяются.
Для каждого NetDevice прикрепленный к каждому узлу в контейнере, тип этого устройства
проверил. Для каждого устройства соответствующего типа (того же типа, которым управляет устройство
помощник), трассировка включена .:
Контейнер узлов n;
...
helper.EnableAscii ("префикс", n);
Это приведет к созданию ряда файлов трассировки ascii, каждый из которых следует
в - - .tr соглашение. Объединение всех следов в
single file выполняется аналогично приведенным выше примерам:
Вы можете включить трассировку pcap на основе идентификатора узла и идентификатора устройства, а также с явным
Ptr. Каждый Узел в системе есть целочисленный идентификатор узла и каждое устройство, подключенное к узлу
имеет целочисленный идентификатор устройства .:
helper.EnableAscii ("префикс", 21, 1);
Конечно, следы можно объединить в один файл, как показано выше.
Наконец, вы можете включить трассировку pcap для всех устройств в системе с тем же типом, что и
который управляется помощником устройства .:
helper.EnableAsciiAll («префикс»);
Это приведет к созданию нескольких файлов трассировки ascii, по одному для каждого устройства в
система типа, управляемая помощником. Все эти файлы будут следовать за
- - .tr соглашение. Объединение всех следов в одну
file выполняется аналогично приведенным выше примерам.
ASCII трассировка Устройство Помощник Имя файла Выбор
В приведенных выше описаниях методов префиксного стиля подразумевается построение полного
имена файлов по способу реализации. По соглашению, ascii трассируется в нс-3 система
формы - id> - id> .tr.
Как упоминалось ранее, каждому узлу в системе будет назначен идентификатор узла; и
каждое устройство будет иметь индекс интерфейса (также называемый идентификатором устройства) относительно его узла.
По умолчанию файл трассировки ascii, созданный в результате включения трассировки на первом
устройство узла 21, используя префикс «префикс», будет префикс-21-1.tr.
Вы всегда можете использовать нс-3 служба имен объектов, чтобы прояснить это. Например, если
вы используете службу имен объектов, чтобы присвоить имя «сервер» узлу 21, в результате
Имя файла трассировки ascii автоматически станет, префикс-сервер-1.tr и если вы также назначаете
имя "eth0" для устройства, ваше имя файла трассировки ascii автоматически подберет это
и называться префикс-сервер-eth0.tr.
ПКП трассировка протокол Помощники
Цель этих Примеси состоит в том, чтобы упростить добавление единообразного средства трассировки pcap в
протоколы. Мы хотим, чтобы все разновидности трассировки pcap работали одинаково во всех
протоколы, поэтому методы этих помощников наследуются помощниками стека. Взгляни на
SRC / сеть / помощник / трассировка-помощник.h если вы хотите следить за обсуждением, глядя на
реальный код.
В этом разделе мы проиллюстрируем методы применительно к протоколу. Ipv4. К
укажите трассировки в аналогичных протоколах, просто подставьте соответствующий тип. Например,
использовать Ptr вместо Ptr и вызов ВключитьPcapIpv6 вместо ВключитьPcapIpv4.
Класс Пкапхелперфорипв4 обеспечивает функциональность высокого уровня для использования трассировки pcap
в Ipv4 протокол. Каждый помощник протокола, включающий эти методы, должен реализовывать один
виртуальный метод, унаследованный от этого класса. Будет отдельная реализация для
Ipv6, например, но разница будет только в именах методов и сигнатурах.
Для устранения неоднозначности класса требуются разные имена методов. Ipv4 от Ipv6 которые оба
производный от класса объект, и методы, имеющие одну и ту же сигнатуру .:
virtual void EnablePcapIpv4Internal (префикс std :: string, Ptr ipv4, интерфейс uint4_t) = 32;
Сигнатура этого метода отражает взгляд на протокол и интерфейс, ориентированный на
ситуация на этом уровне. Все общедоступные методы, унаследованные от класса Пкапхелперфорипв4
сократить до вызова этого единственного метода реализации, зависящего от устройства. Например,
метод pcap самого низкого уровня:
void EnablePcapIpv4 (префикс std :: string, Ptr ipv4, интерфейс uint4_t);
вызовет реализацию устройства Енаблепкаипв4интернал напрямую. Все остальные общественные
Методы трассировки pcap основаны на этой реализации, чтобы обеспечить дополнительный уровень пользователя.
функциональность. Для пользователя это означает, что все помощники протокола в системе будут
иметь все доступные методы трассировки pcap; и все эти методы будут работать в одном
путь через протоколы, если помощник реализует Енаблепкаипв4интернал правильно.
ПКП трассировка протокол Помощник методы
Эти методы предназначены для взаимно однозначного соответствия с Узел- а также
NetDevice- центрические версии версий устройства. Вместо Узел и NetDevice пара
ограничения, мы используем ограничения протокола и интерфейса.
Обратите внимание, что, как и в версии для устройства, существует шесть методов:
void EnablePcapIpv4 (префикс std :: string, Ptr ipv4, интерфейс uint4_t);
void EnablePcapIpv4 (префикс std :: string, std :: string ipv4Name, интерфейс uint32_t);
void EnablePcapIpv4 (префикс std :: string, Ipv4InterfaceContainer c);
void EnablePcapIpv4 (префикс std :: string, NodeContainer n);
void EnablePcapIpv4 (префикс std :: string, uint32_t nodeid, интерфейс uint32_t);
void EnablePcapIpv4All (префикс std :: string);
Предлагаем вам ознакомиться с Doxygen для занятий Пкапхелперфорипв4 чтобы узнать подробности
этих методов; но подведем итог ...
Вы можете включить трассировку pcap для конкретной пары протокол / интерфейс, предоставив
Ptr и интерфейс к ВключитьPcap метод. Например,:
Ptr ipv4 = узел-> GetObject ();
...
helper.EnablePcapIpv4 («префикс», ipv4, 0);
Вы можете включить трассировку pcap для конкретной пары узел / сетевое устройство, предоставив
станд :: строка представление служебной строки имени объекта для ВключитьPcap метод.
Ptr ищется из строки имени. Например,:
Имена :: Добавить ("serverIPv4" ...);
...
helper.EnablePcapIpv4 («префикс», «serverIpv4», 1);
Вы можете включить трассировку pcap для набора пар протокол / интерфейс, предоставив
Ipv4InterfaceContainer, Для каждого Ipv4 / interface пара в контейнере тип протокола
проверено. Для каждого протокола соответствующего типа (того же типа, которым управляет
помощник устройства), трассировка включена для соответствующего интерфейса. Например,:
Узлы NodeContainer;
...
Устройства NetDeviceContainer = deviceHelper.Install (узлы);
...
Ipv4AddressHelper ipv4;
ipv4.SetBase («10.1.1.0», «255.255.255.0»);
Интерфейсы Ipv4InterfaceContainer = ipv4.Assign (устройства);
...
helper.EnablePcapIpv4 («префикс», интерфейсы);
Вы можете включить трассировку pcap для набора пар протокол / интерфейс, предоставив
Нодконтейнер, Для каждого Узел в Нодконтейнер найден соответствующий протокол. За
перечисляются каждый протокол, его интерфейсы, а на результирующем
пары. Например,:
Контейнер узлов n;
...
helper.EnablePcapIpv4 («префикс», n);
Вы также можете включить трассировку pcap на основе идентификатора узла и интерфейса. В таком случае,
идентификатор узла переводится в Ptr и соответствующий протокол ищется в
узел. Результирующий протокол и интерфейс используются для определения результирующей трассировки.
источник.:
helper.EnablePcapIpv4 («префикс», 21, 1);
Наконец, вы можете включить трассировку pcap для всех интерфейсов в системе с соответствующими
протокол того же типа, что и управляемый помощником устройства .:
helper.EnablePcapIpv4All («префикс»);
ПКП трассировка протокол Помощник Имя файла Выбор
Во всех приведенных выше описаниях методов подразумевается построение полного
имена файлов по способу реализации. По соглашению, трассировки pcap, взятые для устройств в
нс-3 системы имеют вид - id> - id> .pcap, В случае
трассировок протоколов, существует взаимно однозначное соответствие между протоколами и Nodes. Это
потому что протокол Объекты объединены в Узел Объекты. Поскольку нет глобального протокола
id в системе, мы используем соответствующий идентификатор узла в именовании файлов. Следовательно, есть
возможность коллизии имен файлов в автоматически выбранных именах файлов трассировки. Для этого
По этой причине соглашение об именах файлов изменено для трассировок протокола.
Как упоминалось ранее, каждому узлу в системе будет назначен идентификатор узла.
Поскольку существует взаимно однозначное соответствие между экземплярами протокола и экземплярами узлов
мы используем идентификатор узла. Каждый интерфейс имеет идентификатор интерфейса, соответствующий его протоколу. Мы используем
конвенция " -n -я .pcap "для именования файлов трассировки в
помощники протокола.
Поэтому по умолчанию файл трассировки pcap, созданный в результате включения трассировки на
интерфейс 1 протокола IPv4 узла 21 с использованием префикса «префикс» будет
«префикс-n21-i1.pcap».
Вы всегда можете использовать нс-3 служба имен объектов, чтобы прояснить это. Например, если
вы используете службу имен объектов, чтобы присвоить Ptr имя serverIpv4. на узле
21, имя результирующего файла трассировки pcap автоматически станет,
«префикс-nserverIpv4-i1.pcap».
ASCII трассировка протокол Помощники
Поведение помощников трассировки ascii в основном аналогично случаю pcap. Взять
смотреть на SRC / сеть / помощник / трассировка-помощник.h если вы хотите следить за обсуждением, пока
глядя на реальный код.
В этом разделе мы проиллюстрируем методы применительно к протоколу. Ipv4. К
укажите трассировки в аналогичных протоколах, просто подставьте соответствующий тип. Например,
использовать Ptr вместо Ptr и вызов ВключитьAsciiIpv6 вместо
ВключитьAsciiIpv4.
Класс AsciiTraceHelperForIpv4 добавляет функциональность высокого уровня для использования ascii
трассировка до помощника протокола. Каждый протокол, который включает эти методы, должен реализовывать
единственный виртуальный метод, унаследованный от этого класса .:
виртуальная пустота EnableAsciiIpv4Internal (Ptr поток, префикс std :: string,
Ptr ipv4, интерфейс uint4_t) = 32;
Сигнатура этого метода отражает взгляд на протокол и интерфейс, ориентированный на
ситуация на этом уровне; а также тот факт, что помощник может писать в общий
выходной поток. Все общедоступные методы, унаследованные от класса
PcapAndAsciiTraceHelperForIpv4 свести к вызову этого единственного устройства, зависящего от
метод реализации. Например, методы трассировки ascii самого низкого уровня:
void EnableAsciiIpv4 (префикс std :: string, Ptr ipv4, интерфейс uint4_t);
void EnableAsciiIpv4 (Ptr поток, Ptr ipv4, интерфейс uint4_t);
вызовет реализацию устройства EnableAsciiIpv4Internal напрямую, обеспечивая либо
префикс или поток. Все другие общедоступные методы трассировки ascii будут основываться на этих
низкоуровневые функции для обеспечения дополнительных функций пользовательского уровня. Что это значит для
Пользователь, чтобы у всех помощников устройств в системе были все методы трассировки ascii
доступный; и эти методы будут работать одинаково для разных протоколов, если
протоколы реализуют EnablAsciiIpv4 Внутренний правильно.
ASCII трассировка Устройство Помощник методы
void EnableAsciiIpv4 (префикс std :: string, Ptr ipv4, интерфейс uint4_t);
void EnableAsciiIpv4 (Ptr поток, Ptr ipv4, интерфейс uint4_t);
void EnableAsciiIpv4 (префикс std :: string, std :: string ipv4Name, интерфейс uint32_t);
void EnableAsciiIpv4 (Ptr поток, std :: string ipv4Name, интерфейс uint32_t);
void EnableAsciiIpv4 (префикс std :: string, Ipv4InterfaceContainer c);
void EnableAsciiIpv4 (Ptr поток, Ipv4InterfaceContainer c);
void EnableAsciiIpv4 (префикс std :: string, NodeContainer n);
void EnableAsciiIpv4 (Ptr поток, NodeContainer n);
void EnableAsciiIpv4 (std :: string prefix, uint32_t nodeid, uint32_t deviceid);
void EnableAsciiIpv4 (Ptr поток, uint32_t nodeid, интерфейс uint32_t);
void EnableAsciiIpv4All (префикс std :: string);
void EnableAsciiIpv4All (Ptr ручей);
Предлагаем вам ознакомиться с Doxygen для занятий PcapAndAsciiHelperForIpv4 найти
подробности этих методов; но подведем итог ...
Для трассировки ascii доступно в два раза больше методов, чем для pcap.
отслеживание. Это потому, что в дополнение к модели в стиле pcap, где следы от каждого
уникальная пара протокол / интерфейс записывается в уникальный файл, мы поддерживаем модель, в которой
информация трассировки для многих пар протокол / интерфейс записывается в общий файл. Этот
означает, что -n - заменен механизм генерации имени файла
механизмом обращения к общему файлу; а количество методов API увеличено вдвое до
разрешить все комбинации.
Как и в случае с трассировкой pcap, вы можете включить трассировку ascii для определенного протокола / интерфейса.
пара, предоставив Ptr и интерфейс к Включить Ascii метод. Например,:
Ptr ipv4;
...
helper.EnableAsciiIpv4 («префикс», ipv4, 1);
В этом случае контексты трассировки не записываются в файл трассировки ascii, поскольку они будут
избыточный. Система выберет имя файла для создания по тем же правилам, что и
описан в разделе pcap, за исключением того, что файл будет иметь суффикс ".tr" вместо
".pcap".
Если вы хотите включить трассировку ascii более чем на одном интерфейсе и отправить все трассировки на
один файл, вы также можете сделать это, используя объект для ссылки на один файл. Мы
уже есть нечто подобное в приведенном выше примере "cwnd":
Ptr протокол4 = узел1-> GetObject ();
Ptr протокол4 = узел2-> GetObject ();
...
Ptr stream = asciiTraceHelper.CreateFileStream ("имя-файла-трассировки.tr");
...
helper.EnableAsciiIpv4 (поток, протокол1, 1);
helper.EnableAsciiIpv4 (поток, протокол2, 1);
В этом случае контексты трассировки записываются в файл трассировки ascii, поскольку они необходимы
для устранения неоднозначности трассировки двух интерфейсов. Обратите внимание: поскольку пользователь полностью
при указании имени файла строка должна включать ".tr" для единообразия.
Вы можете включить трассировку ascii для определенного протокола, указав станд :: строка
представление служебной строки имени объекта для ВключитьPcap метод. Ptr is
поднял глаза от строки имени. В в результирующих именах файлов неявно, поскольку
существует взаимно однозначное соответствие между экземплярами протокола и узлами, например:
Имена :: Добавить ("node1Ipv4" ...);
Имена :: Добавить ("node2Ipv4" ...);
...
helper.EnableAsciiIpv4 («префикс», «node1Ipv4», 1);
helper.EnableAsciiIpv4 («префикс», «node2Ipv4», 1);
Это приведет к созданию двух файлов с именем «prefix-nnode1Ipv4-i1.tr» и
«prefix-nnode2Ipv4-i1.tr» с трассировками для каждого интерфейса в соответствующем файле трассировки.
Поскольку все функции EnableAscii перегружены, чтобы принимать оболочку потока, вы можете
также используйте эту форму:
Имена :: Добавить ("node1Ipv4" ...);
Имена :: Добавить ("node2Ipv4" ...);
...
Ptr stream = asciiTraceHelper.CreateFileStream ("имя-файла-трассировки.tr");
...
helper.EnableAsciiIpv4 (поток, «node1Ipv4», 1);
helper.EnableAsciiIpv4 (поток, «node2Ipv4», 1);
Это приведет к созданию единственного файла трассировки с именем "имя-файла-трассировки.tr", содержащего все
события трассировки для обоих интерфейсов. События будут устранены контекстом трассировки
строки.
Вы можете включить трассировку ascii для набора пар протокол / интерфейс, предоставив
Ipv4InterfaceContainer. Для каждого протокола соответствующего типа (того же типа, что и управляемый
помощником устройства) трассировка включена для соответствующего интерфейса. Опять же,
неявно, поскольку существует взаимно однозначное соответствие между каждым протоколом и
его узел. Например,:
Узлы NodeContainer;
...
Устройства NetDeviceContainer = deviceHelper.Install (узлы);
...
Ipv4AddressHelper ipv4;
ipv4.SetBase («10.1.1.0», «255.255.255.0»);
Интерфейсы Ipv4InterfaceContainer = ipv4.Assign (устройства);
...
...
helper.EnableAsciiIpv4 («префикс», интерфейсы);
Это приведет к созданию ряда файлов трассировки ascii, каждый из которых следует
в -n -я .tr соглашение. Объединение всех следов в
single file выполняется аналогично приведенным выше примерам:
Узлы NodeContainer;
...
Устройства NetDeviceContainer = deviceHelper.Install (узлы);
...
Ipv4AddressHelper ipv4;
ipv4.SetBase («10.1.1.0», «255.255.255.0»);
Интерфейсы Ipv4InterfaceContainer = ipv4.Assign (устройства);
...
Ptr stream = asciiTraceHelper.CreateFileStream ("имя-файла-трассировки.tr");
...
helper.EnableAsciiIpv4 (поток, интерфейсы);
Вы можете включить трассировку ascii для набора пар протокол / интерфейс, предоставив
Нодконтейнер, Для каждого Узел в Нодконтейнер найден соответствующий протокол. За
перечисляются каждый протокол, его интерфейсы, а на результирующем
пары. Например,:
Контейнер узлов n;
...
helper.EnableAsciiIpv4 («префикс», n);
Это приведет к созданию ряда файлов трассировки ascii, каждый из которых следует
в - - .tr соглашение. Объединение всех следов в
single file выполняется аналогично приведенным выше примерам:
Вы также можете включить трассировку pcap на основе идентификатора узла и идентификатора устройства. В таком случае,
идентификатор узла переводится в Ptr и соответствующий протокол ищется в
узел. Результирующий протокол и интерфейс используются для определения результирующей трассировки.
источник.:
helper.EnableAsciiIpv4 («префикс», 21, 1);
Конечно, следы можно объединить в один файл, как показано выше.
Наконец, вы можете включить трассировку ascii для всех интерфейсов в системе с соответствующими
протокол того же типа, что и управляемый помощником устройства .:
helper.EnableAsciiIpv4All («префикс»);
Это приведет к созданию нескольких файлов трассировки ascii, по одному для каждого интерфейса.
в системе, относящейся к протоколу типа, управляемого помощником. Все эти файлы
будет следовать -n -я
в один файл выполняется аналогично приведенным выше примерам.
ASCII трассировка Устройство Помощник Имя файла Выбор
В приведенных выше описаниях методов префиксного стиля подразумевается построение полного
имена файлов по способу реализации. По соглашению, ascii трассируется в нс-3 система
формы " - - .tr. "
Как упоминалось ранее, каждому узлу в системе будет назначен идентификатор узла.
Поскольку существует взаимно однозначное соответствие между протоколами и узлами, которые мы используем для идентификатора узла
для идентификации протокола. Каждый интерфейс по данному протоколу будет иметь
индекс интерфейса (также называемый просто интерфейсом) относительно его протокола. По умолчанию,
затем файл трассировки ascii, созданный в результате включения трассировки на первом устройстве из
узел 21, использующий префикс «prefix», будет «prefix-n21-i1.tr». Используйте префикс для
устранять неоднозначность нескольких протоколов на узел.
Вы всегда можете использовать нс-3 служба имен объектов, чтобы прояснить это. Например, если
вы используете службу имен объектов для присвоения имени "serverIpv4" протоколу на узле
21, а также укажите первый интерфейс, результирующее имя файла трассировки ascii будет автоматически
превратиться в "prefix-nserverIpv4-1.tr".
трассировка реализация детали
Данные Транспортировка
В этой главе описывается структура сбора данных NS-3 (DCF), которая обеспечивает
возможность получать данные, сгенерированные моделями в симуляторе, выполнять в режиме онлайн
сокращение и обработка данных, а также для маршалинга необработанных или преобразованных данных в различные выходные данные
форматов.
В настоящее время фреймворк поддерживает автономные запуски ns-3, которые не зависят от внешних
контроль выполнения программы. Объекты, предоставляемые DCF, могут быть подключены к нс-3 прослеживать
источники для обработки данных.
Исходный код классов находится в каталоге src / stats.
Эта глава организована следующим образом. Во-первых, обзор архитектуры
представлен. Далее представлены помощники для этих классов; это начальное лечение
должен позволить базовое использование структуры сбора данных для многих случаев использования. Пользователи, которые
желаете производить вывод, выходящий за рамки текущих помощников, или желающие создать
их собственные объекты сбора данных, следует прочитать оставшуюся часть главы, которая идет
подробно обо всех основных типах объектов DCF и обеспечивает низкоуровневое кодирование
примеры.
Дизайн
DCF состоит из трех основных классов:
· Образец это механизм для измерения и управления выводом данных моделирования, который
используется для наблюдения за интересными событиями. Он производит вывод в виде одного или нескольких нс-3
источники трассировки. Объекты зонда подключены к одной или нескольким трассам поглотителями (Так называемый
Коллекторы), которые обрабатывают образцы в режиме онлайн и готовят их к выходу.
· Коллектор потребляет данные, созданные одним или несколькими объектами Probe. Он выполняет
преобразования данных, такие как нормализация, сокращение и вычисление
базовая статистика. Объекты-коллекторы не производят данные, которые напрямую выводятся
нс-3 пробег; вместо этого они выводят данные в нисходящий поток к другому типу объекта, называемому
Агрегатор, который выполняет эту функцию. Обычно коллекторы выводят свои данные в
также форма источников следа, позволяющая последовательно соединять сборщики.
· Агрегатор является конечной точкой данных, собранных сетью зондов и сборщиков.
Основная обязанность агрегатора - упорядочить данные и соответствующие им данные.
метаданные в различные форматы вывода, такие как текстовые файлы, файлы электронных таблиц или
базы данных.
Все три класса предоставляют возможность динамически включать и выключать себя.
на протяжении всей симуляции.
Любой автономный нс-3 прогон моделирования, использующий DCF, обычно создает как минимум один
экземпляр каждого из трех вышеупомянутых классов.
[изображение] Обзор системы сбора данных.UNINDENT
Общий поток обработки данных изображен на Данные Транспортировка Рамки обзор.
Слева бегущая нс-3 изображена симуляция. В процессе работы
При моделировании данные предоставляются моделями через источники трассировки или другими способами.
На схеме показано, что зонды могут быть подключены к этим источникам трассировки для получения данных.
асинхронно, или зонды могут опрашивать данные. Затем данные передаются объекту-сборщику.
который преобразует данные. Наконец, можно подключить агрегатор к выходам
коллектор для создания графиков, файлов или баз данных.
[изображение] Агрегирование структуры сбора данных.UNINDENT
Вариант приведенного выше рисунка представлен в Данные Транспортировка Рамки агрегирование.
Этот второй рисунок иллюстрирует, что объекты DCF могут быть связаны вместе способом
что нижестоящие объекты принимают входные данные от нескольких вышестоящих объектов. Фигура
концептуально показывает, что несколько зондов могут генерировать выходные данные, которые передаются в один
коллекционер; например, коллектор, который выводит соотношение двух счетчиков, будет
обычно получают данные каждого счетчика от отдельных датчиков. Несколько коллекторов также могут
подавать в единый агрегатор, который (как следует из названия) может собирать ряд данных
потоки для включения в единый график, файл или базу данных.
Данные Транспортировка Помощники
Полная гибкость структуры сбора данных обеспечивается подключением
зондов, коллекторов и агрегаторов. Выполнение всех этих взаимосвязей приводит к
множество операторов конфигурации в пользовательских программах. Для простоты использования некоторые из наиболее распространенных
операции могут быть объединены и инкапсулированы во вспомогательные функции. Кроме того, некоторые
заявления с участием нс-3 Источники трассировки не имеют привязок Python из-за ограничений в
привязки.
Данные Транспортировка Помощники Обзор
В этом разделе мы даем обзор некоторых вспомогательных классов, которые были созданы для
упростить настройку структуры сбора данных для некоторых распространенных случаев использования. В
помощники позволяют пользователям формировать общие операции с помощью всего нескольких операторов в их C ++ или
Программы на Python. Но такая простота использования обходится значительно дешевле.
гибкость, которую может обеспечить низкоуровневая конфигурация, и необходимость явно кодировать
поддержка новых типов зондов в помощники (для решения проблемы, описанной ниже).
Акцент на текущих помощниках заключается в упорядочивании данных из нс-3 проследить источники в
графики или текстовые файлы gnuplot без высокой степени настройки вывода или статистических данных.
обработка (изначально). Кроме того, использование ограничено доступными типами датчиков в
нс-3. В следующих разделах этой документации будет более подробно рассказано о создании новых
Типы зондов, а также сведения о соединении зондов, коллекторов и агрегаторов
в индивидуальном порядке.
На сегодняшний день реализовано два помощника по сбору данных:
· ГнуплотХелпер
· Помощник по файлам
GnuplotHelper
GnuplotHelper - это вспомогательный класс для создания файлов вывода, используемых для создания gnuplots. В
общая цель - предоставить пользователям возможность быстро строить графики из экспортированных данных.
in нс-3 источники трассировки. По умолчанию выполняется минимальное преобразование данных;
цель состоит в том, чтобы сгенерировать графики с минимальным количеством (по умолчанию) конфигурационных операторов, как
возможное.
GnuplotHelper Обзор
GnuplotHelper создаст 3 разных файла в конце моделирования:
· Файл данных gnuplot, разделенный пробелами
· Контрольный файл gnuplot
· Сценарий оболочки для создания gnuplot
Для построения графиков необходимы два конфигурационных оператора. Первое
оператор настраивает сюжет (имя файла, заголовок, легенды и тип вывода, где вывод
по умолчанию используется PNG, если не указано иное):
void ConfigurePlot (const std :: string & outputFileNameWithoutExtension,
const std :: строка и заголовок,
const std :: string & xLegend,
const std :: string & yLegend,
const std :: string & terminalType = ".png");
Второй оператор перехватывает интересующий источник трассировки:
void PlotProbe (const std :: string & typeId,
const std :: строка и путь,
const std :: string & probeTraceSource,
const std :: string & title);
Аргументы следующие:
· TypeId: нс-3 TypeId зонда
· Path: Путь в нс-3 пространство имен конфигурации для одного или нескольких источников трассировки
· ProbeTraceSource: какой вывод датчика (сам источник трассировки) должен быть нанесен на график.
· Title: заголовок, который нужно связать с набором данных (в легенде gnuplot)
Вариант PlotProbe выше - указать пятый необязательный аргумент, который управляет
где на сюжете ставится ключ (легенда).
Полностью рабочий пример (из седьмой.cc) показан ниже:
// Создаем помощник gnuplot.
GnuplotHelper;
// Настраиваем сюжет.
// Настраиваем сюжет. Первый аргумент - это префикс имени файла.
// для сгенерированных выходных файлов. Второй, третий и четвертый
// аргументами являются, соответственно, заголовок графика, метки оси x и оси y
plotHelper.ConfigurePlot ("счетчик байтов седьмого пакета",
«Зависимость количества байтов пакета от времени»,
"Время (секунды)",
"Счетчик байтов пакета",
"png");
// Укажите тип зонда, путь к источнику трассировки (в пространстве имен конфигурации) и
// зондирование источника трассировки вывода ("OutputBytes") для построения графика. Четвертый аргумент
// указывает имя метки ряда данных на графике. Последний
// аргумент форматирует график, указывая, где должен быть размещен ключ.
plotHelper.PlotProbe (тип зонда,
трассировка,
"OutputBytes",
"Счетчик байтов пакета",
GnuplotAggregator :: KEY_BELOW);
В этом примере тип зонда и трассировка следующие (для IPv4):
probeType = "ns3 :: Ipv4PacketProbe";
tracePath = "/ NodeList / * / $ ns3 :: Ipv4L3Protocol / Tx";
ProbeType является ключевым параметром для работы этого помощника. Этот TypeId должен быть зарегистрирован
в системе, и подпись на приемнике трассировки зонда должна соответствовать сигнатуре трассы.
источник, к которому он подключен. Типы зондов предварительно определены для ряда типов данных.
соответствующий нс-3 отслеживаемые значения, а также для некоторых других сигнатур источников трассировки, таких как
источник трассировки 'Tx' ns3 :: Ipv4L3Protocol класса.
Обратите внимание, что указанный путь к источнику трассировки может содержать подстановочные знаки. В этом случае несколько
наборы данных наносятся на один график; по одному для каждого совпадающего пути.
Основным результатом будет три файла:
седьмой-пакет-байтов-count.dat
седьмой-пакет-байт-count.plt
седьмой-packet-byte-count.sh
На этом этапе пользователи могут либо вручную отредактировать файл .plt для дальнейшей настройки, либо
просто запустите его через gnuplot. Бег sh седьмой-packet-byte-count.sh просто запускает сюжет
через gnuplot, как показано ниже.
[изображение] 2-D Gnuplot Создано с помощью sevenh.cc Example..UNINDENT
Видно, что ключевые элементы (легенда, заголовок, размещение легенды, xlabel, ylabel,
и путь к данным) помещаются на график. Поскольку было два матча до
указан путь конфигурации, показаны две серии данных:
· Счетчик байтов пакета-0 соответствует / NodeList / 0 / $ ns3 :: Ipv4L3Protocol / Tx
· Счетчик байтов пакета-1 соответствует / NodeList / 1 / $ ns3 :: Ipv4L3Protocol / Tx
GnuplotHelper Настроить график
GnuplotHelper's ConfigurePlot () Функцию можно использовать для настройки графиков.
Имеет следующий прототип:
void ConfigurePlot (const std :: string & outputFileNameWithoutExtension,
const std :: строка и заголовок,
const std :: string & xLegend,
const std :: string & yLegend,
const std :: string & terminalType = ".png");
У него следующие аргументы:
┌────────────────────────────────┬────────────────── ──────────────────┐
│Аргумент │ Описание │
├────────────────────────────────┼────────────────── ──────────────────┤
│outputFileNameWithoutExtension │ Имя файлов, связанных с gnuplot, для │
│ │ писать без расширения. │
├────────────────────────────────┼────────────────── ──────────────────┤
│title │ Строка заголовка графика для использования │
│ │ этот сюжет. │
├────────────────────────────────┼────────────────── ──────────────────┤
│xLegend │ Легенда для оси x
│ │ ось. │
├────────────────────────────────┼────────────────── ──────────────────┤
│yLegend │ Легенда для вертикали y │
│ │ ось. │
└────────────────────────────────┴────────────────── ──────────────────┘
│terminalType │ Строка установки типа клеммы для │
│ │ выход. Терминал по умолчанию │
│ │ тип - «png». │
└────────────────────────────────┴────────────────── ──────────────────┘
GnuplotHelper's ConfigurePlot () функция настраивает параметры, связанные с графиком для этого
помощник gnuplot, чтобы он создавал файл данных gnuplot, разделенный пробелами, с именем
outputFileNameWithoutExtension + ".dat", файл управления gnuplot с именем
outputFileNameWithoutExtension + ".plt" и сценарий оболочки для создания gnuplot с именем
outputFileNameWithoutExtension + ".sh".
Пример использования этой функции можно увидеть в седьмой.cc код, описанный выше
где он использовался следующим образом:
plotHelper.ConfigurePlot ("счетчик байтов седьмого пакета",
«Зависимость количества байтов пакета от времени»,
"Время (секунды)",
"Счетчик байтов пакета",
"png");
GnuplotHelper PlotProbe
GnuplotHelper's PlotProbe () Функция может использоваться для построения значений, генерируемых датчиками.
Имеет следующий прототип:
void PlotProbe (const std :: string & typeId,
const std :: строка и путь,
const std :: string & probeTraceSource,
const std :: строка и заголовок,
перечисление GnuplotAggregator :: KeyLocation keyLocation = GnuplotAggregator :: KEY_INSIDE);
У него следующие аргументы:
┌─────────────────┬───────────────────────────────── ───┐
│Аргумент │ Описание │
├─────────────────┼───────────────────────────────── ───┤
│typeId │ ID типа для датчика │
│ │, созданный этим помощником. │
├─────────────────┼───────────────────────────────── ───┤
│path │ Конфигурационный путь для доступа к трассировке │
│ │ источник. │
├─────────────────┼───────────────────────────────── ───┤
│probeTraceSource │ Источник трассировки зонда для │
│ │ доступ. │
├─────────────────┼───────────────────────────────── ───┤
│title │ Название, которое будет связано с │
│ │ этот набор данных │
├─────────────────┼───────────────────────────────── ───┤
│keyLocation │ Расположение ключа в │
│ │ сюжет. Местоположение по умолчанию - │
│ │ внутри. │
└─────────────────┴───────────────────────────────── ───┘
GnuplotHelper's PlotProbe () функция отображает набор данных, созданный путем подключения нс-3
источник трассировки с зондом, созданным помощником, а затем построение значений из
probeTraceSource. Набор данных будет иметь указанный заголовок и будет состоять из
'newValue' на каждой отметке времени.
Если путь конфигурации имеет более одного совпадения в системе из-за наличия подстановочного знака, тогда
будет нанесен один набор данных для каждого совпадения. Заголовки наборов данных будут иметь суффикс
совпадающие символы для каждого из подстановочных знаков в пути конфигурации, разделенные пробелами. За
Например, если предлагаемый заголовок набора данных представляет собой строку «байты», и есть два символа подстановки
в пути, тогда заголовки наборов данных, такие как «байты-0 0» или «байты-12 9», будут возможны как
подписи для построенных наборов данных.
Пример использования этой функции можно увидеть в седьмой.cc код, описанный выше
где он использовался (с подстановкой переменных) следующим образом:
plotHelper.PlotProbe ("ns3 :: Ipv4PacketProbe",
"/ NodeList / * / $ ns3 :: Ipv4L3Protocol / Tx",
"OutputBytes",
"Счетчик байтов пакета",
GnuplotAggregator :: KEY_BELOW);
Другой Примеры
Гнуплот Помощник Пример
Чуть более простой пример, чем седьмой.cc пример можно найти в
SRC / статистика / примеры / gnuplot-helper-example.cc. Следующий 2-D gnuplot был создан с использованием
пример.
[изображение] 2-D Gnuplot Создано gnuplot-helper-example.cc Пример..UNINDENT
В этом примере есть объект Emitter, который увеличивает свой счетчик в соответствии с
Процесс Пуассона, а затем выдает значение счетчика в качестве источника трассировки.
Ptr emitter = CreateObject ();
Names :: Add ("/ Names / Emitter", эмиттер);
Обратите внимание, что из-за отсутствия подстановочных знаков в пути, используемом ниже, был использован только 1 поток данных.
нарисовано в сюжете. Этот единственный поток данных на графике просто помечен как «Emitter Count»,
без дополнительных суффиксов, как если бы в пути были подстановочные знаки.
// Создаем помощник gnuplot.
GnuplotHelper;
// Настраиваем сюжет.
plotHelper.ConfigurePlot ("пример-помощника-gnuplot",
"Счетчик эмиттеров в зависимости от времени",
"Время (секунды)",
"Счетчик эмиттеров",
"png");
// Построить график значений, сгенерированных зондом. Путь, который мы предоставляем
// помогает устранить неоднозначность источника следа.
plotHelper.PlotProbe ("ns3 :: Uinteger32Probe",
"/ Имена / Эмитент / Счетчик",
"Вывод",
"Счетчик эмиттеров",
GnuplotAggregator :: KEY_INSIDE);
FileHelper
FileHelper - это вспомогательный класс, используемый для помещения значений данных в файл. Общая цель
чтобы предоставить пользователям возможность быстро создавать форматированные текстовые файлы из экспортированных данных
in нс-3 источники трассировки. По умолчанию выполняется минимальное преобразование данных;
цель состоит в том, чтобы сгенерировать файлы с минимальным количеством (по умолчанию) конфигурационных инструкций, как
возможное.
FileHelper Обзор
FileHelper создаст 1 или несколько текстовых файлов в конце моделирования.
FileHelper может создавать 4 различных типа текстовых файлов:
· Отформатированный
· Разделенные пробелами (по умолчанию)
· Разделенные запятой
· Разделение табуляцией
Отформатированные файлы используют строки формата C-стиля и функцию sprintf () для печати их
значения в записываемом файле.
Следующий текстовый файл с 2 столбцами форматированных значений с именем
седьмой-пакет-байт-счет-0.txt был создан с использованием нового кода, который был добавлен в
оригинал нс-3 Код учебного примера. Отображаются только первые 10 строк этого файла.
здесь для краткости.
Время (секунды) = 1.000e + 00 Количество байтов пакетов = 40
Время (секунды) = 1.004e + 00 Количество байтов пакетов = 40
Время (секунды) = 1.004e + 00 Количество байтов пакетов = 576
Время (секунды) = 1.009e + 00 Количество байтов пакетов = 576
Время (секунды) = 1.009e + 00 Количество байтов пакетов = 576
Время (секунды) = 1.015e + 00 Количество байтов пакетов = 512
Время (секунды) = 1.017e + 00 Количество байтов пакетов = 576
Время (секунды) = 1.017e + 00 Количество байтов пакетов = 544
Время (секунды) = 1.025e + 00 Количество байтов пакетов = 576
Время (секунды) = 1.025e + 00 Количество байтов пакетов = 544
...
Следующий другой текстовый файл с 2 столбцами форматированных значений с именем
седьмой-пакет-байт-счет-1.txt также был создан с использованием того же нового кода, который был добавлен в
Оригинальный нс-3 Код учебного примера. Отображаются только первые 10 строк этого файла.
здесь для краткости.
Время (секунды) = 1.002e + 00 Количество байтов пакетов = 40
Время (секунды) = 1.007e + 00 Количество байтов пакетов = 40
Время (секунды) = 1.013e + 00 Количество байтов пакетов = 40
Время (секунды) = 1.020e + 00 Количество байтов пакетов = 40
Время (секунды) = 1.028e + 00 Количество байтов пакетов = 40
Время (секунды) = 1.036e + 00 Количество байтов пакетов = 40
Время (секунды) = 1.045e + 00 Количество байтов пакетов = 40
Время (секунды) = 1.053e + 00 Количество байтов пакетов = 40
Время (секунды) = 1.061e + 00 Количество байтов пакетов = 40
Время (секунды) = 1.069e + 00 Количество байтов пакетов = 40
...
Ниже приведен новый код, который был добавлен для создания двух текстовых файлов. Подробнее о
этот API будет рассмотрен в следующем разделе.
Обратите внимание, что, поскольку для подстановочного знака в пути было 2 совпадения, 2 отдельных текстовых файла
были созданы. Первый текстовый файл с именем «седьмой-пакет-байт-счет-0.txt»,
соответствует совпадению с подстановочными знаками, в котором "*" заменено на "0". Второй текстовый файл,
который называется "седьмой-пакет-байтов-счет-1.txt", соответствует совпадению с подстановочным знаком с
"*" заменен на "1". Также обратите внимание, что вызов функции WriteProbe () даст
сообщение об ошибке, если для пути, содержащего символы подстановки, нет совпадений.
// Создаем файловый помощник.
Помощник по файлуПомощник по файлу;
// Настраиваем файл для записи.
fileHelper.ConfigureFile ("счетчик байтов седьмого пакета",
FileAggregator :: FORMATTED);
// Устанавливаем метки для этого отформатированного выходного файла.
fileHelper.Set2dFormat ("Время (секунды) =% .3e \ tPacket Byte Count =% .0f");
// Записываем значения, сгенерированные зондом.
fileHelper.WriteProbe ("ns3 :: Ipv4PacketProbe",
"/ NodeList / * / $ ns3 :: Ipv4L3Protocol / Tx",
"OutputBytes");
FileHelper Настроить файл
FileHelper's ConfigureFile () Функция может использоваться для настройки текстовых файлов.
Имеет следующий прототип:
void ConfigureFile (const std :: string & outputFileNameWithoutExtension,
перечислить FileAggregator :: FileType fileType = FileAggregator :: SPACE_SEPARATED);
У него следующие аргументы:
┌────────────────────────────────┬────────────────── ──────────────────┐
│Аргумент │ Описание │
├────────────────────────────────┼────────────────── ──────────────────┤
│outputFileNameWithoutExtension │ Имя выходного файла для записи │
│ │ без расширения. │
├────────────────────────────────┼────────────────── ──────────────────┤
│fileType │ Тип файла для записи. │
│ │ тип файла по умолчанию - пробел │
│ │ разделены. │
└────────────────────────────────┴────────────────── ──────────────────┘
FileHelper's ConfigureFile () функция настраивает параметры, связанные с текстовым файлом, для
файловый помощник, чтобы он создавал файл с именем outputFileNameWithoutExtension plus
возможная дополнительная информация из совпадений с подстановочными знаками плюс ".txt" со значениями, напечатанными как
указанный в fileType. Тип файла по умолчанию разделен пробелами.
Пример использования этой функции можно увидеть в седьмой.cc код, описанный выше
где он использовался следующим образом:
fileHelper.ConfigureFile ("счетчик байтов седьмого пакета",
FileAggregator :: FORMATTED);
FileHelper WriteProbe
FileHelper's WriteProbe () функция может использоваться для записи значений, сгенерированных датчиками, в
текстовые файлы.
Имеет следующий прототип:
void WriteProbe (const std :: string & typeId,
const std :: строка и путь,
const std :: string & probeTraceSource);
У него следующие аргументы:
┌─────────────────┬───────────────────────────────── ───┐
│Аргумент │ Описание │
├─────────────────┼───────────────────────────────── ───┤
│typeId │ Идентификатор типа для зонда │
│ │ создан. │
├─────────────────┼───────────────────────────────── ───┤
│path │ Конфигурационный путь для доступа к трассировке │
│ │ источник. │
├─────────────────┼───────────────────────────────── ───┤
│probeTraceSource │ Источник трассировки зонда для │
│ │ доступ. │
└─────────────────┴───────────────────────────────── ───┘
FileHelper's WriteProbe () функция создает выходные текстовые файлы, сгенерированные путем подключения
источник трассировки ns-3 с зондом, созданным помощником, а затем записывает значения из
probeTraceSource. Имена выходных файлов будут содержать текст, хранящийся в переменной-члене
m_outputFileNameWithoutExtension плюс ".txt", и будет состоять из 'newValue' на каждом
отметка времени.
Если путь конфигурации имеет более одного совпадения в системе из-за наличия подстановочного знака, тогда
будет создан один выходной файл для каждого совпадения. Имена выходных файлов будут содержать
текст в m_outputFileNameWithoutExtension плюс совпадающие символы для каждого из
символы подстановки в пути конфигурации, разделенные тире, плюс ".txt". Например, если значение
в m_outputFileNameWithoutExtension есть строка «количество байтов пакета», и есть два
подстановочные знаки в пути, затем имена выходных файлов, такие как "количество-байтов-пакетов-0-0.txt" или
"packet-byte-count-12-9.txt" можно будет использовать в качестве имен для создаваемых файлов.
Пример использования этой функции можно увидеть в седьмой.cc код, описанный выше
где он использовался следующим образом:
fileHelper.WriteProbe ("ns3 :: Ipv4PacketProbe",
"/ NodeList / * / $ ns3 :: Ipv4L3Protocol / Tx",
"OutputBytes");
Другой Примеры
Файл Помощник Пример
Чуть более простой пример, чем седьмой.cc пример можно найти в
SRC / статистика / примеры / file-helper-example.cc. В этом примере используется только FileHelper.
Следующий текстовый файл с 2 столбцами форматированных значений с именем файл-помощник-пример.txt
был создан на примере. Здесь показаны только первые 10 строк этого файла для
краткость.
Время (секунды) = 0.203 Счетчик = 1
Время (секунды) = 0.702 Счетчик = 2
Время (секунды) = 1.404 Счетчик = 3
Время (секунды) = 2.368 Счетчик = 4
Время (секунды) = 3.364 Счетчик = 5
Время (секунды) = 3.579 Счетчик = 6
Время (секунды) = 5.873 Счетчик = 7
Время (секунды) = 6.410 Счетчик = 8
Время (секунды) = 6.472 Счетчик = 9
...
В этом примере есть объект Emitter, который увеличивает свой счетчик в соответствии с
Процесс Пуассона, а затем выдает значение счетчика в качестве источника трассировки.
Ptr emitter = CreateObject ();
Names :: Add ("/ Names / Emitter", эмиттер);
Обратите внимание, что из-за отсутствия подстановочных знаков в пути, используемом ниже, был использован только 1 текстовый файл.
созданный. Этот единственный текстовый файл называется просто "file-helper-example.txt", без дополнительных
суффиксы, как если бы в пути были подстановочные знаки.
// Создаем файловый помощник.
Помощник по файлуПомощник по файлу;
// Настраиваем файл для записи.
fileHelper.ConfigureFile ("пример-помощника-файла",
FileAggregator :: FORMATTED);
// Устанавливаем метки для этого отформатированного выходного файла.
fileHelper.Set2dFormat ("Время (секунды) =% .3e \ tCount =% .0f");
// Записываем значения, сгенерированные зондом. Путь, который мы
// provide помогает устранить неоднозначность источника трассировки.
fileHelper.WriteProbe ("ns3 :: Uinteger32Probe",
"/ Имена / Эмитент / Счетчик",
"Вывод");
Объем и ограничения
В настоящее время реализованы только эти зонды, подключенные к GnuplotHelper и
в FileHelper:
· Логический зонд
· Двойной зонд
· Uinteger8Probe
· Uinteger16Probe
· Uinteger32Probe
· ТаймПроб
· ПакетПроб
· ПриложениеПакетПробе
· IPv4PacketProbe
Следовательно, эти зонды - единственные доступные TypeIds, которые можно использовать в PlotProbe () и
WriteProbe ().
В следующих нескольких разделах мы рассмотрим каждый из основных типов объектов (Probe, Collector,
и агрегатор) более подробно и покажите, как их можно связать вместе с помощью
API нижнего уровня.
Зонды
В этом разделе подробно описаны функции, предоставляемые классом Probe для нс-3
моделирование и дает примеры того, как их кодировать в программе. Этот раздел предназначен для
пользователи, заинтересованные в разработке моделирования с нс-3 инструменты и использование данных
Платформа Collection Framework, частью которой является класс Probe, для генерации вывода данных с помощью
результаты их моделирования.
Образец Обзор
Предполагается, что объект Probe связан с переменной из моделирования, значения которой
на протяжении всего эксперимента актуальны для пользователя. Зонд запишет, что было
значения, принимаемые переменной во время моделирования, и передать эти данные другому
член структуры сбора данных. Хотя это выходит за рамки этого раздела,
обсудить, что происходит после того, как зонд выдает выходной сигнал, достаточно сказать, что
в конце моделирования пользователь получит подробную информацию о том, какие значения были
хранится внутри переменной, исследуемой во время моделирования.
Обычно зонд подключается к нс-3 источник трассировки. Таким образом, всякий раз, когда
источник трассировки экспортирует новое значение, зонд потребляет это значение (и экспортирует его ниже по потоку).
к другому объекту через его собственный источник трассировки).
Зонд можно рассматривать как своего рода фильтр по источникам трассировки. Основные причины
возможно подключение к зонду, а не напрямую к источнику трассировки:
· Зонды могут динамически включаться и выключаться во время моделирования с вызовами Давать возможность()
и Запрещать(). Например, вывод данных может быть отключен во время
фаза прогрева симуляции.
· Зонды могут выполнять операции с данными для извлечения значений из более сложных
конструкции; например, вывод значения размера пакета из полученного ns3 :: Packet.
· Зонды регистрируют имя в пространстве имен ns3 :: Config (используя Имена :: Добавить ()) так что другие
объекты могут ссылаться на них.
· Зонды предоставляют статический метод, который позволяет манипулировать Зондом по имени, например
что сделано в ns2measure [Cic06]
Stat :: put ("my_metric", ID, образец);
Эквивалент ns-3 приведенного выше кода ns2measure, например
DoubleProbe :: SetValueByPath ("/ путь / к / зонд", образец);
Создание
Обратите внимание, что объект базового класса Probe не может быть создан, потому что он является абстрактной базой.
class, т.е. в нем есть чисто виртуальные функции, которые не были реализованы. Объект
Тип DoubleProbe, который является подклассом класса Probe, будет создан здесь, чтобы показать
Что должно быть сделано.
Один объявляет DoubleProbe в динамической памяти с помощью класса интеллектуального указателя (Ptr ). К
создать DoubleProbe в динамической памяти с помощью интеллектуальных указателей, просто нужно вызвать
нс-3 метод CreateObject ():
Ptr myprobe = CreateObject ();
Приведенное выше объявление создает DoubleProbes с использованием значений по умолчанию для его атрибутов.
В классе DoubleProbe есть четыре атрибута; два в объекте базового класса
DataCollectionObject и два в базовом классе Probe:
· «Имя» (DataCollectionObject), StringValue
· «Включено» (DataCollectionObject), логическое значение
· «Старт» (зонд), значение времени
· «Стоп» (зонд), значение времени
Такие атрибуты можно установить при создании объекта следующим способом:
Ptr myprobe = CreateObjectWithAttributes (
«Имя», StringValue («myprobe»),
«Включено», BooleanValue (false),
«Старт», TimeValue (Секунды (100.0)),
«Стоп», TimeValue (Секунды (1000.0)));
Start и Stop - это временные переменные, которые определяют интервал действия зонда. В
Зонд будет выводить данные только в том случае, если текущее время моделирования находится внутри этого
интервал. Специальное значение времени 0 секунд для Stop отключит этот атрибут (т. Е.
держите зонд включенным на протяжении всей симуляции). Включено - это флаг, который включает зонд или
выключен, и для зондирования необходимо установить значение true для экспорта данных. Имя - это имя объекта.
в рамках DCF.
Импортирующий и экспорт данным
нс-3 Источники трассировки строго типизированы, поэтому механизмы привязки зондов к трассировке
source и для экспорта данных принадлежат его подклассам. Например, по умолчанию
распределение нс-3 предоставляет класс DoubleProbe, который предназначен для привязки к трассировке
источник, экспортирующий двойное значение. Далее мы подробно рассмотрим работу DoubleProbe и
затем обсудите, как другие классы Probe могут быть определены пользователем.
Двойной зонд Обзор
DoubleProbe подключается к двойному нс-3 источник трассировки, и сам экспортирует
разные двузначные нс-3 источник трассировки.
Следующий код, взятый из SRC / статистика / примеры / double-probe-example.cc, показывает основные
операции по подключению DoubleProbe к моделированию, где он исследует счетчик
экспортируется объектом-эмиттером (класс Emitter).
Ptr emitter = CreateObject ();
Names :: Add ("/ Names / Emitter", эмиттер);
...
Ptr probe1 = CreateObject ();
// Подключаем зонд к счетчику эмиттера
bool connected = probe1-> ConnectByObject («Счетчик», эмиттер);
Следующий код проверяет тот же счетчик, экспортированный тем же объектом-эмиттером. Этот
Однако DoubleProbe использует путь в пространстве имен конфигурации, чтобы
связь. Обратите внимание, что эмиттер зарегистрировался в пространстве имен конфигурации после
это было создано; в противном случае ConnectByPath не будет работать.
Ptr probe2 = CreateObject ();
// Обратите внимание, здесь не проверяется возвращаемое значение
probe2-> ConnectByPath ("/ Имена / Эмиттер / Счетчик");
Следующий показанный ниже DoubleProbe будет иметь значение, установленное с использованием его пути в
пространство имен конфигурации. Обратите внимание, что на этот раз DoubleProbe зарегистрировался в
пространство имен конфигурации после его создания.
Ptr probe3 = CreateObject ();
probe3-> SetName ("StaticallyAccessedProbe");
// Мы должны добавить его в базу конфигурации
Names :: Add ("/ Names / Probes", проба3-> GetName (), проба3);
Функция эмиттера Count () теперь может устанавливать значение для этого DoubleProbe как
следующим образом:
аннулировать
Emitter :: Count (недействительно)
{
...
m_counter + = 1.0;
DoubleProbe :: SetValueByPath ("/ Имена / StaticallyAccessedProbe", m_counter);
...
}
В приведенном выше примере показано, как код, вызывающий зонд, не должен иметь явного
ссылка на Probe, но может направлять настройку значения через пространство имен Config.
По функциям он похож на Stat :: Put Метод, представленный ns2measure paper
[Cic06] и позволяет пользователям временно вставлять операторы Probe, например Printf отчетность
в рамках существующих нс-3 модели. Обратите внимание, что для использования DoubleProbe в этом
В этом примере потребовалось 2 вещи:
1. файл заголовка модуля статистики был включен в пример файла .cc
2. пример был сделан зависимым от модуля статистики в файле wscript.
Аналогичные действия необходимо сделать, чтобы добавить другие зонды в другие места в папке. нс-3
кодовая база.
Значения для DoubleProbe также можно установить с помощью функции DoubleProbe :: SetValue (),
в то время как значения для DoubleProbe можно получить с помощью функции
DoubleProbe :: GetValue ().
DoubleProbe экспортирует двойные значения в свой источник трассировки «Выход»; нижестоящий объект
может подключить приемник трассировки (NotifyViaProbe) к этому следующим образом:
connected = probe1-> TraceConnect ("Выход", probe1-> GetName (), MakeCallback (& NotifyViaProbe));
Другой Зонды
Помимо DoubleProbe, также доступны следующие датчики:
· Uinteger8Probe подключается к нс-3 источник трассировки, экспортирующий файл uint8_t.
· Uinteger16Probe подключается к нс-3 источник трассировки, экспортирующий файл uint16_t.
· Uinteger32Probe подключается к нс-3 источник трассировки, экспортирующий файл uint32_t.
· PacketProbe подключается к нс-3 источник трассировки, экспортирующий пакет.
· ApplicationPacketProbe подключается к нс-3 источник трассировки, экспортирующий пакет и сокет
адрес.
· Ipv4PacketProbe подключается к нс-3 источник трассировки, экспортирующий пакет, объект IPv4 и
интерфейс.
Создающий new Образец Типы
Чтобы создать новый тип зонда, вам необходимо выполнить следующие шаги:
· Убедитесь, что ваш новый класс Probe является производным от базового класса Probe.
· Убедитесь, что чистые виртуальные функции, которые ваш новый класс Probe наследует от
Реализован базовый класс зонда.
· Найдите существующий класс Probe, который использует источник трассировки, наиболее близкий по типу к
тип источника трассировки, который будет использовать ваш зонд.
· Скопируйте файл заголовка существующего класса Probe (.h) и файл реализации (.cc) в два
новые файлы с именами, соответствующими вашему новому зонду.
· Замените типы, аргументы и переменные в скопированных файлах соответствующими
тип для вашего зонда.
· Внесите необходимые изменения, чтобы код компилировался и вел себя так, как вы
нравится.
Примеры
Здесь мы подробно рассмотрим два примера:
· Пример двойного зонда
· Пример построения пакета IPv4
двойной Образец Пример
Пример двойного зонда обсуждался ранее. Пример программы можно найти
in SRC / статистика / примеры / double-probe-example.cc. Подводя итог тому, что происходит в этой программе,
есть эмиттер, который экспортирует счетчик, который увеличивается в соответствии с процессом Пуассона.
В частности, показаны два способа выдачи данных:
1. через отслеживаемую переменную, подключенную к одному зонду:
TracedValue m_counter; // обычно это будет целочисленный тип
2. через счетчик, значение которого отправляется второму Зонду, на который ссылается его имя в
Конфигурационная система:
аннулировать
Emitter :: Count (недействительно)
{
NS_LOG_FUNCTION (это);
NS_LOG_DEBUG ("Подсчет в" << Simulator :: Now () .GetSeconds ());
m_counter + = 1.0;
DoubleProbe :: SetValueByPath ("/ Имена / StaticallyAccessedProbe", m_counter);
Simulator :: Schedule (Seconds (m_var-> GetValue ()), & Emitter :: Count, this);
}
Посмотрим на Зонд повнимательнее. Зонды могут получать свои значения многократно.
способы:
1. Зонд напрямую обращается к источнику трассировки и подключает к нему приемник трассировки.
2. Зонд получает доступ к источнику трассировки через пространство имен config и подключает
проследить за ним
3. вызывающим кодом, явно вызывающим зонд SetValue () метод
4. вызывающим кодом, явно вызывающим SetValueByPath
("/ путь / через / Config / пространство имен", ...)
Ожидается, что первые два метода будут наиболее распространенными. Также в примере
показано подключение нормальной функции обратного вызова, как это обычно делается в нс-3. Это
функция обратного вызова не связана с объектом Probe. Мы назовем этот случай ниже 0).
// Это функция для проверки подключения необработанной функции к источнику трассировки
аннулировать
NotifyViaTraceSource (std :: string context, double oldVal, double newVal)
{
NS_LOG_DEBUG ("context:" << context << "old" << oldVal << "new" << newVal);
}
Во-первых, необходимо настроить эмиттер:
Ptr emitter = CreateObject ();
Names :: Add ("/ Names / Emitter", эмиттер);
// Объект Emitter не связан с узлом ns-3, поэтому
// он не запустится автоматически, поэтому нам нужно сделать это самим
Simulator :: Schedule (секунды (0.0), & Emitter :: Start, emitter);
Различные DoubleProbes взаимодействуют с эмиттером в примере, как показано ниже.
Случай 0):
// Ниже показаны типичные функции без зонда
// (подключаем функцию-приемник к источнику трассировки)
//
connected = emitter-> TraceConnect («Счетчик», «пример контекста», MakeCallback (& NotifyViaTraceSource));
NS_ASSERT_MSG (подключено, «Источник трассировки не подключен»);
Дело 1):
//
// Probe1 будет подключен непосредственно к объекту источника трассировки Emitter
//
// probe1 будет подключен к источнику трассировки Emitter
Ptr probe1 = CreateObject ();
// имя зонда может служить его контекстом при трассировке
probe1-> SetName ("ObjectProbe");
// Подключаем зонд к счетчику эмиттера
connected = probe1-> ConnectByObject («Счетчик», эмиттер);
NS_ASSERT_MSG (подключено, «Источник трассировки не подключен к датчику 1»);
Дело 2):
//
// Probe2 будет подключен к объекту источника трассировки Emitter с помощью
// доступ к нему по имени пути в базе данных Config
//
// Создаем еще один похожий зонд; это будет подключаться через путь конфигурации
Ptr probe2 = CreateObject ();
probe2-> SetName ("PathProbe");
// Обратите внимание, здесь не проверяется возвращаемое значение
probe2-> ConnectByPath ("/ Имена / Эмиттер / Счетчик");
case 4) (случай 3 в этом примере не показан):
//
// Probe3 будет вызываться эмиттером напрямую через
// статический метод SetValueByPath ().
//
Ptr probe3 = CreateObject ();
probe3-> SetName ("StaticallyAccessedProbe");
// Мы должны добавить его в базу конфигурации
Names :: Add ("/ Names / Probes", проба3-> GetName (), проба3);
И, наконец, пример показывает, как можно подключить зонды для генерации вывода:
// Сам зонд должен генерировать выходные данные. Контекст, который мы предоставляем
// к этому зонду (в данном случае имя зонда) поможет устранить неоднозначность
// источник следа
connected = probe3-> TraceConnect ("Выход",
"/ Имена / Зонды / StaticallyAccessedProbe / Выход",
MakeCallback (& NotifyViaProbe));
NS_ASSERT_MSG (подключен, «Источник трассировки не .. подключен к выходу датчика 3»);
Следующий обратный вызов подключен к Probe в этом примере в иллюстративных целях;
обычно зонд будет привязан к объекту Collector.
// Это функция для тестирования подключения к выходу зонда
аннулировать
NotifyViaProbe (std :: string context, double oldVal, double newVal)
{
NS_LOG_DEBUG ("context:" << context << "old" << oldVal << "new" << newVal);
}
IPv4 пакет Участок Пример
Пример построения пакета IPv4 основан на примере Friday.cc из нс-3 Руководство. Это
можно найти в SRC / статистика / примеры / ipv4-packet-plot-example.cc.
узел 0 узел 1
+ ---------------- + + ---------------- +
| нс-3 TCP | | нс-3 TCP |
+ ---------------- + + ---------------- +
| 10.1.1.1 | | 10.1.1.2 |
+ ---------------- + + ---------------- +
| точка-точка | | точка-точка |
+ ---------------- + + ---------------- +
| |
+ --------------------- +
Мы просто посмотрим на Probe, поскольку он показывает, что Probes также может распаковывать значения из
структуры (в данном случае пакеты) и сообщают эти значения как выходные данные источника трассировки, а
чем просто передача одного и того же типа данных.
Есть и другие аспекты этого примера, которые будут объяснены позже в документации.
Два типа экспортируемых данных - это сам пакет (Результат) и подсчет
количество байтов в пакете (Выходные байты).
Идентификатор типа
Ipv4PacketProbe :: GetTypeId ()
{
статический TypeId tid = TypeId ("ns3 :: Ipv4PacketProbe")
.SetParent ()
.AddConstructor ()
.AddTraceSource ("Вывод",
«Пакет плюс его объект IPv4 и интерфейс, которые служат выходными данными для этого зонда»,
MakeTraceSourceAccessor (& Ipv4PacketProbe :: m_output))
.AddTraceSource ("Выходные байты",
"Количество байтов в пакете",
MakeTraceSourceAccessor (& Ipv4PacketProbe :: m_outputBytes))
;
вернуть tid;
}
Когда приемник трассировки зонда получает пакет, если зонд включен, он выводит
пакет на его Результат источник трассировки, но он также будет выводить количество байтов в
Выходные байты источник трассировки.
аннулировать
Ipv4PacketProbe :: TraceSink (Ptr пакет, Ptr ipv4, интерфейс uint4_t)
{
NS_LOG_FUNCTION (этот << интерфейс пакета << ipv4 <<);
если (IsEnabled ())
{
m_packet = пакет;
m_ipv4 = ipv4;
m_interface = интерфейс;
m_output (пакет, ipv4, интерфейс);
uint32_t packetSizeNew = packet-> GetSize ();
m_outputBytes (m_packetSizeOld, packageSizeNew);
m_packetSizeOld = packageSizeNew;
}
}
Рекомендации
[Cic06]
Клаудио Чикконетти, Энцо Мингоцци, Джованни Стеа, «Интегрированная платформа для
Обеспечение эффективного сбора данных и статистического анализа с помощью ns2, семинар по
нс-2 (WNS2), Пиза, Италия, октябрь 2006 г.
Коллекторы
Этот раздел является заполнителем для подробного описания функций, предоставляемых Collector.
класс к нс-3 моделирование и дает примеры того, как их кодировать в программе.
Примечание: Начиная с версии ns-3.18, коллекторы все еще находятся в стадии разработки и еще не входят в состав
каркаса.
Накопители
В этом разделе подробно описаны функции, предоставляемые классом Aggregator для нс-3
моделирование. Этот раздел предназначен для пользователей, заинтересованных в разработке моделирования с помощью
нс-3 инструменты и использование Data Collection Framework, класс Aggregator является
часть, чтобы генерировать выходные данные с результатами их моделирования.
Агрегатор Обзор
Предполагается, что объект-агрегатор должен быть подключен к одному или нескольким источникам трассировки, чтобы
получить ввод. Агрегаторы - это конечная точка данных, собранных сетью
Зонды и коллекторы во время моделирования. Работа агрегатора - взять эти
значения и преобразовать их в окончательный формат вывода, такой как текстовые файлы,
файлы электронных таблиц, графики или базы данных.
Обычно агрегатор подключен к одному или нескольким коллекторам. Таким образом, всякий раз, когда
источники трассировки сборщиков экспортируют новые значения, агрегатор может обработать значение, чтобы
что его можно использовать в формате окончательного вывода, где значения данных будут располагаться после
моделирование.
Обратите внимание на следующее об агрегаторах:
· Агрегаторы могут динамически включаться и выключаться во время моделирования с вызовами
Давать возможность() и Запрещать(). Например, агрегирование данных может быть отключено во время
фаза прогрева моделирования, что означает, что эти значения не будут включены в окончательный
средство вывода.
· Агрегаторы получают данные от коллекторов через обратные вызовы. Когда коллектор связан
к агрегатору выполняется вызов TraceConnect для установления трассировки агрегатора.
приемник как обратный вызов.
На сегодняшний день реализовано два агрегатора:
· ГнуплотАгрегатор
· Файловый агрегатор
GnuplotАгрегатор
GnuplotAggregator создает файлы вывода, используемые для создания gnuplots.
В конце моделирования GnuplotAggregator создаст 3 разных файла:
· Файл данных gnuplot, разделенный пробелами
· Контрольный файл gnuplot
· Сценарий оболочки для создания gnuplot
Создание
Здесь будет создан объект типа GnuplotAggregator, чтобы показать, что нужно сделать.
Один объявляет GnuplotAggregator в динамической памяти с помощью класса интеллектуального указателя.
(Птр ). Чтобы создать GnuplotAggregator в динамической памяти с интеллектуальными указателями, достаточно
необходимо позвонить в нс-3 метод CreateObject (). Следующий код из
SRC / статистика / примеры / gnuplot-aggregator-example.cc показывает, как это сделать:
строка fileNameWithoutExtension = "gnuplot-aggregator";
// Создаем агрегатор.
Ptr агрегатор =
CreateObject (имя_файлаWithoutExtension);
Первый аргумент конструктора fileNameWithoutExtension - это имя
Файлы, связанные с gnuplot, для записи без расширения. Этот GnuplotAggregator создаст
разделенный пробелами файл данных gnuplot с именем "gnuplot-aggregator.dat", управляющий файл gnuplot
с именем "gnuplot-aggregator.plt" и сценарий оболочки для создания gnuplot с именем +
"gnuplot-aggregator.sh".
Созданный gnuplot может иметь свой ключ в 4 разных местах:
· Нет ключа
· Ключ внутри сюжета (по умолчанию)
· Ключ над сюжетом
· Ключ под сюжетом
Следующие значения перечисления местоположения ключа gnuplot могут указывать положение ключа:
перечисление KeyLocation {
НЕТ КЛЮЧА,
КЛЮЧ_ВНУТРИ,
KEY_ВЫШЕ,
KEY_BELOW
};
Если было желательно, чтобы ключ был внизу, а не в положении по умолчанию внутри, тогда
вы могли бы сделать следующее.
агрегатор-> SetKeyLocation (GnuplotAggregator :: KEY_BELOW);
Примеры
Здесь будет подробно обсуждаться один пример:
· Пример агрегатора Gnuplot
Гнуплот Агрегатор Пример
Пример использования GnuplotAggregator можно найти в
SRC / статистика / примеры / gnuplot-aggregator-example.cc.
Следующий двухмерный gnuplot был создан с использованием этого примера.
[изображение] 2-D Gnuplot Создано gnuplot-aggregator-example.cc Пример..UNINDENT
Этот код из примера показывает, как создать GnuplotAggregator, как обсуждалось.
выше.
недействительным Create2dPlot ()
{
использование пространства имен std;
строка fileNameWithoutExtension = "gnuplot-aggregator";
string plotTitle = "График агрегатора Gnuplot";
string plotXAxisHeading = "Время (секунды)";
строка plotYAxisHeading = "Двойные значения";
string plotDatasetLabel = "Значения данных";
строка datasetContext = "Набор данных / Контекст / Строка";
// Создаем агрегатор.
Ptr агрегатор =
CreateObject (имя_файлаWithoutExtension);
Устанавливаются различные атрибуты GnuplotAggregator, включая двумерный набор данных, который будет
нанесен.
// Устанавливаем свойства агрегатора.
агрегатор-> SetTerminal ("png");
агрегатор-> SetTitle (plotTitle);
агрегатор-> SetLegend (plotXAxisHeading, plotYAxisHeading);
// Добавляем набор данных в агрегатор.
агрегатор-> Add2dDataset (datasetContext, plotDatasetLabel);
// агрегатор должен быть включен
агрегатор-> Включить ();
Затем вычисляются двумерные значения, и каждое из них индивидуально записывается в
GnuplotAggregator, использующий Write2d () функции.
двойное время;
двойное значение;
// Создаем двумерный набор данных.
для (время = -5.0; время <= +5.0; время + = 1.0)
{
// Расчет двухмерной кривой
//
// 2
// значение = время.
//
значение = время * время;
// Добавляем эту точку на график.
агрегатор-> Write2d (контекст набора данных, время, значение);
}
// Отключаем ведение журнала данных для агрегатора.
агрегатор-> Отключить ();
}
ФайлАгрегатор
FileAggregator отправляет полученные значения в файл.
FileAggregator может создавать файлы 4 различных типов:
· Отформатированный
· Разделенные пробелами (по умолчанию)
· Разделенные запятой
· Разделение табуляцией
Отформатированные файлы используют строки формата C-стиля и функцию sprintf () для печати их
значения в записываемом файле.
Создание
Здесь будет создан объект типа FileAggregator, чтобы показать, что нужно сделать.
Один объявляет FileAggregator в динамической памяти с помощью класса интеллектуального указателя (Ptr ).
Чтобы создать FileAggregator в динамической памяти с интеллектуальными указателями, достаточно вызвать
нс-3 метод CreateObject. Следующий код из
SRC / статистика / примеры / file-aggregator-example.cc показывает, как это сделать:
строка fileName = "файл-агрегатор-форматированные-значения.txt";
// Создаем агрегатор, который будет иметь форматированные значения.
Ptr агрегатор =
CreateObject (имя_файла, FileAggregator :: ОТФОРМАТИРОВАННОЕ);
Первым аргументом конструктора, filename, является имя файла для записи; в
Второй аргумент, fileType, - это тип файла для записи. Этот FileAggregator создаст
файл с именем "file-aggregator-formatted-values.txt" с его значениями, напечатанными, как указано
fileType, т. е. отформатированный в данном случае.
Допускаются следующие значения перечисления типов файлов:
перечисление ТипФайла {
ФОРМАТИРОВАННЫЙ,
SPACE_SEPARATED,
РАЗДЕЛЕННЫЕ ЗАПЯТОЙ,
TAB_SEPARATED
};
Примеры
Здесь будет подробно обсуждаться один пример:
· Пример агрегатора файлов
Файл Агрегатор Пример
Пример использования FileAggregator можно найти в
SRC / статистика / примеры / file-aggregator-example.cc.
Следующий текстовый файл с 2 столбцами значений, разделенных запятыми, был создан с использованием
пример.
-5,25
-4,16
-3,9
-2,4
-1,1
0,0
1,1
2,4
3,9
4,16
5,25
Этот код из примера показывает, как создать FileAggregator, как обсуждалось.
выше.
недействительным CreateCommaSeparatedFile ()
{
использование пространства имен std;
строка fileName = "файл-агрегатор-запятыми.txt";
строка datasetContext = "Набор данных / Контекст / Строка";
// Создаем агрегатор.
Ptr агрегатор =
CreateObject (имя_файла, FileAggregator :: COMMA_SEPARATED);
Атрибуты FileAggregator установлены.
// агрегатор должен быть включен
агрегатор-> Включить ();
Затем вычисляются двумерные значения, и каждое из них индивидуально записывается в
FileAggregator, использующий Write2d () функции.
двойное время;
двойное значение;
// Создаем двумерный набор данных.
для (время = -5.0; время <= +5.0; время + = 1.0)
{
// Расчет двухмерной кривой
//
// 2
// значение = время.
//
значение = время * время;
// Добавляем эту точку на график.
агрегатор-> Write2d (контекст набора данных, время, значение);
}
// Отключаем ведение журнала данных для агрегатора.
агрегатор-> Отключить ();
}
Следующий текстовый файл с 2 столбцами форматированных значений также был создан с использованием
пример.
Время = -5.000e + 00 Значение = 25
Время = -4.000e + 00 Значение = 16
Время = -3.000e + 00 Значение = 9
Время = -2.000e + 00 Значение = 4
Время = -1.000e + 00 Значение = 1
Время = 0.000e + 00 Значение = 0
Время = 1.000e + 00 Значение = 1
Время = 2.000e + 00 Значение = 4
Время = 3.000e + 00 Значение = 9
Время = 4.000e + 00 Значение = 16
Время = 5.000e + 00 Значение = 25
Этот код из примера показывает, как создать FileAggregator, как обсуждалось.
выше.
недействительным CreateFormattedFile ()
{
использование пространства имен std;
строка fileName = "файл-агрегатор-форматированные-значения.txt";
строка datasetContext = "Набор данных / Контекст / Строка";
// Создаем агрегатор, который будет иметь форматированные значения.
Ptr агрегатор =
CreateObject (имя_файла, FileAggregator :: ОТФОРМАТИРОВАННОЕ);
Устанавливаются атрибуты FileAggregator, включая используемую строку формата C.
// Устанавливаем формат значений.
агрегатор-> Set2dFormat ("Время =% .3e \ tValue =% .0f");
// агрегатор должен быть включен
агрегатор-> Включить ();
Затем вычисляются двумерные значения, и каждое из них индивидуально записывается в
FileAggregator, использующий Write2d () функции.
двойное время;
двойное значение;
// Создаем двумерный набор данных.
для (время = -5.0; время <= +5.0; время + = 1.0)
{
// Расчет двухмерной кривой
//
// 2
// значение = время.
//
значение = время * время;
// Добавляем эту точку на график.
агрегатор-> Write2d (контекст набора данных, время, значение);
}
// Отключаем ведение журнала данных для агрегатора.
агрегатор-> Отключить ();
}
адаптеры
В этом разделе подробно описаны функции, предоставляемые классом адаптера для нс-3
моделирование. Этот раздел предназначен для пользователей, заинтересованных в разработке моделирования с помощью
нс-3 инструменты и использование Data Collection Framework, частью которого является класс Adapter,
для генерации выходных данных с результатами их моделирования.
Примечание: термин «адаптер» может также записываться как «адаптер»; мы выбрали орфографию с выравниванием
со стандартом C ++.
адаптер Обзор
Адаптер используется для установления соединений между различными типами объектов DCF.
На сегодняшний день реализован один Адаптер:
· Адаптер временных рядов
Время Серии адаптер
TimeSeriesAdaptor позволяет зондам подключаться напрямую к агрегаторам без необходимости
Коллектор посередине.
Оба реализованных помощника DCF используют TimeSeriesAdaptors для проверки
значения разных типов и выводят текущее время плюс значение с обоими преобразованными
в два раза.
Роль класса TimeSeriesAdaptor - роль адаптера, который принимает необработанные значения
проверяет данные разных типов и выводит кортеж из двух двойных значений. Первый - это
метка времени, которая может иметь различное разрешение (например, секунды, миллисекунды и т. д.) в
будущее, но которое в настоящее время жестко запрограммировано на Seconds. Второй - это преобразование
не двойное значение, а двойное значение (возможно, с потерей точности).
Объем / ограничения
В этом разделе обсуждаются объем и ограничения структуры сбора данных.
В настоящее время в DCF реализованы только эти Зонды:
· Логический зонд
· Двойной зонд
· Uinteger8Probe
· Uinteger16Probe
· Uinteger32Probe
· ТаймПроб
· ПакетПроб
· ПриложениеПакетПробе
· IPv4PacketProbe
В настоящее время в DCF нет доступных коллекторов, хотя BasicStatsCollector находится под
развития.
В настоящее время в DCF реализованы только следующие агрегаторы:
· ГнуплотАгрегатор
· Файловый агрегатор
В настоящее время в DCF реализован только этот адаптер:
Адаптер временных рядов.
Будущее Работайте
В этом разделе обсуждается будущая работа, которую предстоит проделать в рамках структуры сбора данных.
Вот некоторые вещи, которые еще предстоит сделать:
· Подключите больше источников трассировки в нс-3 код, чтобы получить больше значений из симулятора.
· Внедрить больше типов зондов, чем есть в настоящее время.
· Реализуйте больше, чем просто текущий двумерный сборщик, BasicStatsCollector.
· Внедрить больше агрегаторов.
· Реализуйте больше, чем просто адаптеры.
Статистический Рамки
В этой главе описывается работа по сбору данных моделирования и статистическая основа для
нс-3.
Исходный код статистической основы находится в каталоге src / stats.
Цели
Основные цели этих усилий заключаются в следующем:
· Предоставлять функциональные возможности для записи, расчета и представления данных и статистики для анализа
сетевого моделирования.
· Повышение производительности моделирования за счет сокращения необходимости создания обширных журналов трассировки в
для сбора данных.
· Возможность управления симуляцией через онлайн-статистику, например, прекращение симуляции или
повторные испытания.
Производные подцели и другие целевые функции включают следующее:
· Интеграция с существующей системой слежения NS-3 в качестве базовой инструментальной базы
внутреннего механизма моделирования, например сетевых стеков, сетевых устройств и каналов.
· Предоставление пользователям возможности использовать структуру статистики без необходимости использования трассировки
системы.
· Помощь пользователям в создании, агрегировании и анализе данных по нескольким испытаниям.
· Поддержка инструментов, созданных пользователем, например, событий, связанных с конкретным приложением, и
меры.
· Низкая нагрузка на память и ЦП, когда пакет не используется.
· Максимальное использование существующих инструментов анализа и вывода. Фреймворк может
предоставить некоторую базовую статистику, но основное внимание уделяется сбору данных и их обработке.
доступны для манипуляций с помощью установленных инструментов.
· Возможная поддержка распространения независимых репликаций важна, но не включена
в первом раунде функций.
Обзор
Платформа статистики включает в себя следующие функции:
· Базовая структура и два основных сборщика данных: счетчик и минимальный / максимальный / средний / общий
наблюдатель.
· Расширения для простой работы с временами и пакетами.
· Вывод в виде обычного текста, отформатированный для OMNet ++.
· Вывод базы данных с использованием SQLite, автономный, легкий, высокопроизводительный механизм SQL.
· Обязательные и открытые метаданные для описания прогонов и работы с ними.
· Пример, основанный на теоретическом эксперименте по изучению свойств НС-3.
производительность специального Wi-Fi по умолчанию. Он включает в себя следующее:
· Конструкции двухузловой специальной сети Wi-Fi с параметризованным расстоянием между узлами
Кроме.
· Приложения источника и приемника трафика UDP с немного другим поведением и
крючки для измерения, чем классы ложи.
· Сбор данных от ядра NS-3 через существующие сигналы трассировки, в частности данные о
фреймы, переданные и полученные объектами MAC WiFi.
· Инструментарий пользовательских приложений путем подключения новых сигналов трассировки к статистике
framework, а также через прямые обновления. Информация записывается об общем количестве пакетов
отправлено и получено, передано байтов и сквозная задержка.
· Пример использования тегов пакетов для отслеживания сквозной задержки.
· Простой управляющий скрипт, который запускает несколько попыток эксперимента при различных
расстояния и запрашивает полученную базу данных для построения графика с помощью GNUPlot.
Делать
Пункты с высоким приоритетом включают:
· Включение кода онлайн-статистики, например, для доверительных интервалов эффективного использования памяти.
· Положения в сборщиках данных для прекращения прогонов, т. Е. Когда пороговое значение или
уверенность встречается.
· Сборщики данных для регистрации образцов с течением времени и вывода в различные форматы.
· Продемонстрируйте написание простого клея циклических событий для регулярного опроса некоторой ценности.
Каждый из них должен быть несложным для включения в текущую структуру.
Подход
Структура основана на следующих основных принципах:
· Одно испытание эксперимента проводится одним экземпляром программы моделирования, будь то в
параллельно или последовательно.
· Сценарий управления выполняет экземпляры моделирования, при необходимости изменяя параметры.
· Данные собираются и хранятся для построения и анализа с использованием внешних скриптов и
существующие инструменты.
· Меры в рамках ядра NS-3 принимаются путем подключения структуры статистики к существующим
отслеживать сигналы.
· Сигналы трассировки или прямые манипуляции с фреймворком могут использоваться для инструментовки на заказ
код моделирования.
Эти основные компоненты структуры и их взаимодействие изображены на
следующий рисунок. [изображение]
Пример
В этом разделе рассматривается процесс построения эксперимента в рамках и
создание данных для анализа (графиков) из него, демонстрация структуры и API вместе
путь.
Вопрос
'' Какова (смоделированная) производительность Wi-Fi NetDevices ns-3 (с использованием значения по умолчанию
настройки)? Насколько далеко друг от друга могут быть беспроводные узлы в моделировании, прежде чем они не смогут
надежно общаться?»
· Гипотеза: на основе знаний о производительности в реальной жизни узлы должны взаимодействовать
достаточно хорошо на расстоянии не менее 100 м друг от друга. Связь за пределами 200 м не должна быть
возможно.
Хотя это не очень распространенный вопрос в контексте моделирования, это важное свойство
базовое понимание которых должны иметь разработчики симуляторов. Это также общий
исследование, проведенное на живом оборудовании.
Симулятор Программа
Первое, что нужно сделать при реализации этого эксперимента, — это разработать симуляцию.
программа. Код для этого примера можно найти в примеры/статистика/wifi-example-sim.cc.
Он выполняет следующие основные шаги.
· Объявление параметров и разбор командной строки с помощью ns3::Командная строка.
двойное расстояние = 50.0;
строковый формат ("OMNet++");
строковый эксперимент ("wifi-distance-test");
строковая стратегия ("wifi-по умолчанию");
строка runID;
Командная строка командной строки;
cmd.AddValue("distance", "Расстояние между узлами (в метрах).", Distance);
cmd.AddValue("format", "Формат для вывода данных.", format);
cmd.AddValue("эксперимент", "Идентификатор эксперимента.", эксперимент);
cmd.AddValue("стратегия", "Идентификатор стратегии.", стратегия);
cmd.AddValue("run", "Идентификатор запуска", runID);
cmd.Parse(argc, argv);
· Создание узлов и сетевых стеков с использованием ns3 :: NodeContainer, ns3::WiFiHelperи
ns3::ИнтернетСтакхелпер.
Узлы NodeContainer;
узлы.Создать(2);
WifiПомощник по вайфаю;
wifi.SetMac("ns3::AdhocWifiMac");
wifi.SetPhy("ns3::WifiPhy");
NetDeviceContainer nodeDevices = wifi.Install(узлы);
InternetStackHelper Интернет;
интернет.Установить(узлы);
IPv4AddressHelper ipAddrs;
ipAddrs.SetBase("192.168.0.0", "255.255.255.0");
ipAddrs.Assign(nodeDevices);
· Позиционирование узлов с помощью ns3::MobilityHelper. По умолчанию узлы имеют статические
мобильны и не будут двигаться, но должны быть расположены на заданном расстоянии друг от друга. Есть
несколько способов сделать это; это делается здесь с помощью ns3::ListPositionAllocator, который привлекает
позиции из заданного списка.
MobilityHelper мобильность;
Птр позицияAlloc =
СоздатьОбъект ();
positionAlloc->Добавить(Вектор(0.0, 0.0, 0.0));
positionAlloc->Добавить(Вектор(0.0, расстояние, 0.0));
мобильность.SetPositionAllocator(positionAlloc);
мобильность.Установить(узлы);
· Установка генератора трафика и стока трафика. Акции Приложения может быть
используется, но пример включает пользовательские объекты в src/test/test02-apps.(cc|h), Эти
имеют простое поведение, генерируя заданное количество пакетов с заданным интервалом.
Поскольку их всего по одному, они устанавливаются вручную; для большего набора
ns3:: Помощник по приложению можно было бы использовать класс. Закомментированный Конфиг :: Установить изменения строки
пункт назначения пакетов, установленный по умолчанию для широковещательной передачи в этом примере. Обратите внимание, что
в целом Wi-Fi может иметь разную производительность для широковещательных и одноадресных кадров из-за
различные политики управления скоростью и повторной передачи MAC.
Птр appSource = NodeList::ПолучитьУзел(0);
Птр отправитель = СоздатьОбъект ();
appSource->AddApplication (отправитель);
отправитель->Начать(Секунд(1));
Птр appSink = NodeList::ПолучитьУзел(1);
Птр получатель = СоздатьОбъект ();
appSink->AddApplication (получатель);
приемник->Старт(Секунд(0));
// Config::Set("/NodeList/*/ApplicationList/*/$Sender/Destination",
// Ipv4AddressValue("192.168.0.2"));
· Настройка собираемых данных и статистики. Основная парадигма состоит в том, что
ns3:: Сборщик данных объект создается для хранения информации об этом конкретном запуске, чтобы
какие наблюдатели и калькуляторы подключены для фактической генерации данных. Важно,
информация о запуске включает метки для «эксперимента», «стратегии», «ввода» и
''бегать''. Они используются для последующей идентификации и простой группировки данных из нескольких испытаний.
· Эксперимент – это исследование, частью которого является это испытание. Вот он по вайфаю
Производительность и расстояние.
· Стратегия – это код или параметры, изучаемые в этом испытании. В этом примере
это исправлено, но очевидным расширением было бы исследование другого бита WiFi
ставки, каждая из которых будет отдельной стратегией.
· Исходные данные – это конкретная проблема, поставленная перед этим испытанием. Вот это просто
расстояние между двумя узлами.
· RunID – это уникальный идентификатор для этой пробной версии, которым помечается информация о ней.
для идентификации в последующем анализе. Если идентификатор запуска не указан, пример программы делает
(слабый) идентификатор запуска с использованием текущего времени.
Эти четыре части метаданных необходимы, но может потребоваться больше. Они могут быть добавлены
к записи с помощью ns3::DataCollector::AddMetadata() метод.
Данные коллектора данных;
data.DescribeRun(эксперимент, стратегия, ввод, runID);
data.AddMetadata("автор", "tjkopena");
Фактические наблюдения и расчеты выполняются ns3::Калькулятор данных объекты, из которых
существует несколько различных типов. Они создаются программой моделирования, прикрепленной к
код отчетности или выборки, а затем регистрируется в ns3:: Сборщик данных так они будут
будут запрошены позже для их вывода. Одним из простых механизмов наблюдения является использование существующих
источники трассировки, например, для инструментирования объектов в ядре ns-3 без изменения их
код. Здесь счетчик подключен непосредственно к сигналу трассировки на MAC-уровне WiFi на
целевой узел.
Птр totalRx = СоздатьОбъект ();
totalRx->SetKey("wifi-rx-frames");
Config::Connect("/NodeList/1/DeviceList/*/$ns3::WifiNetDevice/Rx",
MakeCallback(&PacketCounterCalculator::FrameUpdate, totalRx));
data.AddDataCalculator (totalRx);
Калькуляторами также можно манипулировать напрямую. В этом примере счетчик создается и
передается приложению-приемнику трафика для обновления при получении пакетов.
Птр > appRx = СоздатьОбъект >();
appRx->SetKey("получатель-RX-пакетов");
приемник->SetCounter(appRx);
data.AddDataCalculator (appRx);
Чтобы увеличить счетчик, код обработки пакетов приемника затем вызывает один из
методы обновления калькулятора.
m_calc->Обновить();
Программа также включает в себя несколько других примеров, использующих как примитивные
калькуляторы, такие как ns3::Счетчиккалькулятор и те, которые приспособлены для наблюдения за пакетами и
раз. В src/test/test02-apps.(cc|h) он также создает простой пользовательский тег, который использует
отслеживать сквозную задержку для сгенерированных пакетов, сообщая о результатах
ns3::TimeMinMaxAvgTotalCalculator калькулятор данных.
· Запуск симуляции, которая после создания очень проста.
Симулятор::Выполнить();
· Создание либо OMNet ++ or SQLite вывод, в зависимости от аргументов командной строки. К
сделай это ns3::DataOutputInterface объект создан и настроен. Конкретный тип
это будет определять выходной формат. Затем этому объекту присваивается
ns3:: Сборщик данных объект, который он опрашивает для получения вывода.
Птр вывод;
если (формат == "OMNet++") {
NS_LOG_INFO("Создание вывода данных в формате OMNet++.");
вывод = СоздатьОбъект ();
} Еще {
# ifdef STAT_USE_DB
NS_LOG_INFO("Создание вывода данных в формате SQLite.");
вывод = СоздатьОбъект ();
# конец
}
вывод->вывод(данные);
· Освобождение памяти, используемой симуляцией. Это должно быть в конце основного
функция для примера.
Симулятор::Уничтожить();
Запись
Чтобы увидеть, что делает программа-пример, приложения и структура статистики в деталях, установите
НС_ЛОГ переменная соответствующим образом. Ниже приводится обильный вывод из всех
три.
$ экспорт NS_LOG=WiFiDistanceExperiment:WiFiDistanceApps
Обратите внимание, что это чрезвычайно замедляет симуляцию.
Образец Результат
Компиляция и простой запуск тестовой программы добавит OMNet ++ форматированный вывод, например
следующее data.sca.
беги беги-1212239121
attr эксперимент "wifi-distance-test"
стратегия attr "wifi-по умолчанию"
ввод атрибута "50"
описание атрибута ""
атрибут "автор" "tjkopena"
скалярное количество Wi-Fi-TX-кадров 30
скалярное количество Wi-Fi-RX-кадров 30
скалярное количество пакетов sender-tx-packets 30
скалярный прием-RX-пакетов подсчитывает 30
скаляр tx-pkt-size count 30
скалярный tx-pkt-size всего 1920
скалярное среднее значение tx-pkt-size 64
скалярный tx-pkt-size max 64
скаляр tx-pkt-size мин. 64
скалярная задержка счетчика 30
суммарная скалярная задержка 5884980 нс
скалярная задержка в среднем 196166 нс
скалярная задержка макс. 196166 нс
скалярная задержка мин. 196166 нс
Control Сценарий
Для автоматизации сбора данных на различных входах (расстояниях) простой Bash
script используется для выполнения серии симуляций. Его можно найти на
примеры/статистика/wifi-example-db.sh. Скрипт предназначен для запуска из примеры/статистика/
каталог.
Скрипт проходит через набор расстояний, собирая результаты в SQLite
база данных. На каждой дистанции проводится пять испытаний, чтобы получить более точную картину ожидаемых результатов.
представление. Весь эксперимент занимает всего несколько десятков секунд, чтобы запуститься на низком уровне.
машина, так как во время моделирования нет выходных данных и генерируется небольшой трафик.
#!/ Бен / ш
РАССТОЯНИЯ="25 50 75 100 125 145 147 150 152 155 157 160 162 165 167 170 172 175 177 180"
ИСПЫТАНИЯ="1 2 3 4 5"
echo Пример эксперимента WiFi
если [ -e data.db ]
тогда
эхо Уничтожить data.db?
читать ответ
если [ "$ANS" = "да" -o "$ANS" = "y" ]
тогда
эхо Удаление базы данных
РМ data.db
fi
fi
для пробной версии в $TRIALS
do
для расстояния в $DISTANCES
do
echo Триал $триал, расстояние $расстояние
./bin/test02 --format=db --distance=$distance --run=run-$distance-$trial
сделанный
сделанный
Анализ и Заключение
После того, как все испытания были проведены, сценарий выполняет простой SQL-запрос по
база данных с использованием SQLite программа командной строки. Запрос вычисляет среднюю потерю пакетов в
каждый набор испытаний, связанных с каждой дистанцией. Не учитываются разные
стратегии, но информация присутствует в базе данных, чтобы сделать некоторые простые расширения
и сделать так. Собранные данные затем передаются в GNUPlot для построения графика.
CMD="выбрать exp.input,среднее(100-((rx.value*100)/tx.value))
от Singletons rx, Singletons tx, Experiments exp
где rx.run = tx.run И
rx.run = exp.run И
rx.name='receiver-rx-packets' И
tx.name='отправитель-tx-пакетов'
группировать по exp.input
заказать по абс(exp.input) ASC;"
sqlite3 -noheader data.db "$CMD" > wifi-default.data
sed -i "s/|/ /" wifi-default.data
gnuplot wifi-example.gnuplot
Скрипт GNUPlot, найденный по адресу примеры/статистика/wifi-example.gnuplot просто определяет вывод
формат и некоторое базовое форматирование графика.
установить терминальный постскриптум портретный расширенный lw 2 "Helvetica" 14
установить размер 1.0, 0.66
#------------------------------------------------- ------
установить "wifi-default.eps"
#set title "Потеря пакетов на расстоянии"
set xlabel "Расстояние (м) --- среднее из 5 испытаний на точку"
установить xrange [0:200]
установить ylabel "% потери пакетов"
установить диапазон [0: 110]
график «wifi-default.data» с заголовком строки «WiFi по умолчанию»
Конец Результат
Полученный график не свидетельствует о том, что производительность модели Wi-Fi по умолчанию ниже.
обязательно неразумным и придает некоторую уверенность хотя бы символической верности
реальность. Что еще более важно, это простое расследование было проведено на всем протяжении
с использованием статистической базы. Успех! [изображение]
RealTime
нс-3 был разработан для интеграции в среду тестовых стендов и виртуальных машин. К
интегрироваться с реальными сетевыми стеками и отправлять/потреблять пакеты, планировщик в реальном времени
необходимо попытаться синхронизировать часы моделирования с аппаратными часами. Мы описываем здесь
компонент этого: планировщик реального времени.
Цель планировщика реального времени состоит в том, чтобы вызвать прогрессирование часов симуляции.
происходить синхронно относительно некоторой внешней базы времени. Без присутствия
внешняя временная база (настенные часы), время симуляции мгновенно перескакивает с одного смоделированного
время до следующего.
Поведение
При использовании планировщика не в реальном времени (по умолчанию в нс-3), симулятор продвигает
время моделирования до следующего запланированного события. Во время выполнения события время моделирования составляет
замороженный. С планировщиком реального времени поведение аналогично с точки зрения
модели симуляции (т. е. время симуляции заморожено во время выполнения события), но между
событий, симулятор будет пытаться синхронизировать часы моделирования с машиной.
Часы.
Когда событие завершено и планировщик переходит к следующему событию,
планировщик сравнивает время выполнения следующего события с часами машины. Если следующий
событие запланировано на будущее, симулятор спит до тех пор, пока не будет достигнуто это реальное время
а затем выполняет следующее событие.
Может случиться так, что из-за обработки, присущей выполнению событий моделирования,
что симулятор не может идти в ногу с реальным временем. В таком случае все зависит от пользователя.
настройка что делать. Есть два нс-3 атрибуты, управляющие поведением. То
во-первых ns3::RealTimeSimulatorImpl::SynchronizationMode. Две возможные записи для
этот атрибут Лучшее усилие (по умолчанию) или ХардЛимит. В режиме «BestEffort»
симулятор просто попытается догнать реальное время, выполняя события, пока не достигнет
точка, в которой следующее событие произойдет в будущем (в реальном времени), иначе симуляция закончится. В
Таким образом, в режиме BestEffort симуляция может занять больше времени, чем
время настенных часов. Другая опция «HardLimit» приведет к прекращению моделирования, если
порог толерантности превышен. Этот атрибут ns3::RealTimeSimulatorImpl::HardLimit
и значение по умолчанию составляет 0.1 секунды.
Другой режим работы — это режим, в котором симулированное время замер во время мероприятия
исполнение. Этот режим моделирования в реальном времени был реализован, но удален из нс-3 дерево
из-за вопросов о том, будет ли это полезно. Если пользователи заинтересованы в реальном времени
симулятор, для которого время моделирования не останавливается во время выполнения события (т. е. каждый
позвонить Симулятор::Сейчас() возвращает текущее время настенных часов, а не время, когда
событие начало выполняться), обратитесь в список рассылки ns-developers.
Применение
Использование симулятора реального времени просто с точки зрения сценариев.
Пользователям просто нужно установить атрибут Тип реализации симулятора к реальному времени
симулятор, например:
GlobalValue::Bind("SimulatorImplementationType",
StringValue("ns3::RealtimeSimulatorImpl"));
Есть скрипт в примеры/в реальном времени/в реальном времени-udp-echo.cc у которого есть пример того, как
настроить поведение в реальном времени. Пытаться:
$ ./waf --run realtime-udp-echo
Будет ли симулятор работать наилучшим образом или политика жесткого ограничения будет регулироваться
атрибутами, описанными в предыдущем разделе.
Реализация
Реализация содержится в следующих файлах:
· src/core/model/realtime-simulator-impl.{cc,h}
· src/core/model/wall-lock-synchronizer.{cc,h}
Для того, чтобы создать планировщик реального времени, в первом приближении нужно просто вызвать
время симуляции переходит в режим реального времени. Мы предлагаем сделать это, используя комбинацию
сон- и занят- ждет. Ожидание ожидания приводит к тому, что вызывающий процесс (поток) выдает
процессор на некоторое время. Несмотря на то, что указанное количество времени может пройти
до наносекундного разрешения, оно фактически преобразуется в специфичную для ОС степень детализации. В
Linux, гранулярность называется Jiffy. Обычно этого разрешения недостаточно для
наши потребности (порядка десяти миллисекунд), поэтому мы округляем и спим некоторое время.
меньшее количество Jiffies. Затем процесс пробуждается через указанное количество
Джиффис прошел. На данный момент у нас есть некоторое остаточное время для ожидания. На этот раз
обычно меньше, чем минимальное время сна, поэтому мы заняты ожиданием оставшейся части
время. Это означает, что поток просто сидит в цикле for, потребляя циклы до тех пор, пока не
наступает желаемое время. После комбинации ожиданий сна и ожидания, прошедшее в реальном времени
(настенные) часы должны согласовываться со временем симуляции следующего события и симуляцией
продолжается.
Помощники
Вышеприведенные главы познакомили вас с различными нс-3 концепции программирования, такие как умный
указатели для управления памятью с подсчетом ссылок, атрибутами, пространствами имен, обратными вызовами и т. д.
Пользователи, работающие с этим низкоуровневым API, могут подключаться нс-3 объекты с мелкой зернистостью.
Однако программа моделирования, полностью написанная с использованием низкоуровневого API, была бы довольно длинной.
и утомительно кодировать. По этой причине был наложен отдельный так называемый «вспомогательный API».
на ядре нс-3 API. Если вы прочитали нс-3 учебник, вы уже будете знакомы
с вспомогательным API, так как это API, с которым новые пользователи обычно знакомятся в первую очередь.
В этой главе мы представляем философию разработки вспомогательного API и противопоставляем ее
низкоуровневый API. Если вы станете активным пользователем нс-3, вы, вероятно, будете двигаться вперед и назад
между этими API даже в одной программе.
Вспомогательный API преследует несколько целей:
1. остальная часть SRC / не имеет зависимостей от вспомогательного API; все, что можно сделать с
вспомогательный API может быть закодирован также на низкоуровневом API
2. Контейнеры: Часто в симуляциях нужно будет выполнить ряд одинаковых действий с группами.
объектов. Вспомогательный API интенсивно использует контейнеры похожих объектов, к которым
могут выполняться аналогичные или идентичные операции.
3. Вспомогательный API не является универсальным; он не стремится максимизировать повторное использование кода. Так,
программные конструкции, такие как полиморфизм и шаблоны, которые обеспечивают повторное использование кода.
не так распространен. Например, есть отдельные помощники CsmaNetDevice и
Помощники PointToPointNetDevice, но они не являются производными от общей базы NetDevice.
класса.
4. Вспомогательный API обычно работает с объектами, размещенными в стеке (а не в куче). За
некоторые программы, нс-3 пользователям, возможно, не придется беспокоиться о каком-либо низкоуровневом создании объектов или
обработка PTR; они могут обойтись контейнерами объектов и помощниками, размещенными в стеке.
которые действуют на них.
Вспомогательный API действительно предназначен для создания нс-3 программы легче писать и читать, без
лишая возможности низкоуровневый интерфейс. В остальной части этой главы представлены некоторые
примеры соглашений о программировании вспомогательного API.
Создание участки через Гнуплот Класс
Есть 2 распространенных метода создания сюжета с использованием нс-3 и gnuplot (‐
http://www.gnuplot.info):
1. Создайте управляющий файл gnuplot, используя нс-3класс Gnuplot.
2. Создайте файл данных gnuplot, используя значения, сгенерированные нс-3.
Этот раздел посвящен методу 1, т.е. тому, как построить график, используя нс-3Gnuplot
класс. Если вас интересует метод 2, см. подраздел «Реальный пример» в разделе
Раздел «Отслеживание» в нс-3 Обучение.
Создающий участки . Гнуплот Класс
Для создания графика с использованием нс-3класс Gnuplot:
1. Измените свой код, чтобы он использовал класс Gnuplot и его функции.
2. Запустите свой код, чтобы он создал управляющий файл gnuplot.
3. Вызовите gnuplot с именем управляющего файла gnuplot.
4. Просмотрите созданный графический файл в своем любимом средстве просмотра графики.
См. код из примеров графиков, которые обсуждаются ниже, для получения подробной информации о шаге 1.
An Пример Программа который Пользы Гнуплот Класс
Пример программы, которая использует нс-3Класс Gnuplot можно найти здесь:
src/stats/examples/gnuplot-example.cc
Чтобы запустить этот пример, сделайте следующее:
$ ./ваф оболочка
$ cd build/debug/src/stats/examples
$ ./gnuplot-пример
Это должно создать следующие управляющие файлы gnuplot в каталоге, где находится пример
расположен:
участок-2d.plt
сюжет-2d-с-ошибки-бары.plt
участок-3d.plt
Чтобы обработать эти управляющие файлы gnuplot, сделайте следующее:
$ gnuplotplot-2d.plt
$ gnuplotplot-2d-with-error-bars.plt
$ gnuplotplot-3d.plt
Это должно создать следующие графические файлы в каталоге, где находится пример.
располагается:
сюжет-2d.png
сюжет-2d-с-ошибками-барами.png
сюжет-3d.png
Вы можете просмотреть эти графические файлы в своем любимом средстве просмотра графики. Если у вас есть гимп
установлен на вашем компьютере, например, вы можете сделать это:
$ gimpplot-2d.png
$ gimpplot-2d-with-error-bars.png
$ gimpplot-3d.png
An Пример 2-Dimensional Участок
Следующий 2-мерный сюжет
[Image]
был создан с использованием следующего кода из gnuplot-example.cc:
использование пространства имен std;
строка fileNameWithNoExtension = "plot-2d";
строка graphicsFileName = имя_файла без расширения + ".png";
string plotFileName = fileNameWithNoExtension + ".plt";
string plotTitle = "Двухмерный график";
string dataTitle = "Двухмерные данные";
// Создаем график и устанавливаем его заголовок.
График Gnuplot (имя_графического_файла);
сюжет.SetTitle (название сюжета);
// Создаем графический файл, который создаст файл графика, когда он
// используется с Gnuplot, быть PNG-файлом.
plot.SetTerminal("png");
// Установить метки для каждой оси.
plot.SetLegend("Значения X", "Значения Y");
// Установите диапазон для оси x.
plot.AppendExtra ("установить xrange [-6:+6]");
// Создаем экземпляр набора данных, устанавливаем его заголовок и делаем точки
// строится вместе с соединительными линиями.
набор данных Gnuplot2dDataset;
набор данных.SetTitle (заголовок данных);
набор данных.SetStyle(Gnuplot2dDataset::LINES_POINTS);
двойной x;
двойной у;
// Создаем двумерный набор данных.
для (х = -5.0; х <= +5.0; х += 1.0)
{
// Расчет двухмерной кривой
//
// 2
// у = х.
//
у = х * х;
// Добавляем эту точку.
набор данных.Добавить (х, у);
}
// Добавляем набор данных на график.
plot.AddDataset (набор данных);
// Открываем файл графика.
ofstreamplotFile(plotFileName.c_str());
// Записываем файл графика.
plot.GenerateOutput(plotFile);
// Закрыть файл графика.
ФайлФайла.закрыть ();
An Пример 2-Dimensional Участок Ошибка брусья
Следующий двумерный график с планками погрешностей в направлениях x и y
[Image]
был создан с использованием следующего кода из gnuplot-example.cc:
использование пространства имен std;
string fileNameWithNoExtension = "plot-2d-with-error-bars";
строка graphicsFileName = имя_файла без расширения + ".png";
string plotFileName = fileNameWithNoExtension + ".plt";
string plotTitle = "Двухмерный график с планками погрешностей";
string dataTitle = "Двухмерные данные с планками погрешностей";
// Создаем график и устанавливаем его заголовок.
График Gnuplot (имя_графического_файла);
сюжет.SetTitle (название сюжета);
// Создаем графический файл, который создаст файл графика, когда он
// используется с Gnuplot, быть PNG-файлом.
plot.SetTerminal("png");
// Установить метки для каждой оси.
plot.SetLegend("Значения X", "Значения Y");
// Установите диапазон для оси x.
plot.AppendExtra ("установить xrange [-6:+6]");
// Создаем экземпляр набора данных, устанавливаем его заголовок и делаем точки
// построен без соединительных линий.
набор данных Gnuplot2dDataset;
набор данных.SetTitle (заголовок данных);
набор данных.SetStyle(Gnuplot2dDataset::POINTS);
// Сделать так, чтобы в наборе данных были планки погрешностей как в направлении x, так и в направлении y.
набор данных.SetErrorBars(Gnuplot2dDataset::XY);
двойной x;
двойной xErrorDelta;
двойной у;
двойной yErrorDelta;
// Создаем двумерный набор данных.
для (х = -5.0; х <= +5.0; х += 1.0)
{
// Расчет двухмерной кривой
//
// 2
// у = х.
//
у = х * х;
// Сделать неопределенность в направлении x постоянной и сделать
// неопределенность в направлении y будет постоянной долей
// значение у.
xErrorDelta = 0.25;
yErrorDelta = 0.1 * у;
// Добавляем эту точку с неопределенностями как по x, так и по y
// направление.
набор данных.Добавить (x, y, xErrorDelta, yErrorDelta);
}
// Добавляем набор данных на график.
plot.AddDataset (набор данных);
// Открываем файл графика.
ofstreamplotFile(plotFileName.c_str());
// Записываем файл графика.
plot.GenerateOutput(plotFile);
// Закрыть файл графика.
ФайлФайла.закрыть ();
An Пример 3-Dimensional Участок
Следующий 3-мерный сюжет
[Image]
был создан с использованием следующего кода из gnuplot-example.cc:
использование пространства имен std;
строка fileNameWithNoExtension = "plot-3d";
строка graphicsFileName = имя_файла без расширения + ".png";
string plotFileName = fileNameWithNoExtension + ".plt";
string plotTitle = "Двухмерный график";
string dataTitle = "Двухмерные данные";
// Создаем график и устанавливаем его заголовок.
График Gnuplot (имя_графического_файла);
сюжет.SetTitle (название сюжета);
// Создаем графический файл, который создаст файл графика, когда он
// используется с Gnuplot, быть PNG-файлом.
plot.SetTerminal("png");
// Поворачиваем график на 30 градусов вокруг оси x, а затем поворачиваем
// построить 120 градусов вокруг новой оси z.
plot.AppendExtra ("установить вид 30, 120, 1.0, 1.0");
// Сделаем нуль для оси z на плоскости оси x и оси y.
plot.AppendExtra ("установить тиковый уровень 0");
// Установить метки для каждой оси.
plot.AppendExtra ("установить xlabel 'Значения X'");
plot.AppendExtra ("установить метку Y Values");
plot.AppendExtra ("установить zlabel 'Значения Z'");
// Установите диапазоны для осей x и y.
plot.AppendExtra ("установить xrange [-5:+5]");
plot.AppendExtra ("установить yrange [-5:+5]");
// Создаем экземпляр набора данных, устанавливаем его заголовок и делаем точки
// соединены линиями.
набор данных Gnuplot3dDataset;
набор данных.SetTitle (заголовок данных);
набор данных.SetStyle ("с линиями");
двойной x;
двойной у;
двойной г;
// Создаем двумерный набор данных.
для (х = -5.0; х <= +5.0; х += 1.0)
{
для (y = -5.0; y <= +5.0; y += 1.0)
{
// Расчет трехмерной поверхности
//
// 2 2
// г = х * у.
//
г = х * х * у * у;
// Добавляем эту точку.
набор данных.Добавить (x, y, z);
}
// Пустая строка необходима в конце данных каждого значения x
// точек для работы трехмерной сетки поверхности.
набор данных.AddEmptyLine();
}
// Добавляем набор данных на график.
plot.AddDataset (набор данных);
// Открываем файл графика.
ofstreamplotFile(plotFileName.c_str());
// Записываем файл графика.
plot.GenerateOutput(plotFile);
// Закрыть файл графика.
ФайлФайла.закрыть ();
. Питон в Run нс-3
Привязки Python позволяют использовать код C++ в нс-3 для вызова из Python.
В этой главе показано, как создать сценарий Python, который может выполняться нс-3 а также
процесс создания привязок Python для C++ нс-3 модуль.
Введение
Цель привязок Python для нс-3 являются двухкратными:
1. Разрешить программисту писать полные сценарии моделирования на Python (‐
http://www.python.org);
2. Создание прототипов новых моделей (например, протоколов маршрутизации).
Пока в центре внимания креплений находится первая цель, но вторая
цель в конечном итоге также будет поддержана. Привязки Python для нс-3 разрабатываются
с помощью нового инструмента под названием PyBindGen (http://code.google.com/p/pybindgen).
An Пример Питон Сценарий который Работает нс-3
Вот пример кода, написанного на Python и работающего нс-3, который написан
в С++. Этот пример Python можно найти в примеры/учебник/first.py:
импортировать ns.applications
импортировать ns.core
импортировать ns.internet
импортировать ns.network
импортировать ns.point_to_point
ns.core.LogComponentEnable("UdpEchoClientApplication", ns.core.LOG_LEVEL_INFO)
ns.core.LogComponentEnable("UdpEchoServerApplication", ns.core.LOG_LEVEL_INFO)
узлы = ns.network.NodeContainer()
узлы.Создать(2)
pointToPoint = ns.point_to_point.PointToPointHelper()
pointToPoint.SetDeviceAttribute("DataRate", ns.core.StringValue("5Mbps"))
pointToPoint.SetChannelAttribute ("Задержка", ns.core.StringValue ("2 мс"))
устройства = pointToPoint.Install(узлы)
стек = ns.internet.InternetStackHelper()
stack.Install(узлы)
адрес = ns.internet.Ipv4AddressHelper()
address.SetBase(ns.network.Ipv4Address("10.1.1.0"), ns.network.Ipv4Mask("255.255.255.0"))
interfaces = address.Assign (устройства);
эхо-сервер = ns.applications.UdpEchoServerHelper(9)
serverApps = echoServer.Install(узлов.Получить(1))
serverApps.Start(ns.core.Seconds(1.0))
serverApps.Stop(ns.core.Seconds(10.0))
echoClient = ns.applications.UdpEchoClientHelper(интерфейсы.GetAddress(1), 9)
echoClient.SetAttribute("МаксПакетов", ns.core.UintegerValue(1))
echoClient.SetAttribute("Интервал", ns.core.TimeValue(ns.core.Seconds (1.0)))
echoClient.SetAttribute("РазмерПакета", ns.core.UintegerValue(1024))
clientApps = echoClient.Install(узлов.Получить(0))
clientApps.Start(ns.core.Seconds(2.0))
clientApps.Stop(ns.core.Seconds(10.0))
ns.core.Simulator.Run()
ns.core.Simulator.Destroy()
Бег Питон Сценарии
waf содержит некоторые параметры, которые автоматически обновляют путь python для поиска файла ns3.
модуль. Для запуска примеров программ есть два способа использовать waf. Один
запустить waf-оболочку; например:
$ ./ваф --шелл
$ примеры python/беспроводная сеть/mixed-wireless.py
а другой - использовать параметр --pyrun для waf:
$ ./waf --pyrun example/wireless/mixed-wireless.py
Чтобы запустить скрипт Python под отладчиком C:
$ ./ваф --шелл
$ gdb --args примеры python/wireless/mixed-wireless.py
Чтобы запустить собственный скрипт Python, который вызывает нс-3 и что имеет этот путь,
/путь/к/вашему/примеру/my-script.py, Выполните следующие действия:
$ ./ваф --шелл
$ python /path/to/your/example/my-script.py
Предостережения
Привязки Python для нс-3 находятся в стадии разработки, и некоторые ограничения известны
Разработчики. Некоторые из этих ограничений (не все) перечислены здесь.
Неполный Покрытие
Прежде всего, имейте в виду, что не 100% API поддерживается в Python. Несколько из
причины:
1. некоторые API используют указатели, которые требуют знания того, какая память
прохождение семантики (кто какой памятью владеет). Такое знание не является частью функции
подписи и либо документируется, либо иногда даже не документируется. Аннотации
необходимо для привязки этих функций;
2. Иногда используется необычный фундаментальный тип данных или конструкция C++, которая еще не
поддерживается PyBindGen;
3. GCC-XML не сообщает о классах на основе шаблонов, если они не созданы.
Большинство отсутствующих API-интерфейсов можно свернуть, если у них будет достаточно времени, терпения и опыта.
скорее всего, будет завернут, если будут отправлены отчеты об ошибках. Однако не отправляйте отчет об ошибке
говоря, что «привязки не завершены», потому что у нас нет рабочей силы, чтобы выполнить 100%
привязки.
Конверсия Конструкторы
Конверсия конструкторы еще не полностью поддерживаются PyBindGen, и они всегда действуют как
явные конструкторы при переводе API в Python. Например, в C++ вы можете сделать
это:
IPv4AddressHelper ipAddrs;
ipAddrs.SetBase("192.168.0.0", "255.255.255.0");
ipAddrs.Assign (базовые устройства);
В Python на данный момент вам нужно сделать:
ipAddrs = ns3.Ipv4AddressHelper()
ipAddrs.SetBase(ns3.Ipv4Address("192.168.0.0"), ns3.Ipv4Mask("255.255.255.0"))
ipAddrs.Assign(магистральные устройства)
Командная строка
КоманднаяСтрока::ДобавитьЗначение() в Python работает иначе, чем в нс-3. В Python
Первый параметр — это строка, представляющая имя параметра командной строки. Когда вариант
установлен, атрибут с тем же именем, что и имя опции, устанавливается на Командная строка()
объект. Пример:
NUM_NODES_SIDE_DEFAULT = 3
cmd = ns3.CommandLine()
cmd.NumNodesSide = Нет
cmd.AddValue("NumNodesSide", "Количество узлов на стороне сетки (общее количество узлов будет равно этому числу в квадрате)")
cmd.Parse(аргумент)
[...]
если cmd.NumNodesSide имеет значение None:
num_nodes_side = NUM_NODES_SIDE_DEFAULT
еще:
num_nodes_side = int (cmd.NumNodesSide)
трассировка
Трассировка на основе обратного вызова еще не поддерживается должным образом для Python, поскольку нс-3 API должен
должны быть предусмотрены для поддержки этого.
Запись файлов Pcap поддерживается через обычный API.
Трассировка Ascii поддерживается, поскольку нс-3.4 через обычный C++ API, переведенный на Python.
Однако трассировка ascii требует создания объекта ostream для передачи в ascii.
методы отслеживания. В Python C++ std::ofstream имеет минимальную оболочку, чтобы позволить
это. Например:
ascii = ns3.ofstream("wifi-ap.tr") # создаем файл
ns3.YansWifiPhyHelper.EnableAsciiAll(ascii)
ns3.Симулятор.Выполнить()
ns3.Симулятор.Уничтожить()
ascii.close() # закрыть файл
Есть одно предостережение: вы не должны допускать сборку мусора файлового объекта во время нс-3
все еще использует его. Это означает, что указанная выше переменная ascii не должна быть разрешена.
выходит за рамки, иначе программа рухнет.
Cygwin ограничение
Привязки Python не работают на Cygwin. Это связано с ошибкой gccxml.
Вам может это сойти с рук путем повторного сканирования определений API из cygwin.
окружение (./waf --python-scan). Однако наиболее вероятным решением, вероятно, будет
будь то мы отключаем привязки python в CygWin.
Если вы действительно заботитесь о привязках Python к Windows, попробуйте собрать с помощью mingw и нативного кода.
вместо питона. Или же, чтобы построить без привязок python, отключите привязки python в
этап настройки:
$ ./waf настроить --disable-python
Работы Питон Наручники
В настоящее время существует два типа привязок Python в нс-3:
1. Монолитные привязки содержат определения API для всех модулей и могут быть найдены в
единый каталог, привязки/питон.
2. Модульные привязки содержат определения API для одного модуля и могут быть найдены в каждом
модуль переплеты каталог.
Питон Наручники Рабочий процесс
Процесс, с помощью которого обрабатываются привязки Python, следующий:
1. Периодически разработчик использует GCC-XML (http://www.gccxml.org) сканирование на основе API
сценарий, который сохраняет отсканированное определение API как привязки/python/ns3_module_*.py файлов
или как файлы Python в каждом модуле переплеты каталог. Эти файлы хранятся под
контроль версий в главном нс-3 хранилище;
2. Другие разработчики клонируют репозиторий и используют уже отсканированные определения API;
3. При настройке нс-3, pybindgen будет автоматически загружен, если это еще не сделано
установлен. Вышел нс-3 tarballs отправит копию pybindgen.
Если что-то пойдет не так с компиляцией привязок Python, и вы просто хотите их игнорировать
и перейти к C++, вы можете отключить Python с помощью:
$ ./ваф --отключить-питон
инструкции для Управляемость Новое Файлы or Изменено API,
Итак, вы меняете существующие нс-3 API и привязки Python больше не компилируются? Делать
не отчаивайтесь, вы можете пересканировать привязки, чтобы создать новые привязки, отражающие изменения
до нс-3 API.
В зависимости от того, используете ли вы монолитные или модульные крепления, ознакомьтесь с приведенными ниже обсуждениями.
узнайте, как повторно сканировать привязки Python.
монолитный Питон Наручники
Сканирование монолитный Питон Наручники
Для сканирования монолитных привязок Python выполните следующие действия:
$ ./waf --python-сканирование
организация of монолитный Питон Наручники
Определения монолитного API Python организованы следующим образом. Для каждого нс-3 модуль
, файл привязки/python/ns3_module_ .py описывает его API. Каждый из этих
файлы имеют 3 функции верхнего уровня:
1. защиту регистр_типы(модуль)(): эта функция заботится о регистрации новых типов (например,
классы C++, перечисления), определенные в модуле;
2. защиту методы_регистрации(модуль)(): эта функция вызывает для каждого класса , Другая
функция register_methods_Ns3 (модуль). Эти последние функции добавляют метод
определения для каждого класса;
3. защиту регистр_функции(модуль)(): эта функция регистрирует нс-3 функции, принадлежащие
этот модуль.
модульная Питон Наручники
Обзор
Начиная с ns 3.11 добавляются модульные привязки, параллельно старым монолитным
привязки.
Новые привязки python генерируются в пространстве имен «ns», а не «ns3» для старого.
привязки. Пример:
из узла импорта ns.network
n1 = узел ()
С модульными привязками Python:
1. Существует один отдельный модуль расширения Python для каждого нс-3 модуль;
2. Сканирование определений API (apidefs) выполняется для каждого ns-модуля;
3. Файлы apidefs каждого модуля хранятся в подкаталоге «bindings» модуля.
каталог;
Сканирование модульная Питон Наручники
Например, чтобы отсканировать модульные привязки Python для основного модуля, сделайте следующее:
$ ./waf --apiscan=ядро
Чтобы просмотреть модульные привязки Python для всех модулей, выполните следующие действия:
$ ./ваф --apiscan=все
Создающий a Новое Модули
Если вы добавляете новый модуль, привязки Python продолжат компилироваться, но не будут
закройте новый модуль.
Чтобы покрыть новый модуль, вы должны создать привязки/python/ns3_module_ .py файл,
аналогично тому, что описано в предыдущих разделах, и прописать его в переменной
ЛОКАЛЬНЫЕ_МОДУЛИ() in привязки/python/ns3modulegen.py
Добавление модульная Наручники к A Существующий Модули
Чтобы добавить поддержку модульных привязок к существующему нс-3 модуль, просто добавьте следующее
строку в его функцию wscript build():
bld.ns3_python_bindings()
организация of модульная Питон Наручники
" источник/ /привязки каталог может содержать следующие файлы, некоторые из них
необязательный:
· callbacks_list.py: это отсканированный файл, НЕ ТРОГАТЬ. Содержит список
экземпляры шаблона Callback<...>, обнаруженные в просканированных заголовках;
· модульgen__gcc_LP64.py: это отсканированный файл, НЕ ТРОГАТЬ. Отсканированные определения API
для архитектуры GCC, LP64 (64-разрядная версия)
· модульgen__gcc_ILP32.py: это отсканированный файл, НЕ ТРОГАТЬ. Отсканированные определения API
для архитектуры GCC, ILP32 (32-разрядная версия)
· модульgen_customizations.py: вы можете дополнительно добавить этот файл, чтобы настроить
генерация кода pybindgen
· скан-header.h: вы можете дополнительно добавить этот файл, чтобы указать, какой заголовочный файл сканируется
для модуля. В основном этот файл сканируется вместо ns3/ -модуль.ч.
Как правило, первым оператором является #include "ns3/ -module.h", плюс некоторые другие
вещи для принудительного создания экземпляров шаблона;
· модуль_helpers.cc: вы можете добавить дополнительные файлы, такие как этот, которые будут связаны с python.
модуль расширения, но они должны быть зарегистрированы в файле wscript. смотреть на
src/core/wscript для примера того, как это сделать;
· .py: если этот файл существует, он становится «интерфейсным» модулем python для ns3.
модуль, а модуль расширения (файл .so) становится _ .so вместо .так.
То .py файл должен импортировать все символы из модуля _ (это больше
сложно, чем кажется, см. пример src/core/bindings/core.py), а затем можно добавить
некоторые дополнительные определения чистого Python.
Ещё Информация для Разработчики
Если вы разработчик и вам нужна дополнительная информация о нс-3привязки Python, см.
Питон Наручники Вики страница.
Tests
Обзор
Этот документ касается тестирования и проверки нс-3 .
Этот документ предоставляет
· справочная информация о терминологии и тестировании программного обеспечения (глава 2);
· описание среды тестирования ns-3 (глава 3);
· руководство для разработчиков моделей или участников новых моделей по написанию тестов (глава
4);
Короче говоря, первые три главы должны быть прочитаны русскими разработчиками и участниками, которые
нужно понимать, как добавлять тестовый код и проверенные программы, а остальные
документа предоставляет людям место для сообщения о том, какие аспекты выбранных моделей
были утверждены.
проверка данных
Эти глава май be пропущено by читатели знакомый основы of программное обеспечение тестирование.
Написание бездефектного программного обеспечения — трудная задача. Есть много измерений для
проблема, и существует большая путаница в отношении того, что подразумевается под разными терминами в
разные контексты. Мы сочли целесообразным потратить немного времени на изучение
тему и определение некоторых терминов.
Тестирование программного обеспечения можно приблизительно определить как процесс выполнения программы с
намерение найти ошибки. Когда кто-то вступает в дискуссию о тестировании программного обеспечения,
быстро становится очевидным, что существует множество различных складов ума, с помощью которых можно
подойти к предмету.
Например, можно разбить процесс на широкие функциональные категории, такие как
«тестирование правильности», «тестирование производительности», «тестирование надежности» и «тестирование безопасности».
тестирование». Другой способ взглянуть на проблему — по жизненному циклу: «тестирование требований»,
«проектное тестирование», «приемочное тестирование» и «эксплуатационное тестирование». Еще один вид
определяется рамками тестируемой системы. В этом случае можно говорить о «модульном тестировании».
«тестирование компонентов», «тестирование интеграции» и «тестирование системы».
тоже никак не стандартизированы, а так "техническое тестирование" и "регрессия
тестирование» можно услышать взаимозаменяемо. Кроме того, эти термины часто используются неправильно.
Существует также ряд различных философских подходов к тестированию программного обеспечения. За
Например, некоторые организации выступают за то, чтобы писать тестовые программы до фактического внедрения.
желаемое программное обеспечение, что приводит к «разработке через тестирование». Некоторые организации выступают за
тестирование с точки зрения клиента как можно скорее, проводя параллель с
гибкий процесс разработки: «тестируйте рано и тестируйте часто». Иногда это называют
«гибкое тестирование». Кажется, что существует по крайней мере один подход к тестированию для каждого
методология разработки.
" нс-3 проект не занимается защитой какого-либо из этих процессов, но
проект в целом имеет требования, которые помогают информировать процесс тестирования.
Как и все основные программные продукты, нс-3 имеет ряд качеств, которые должны присутствовать для
продукт, чтобы добиться успеха. С точки зрения тестирования, некоторые из этих качеств, которые должны быть
адресовано, что нс-3 должен быть «правильным», «надежным», «эффективным» и
''обслуживаемый''. В идеале должны быть показатели для каждого из этих параметров, которые
проверяется тестами, чтобы определить, когда продукт не соответствует ожиданиям /
запросам наших потенциальных клиентов.
правильность
Основной целью тестирования является определение того, что часть программного обеспечения ведет себя
''правильно''. нс-3 это означает, что если мы что-то симулируем, симуляция должна
точно представлять некоторый физический объект или процесс с заданной точностью и
точность.
Оказывается, есть две точки зрения, с которых можно рассматривать правильность.
Проверка того, что конкретная модель реализована в соответствии с ее спецификацией,
обычно называется проверка. Процесс принятия решения о том, что модель верна для
его предполагаемое использование обычно называется Проверка.
Проверка и Проверка
Компьютерная модель — это математическое или логическое представление чего-либо. Оно может
изображают транспортное средство, слона (см. Давид Харел говорить в отношении моделирование an слон at
SIMUИнструменты 2009или сетевой карты. Модели также могут представлять такие процессы, как глобальные
потепление, транспортный поток на автостраде или спецификация сетевого протокола. Модели могут быть
полностью точные представления спецификации логического процесса, но они
обязательно никогда не сможет полностью имитировать физический объект или процесс. В большинстве случаев
в модель внесен ряд упрощений, чтобы сделать моделирование вычислительным
сговорчивый.
Каждая модель имеет цель система что он пытается имитировать. Первый шаг в
создание имитационной модели заключается в определении этой целевой системы и уровня детализации и
точность, которую необходимо воспроизвести при моделировании. В случае логического процесса
целевая система может быть идентифицирована как «TCP, как определено в RFC 793». В этом случае она
вероятно, будет желательно создать модель, полностью и точно воспроизводящую RFC.
793. В случае физического процесса это будет невозможно. Если, например, вы
хотите имитировать беспроводную сетевую карту, вы можете определить, что вам нужно, "
точная реализация спецификации 802.11 на уровне MAC и [...] не очень медленный
Модель уровня PHY спецификации 802.11a.''
Как только это будет сделано, можно разработать абстрактную модель целевой системы. Это
как правило, упражнение в управлении компромиссами между сложностью, требованиями к ресурсам
и точность. Процесс создания абстрактной модели называется модель
квалификация в литературе. В случае протокола TCP этот процесс приводит к
дизайн для набора объектов, взаимодействий и поведений, которые будут полностью реализовывать
RFC 793 в нс-3. В случае с беспроводной картой этот процесс приводит к ряду
компромиссы, позволяющие моделировать физический уровень и дизайн сетевого устройства
и канал для ns-3 вместе с желаемыми объектами, взаимодействиями и поведением.
Затем эта абстрактная модель превращается в нс-3 модель, реализующая абстрактный
Модель как компьютерная программа. Процесс согласования реализации с
абстрактная модель называется модель проверка в литературе.
Процесс пока открытый. Остается определить, что данный ns-3
модель имеет какое-то отношение к некоторой реальности — что модель является точным представлением
реальная система, будь то логический процесс или физический объект.
Если кто-то собирается использовать имитационную модель, чтобы попытаться предсказать, как работает некоторая реальная система,
вести себя, должна быть какая-то причина верить вашим результатам, т. е. можно ли доверять тому, что
вывод, сделанный на основе модели, преобразуется в правильный прогноз для реальной системы.
Процесс согласования поведения модели ns-3 с желаемой целевой системой.
поведение, определенное процессом квалификации модели, называется модель Проверка в
литература. В случае реализации TCP вы можете сравнить поведение
вашу модель TCP ns-3 в какую-либо эталонную реализацию, чтобы проверить вашу модель. В
В случае имитации физического уровня беспроводной сети вы можете сравнить поведение
ваша модель к модели реального оборудования в контролируемых условиях,
" нс-3 Среда тестирования предоставляет инструменты, позволяющие как проверять модель, так и
тестирования и поощряет публикацию результатов проверки.
прочность
Надежность – это способность противостоять нагрузкам или изменениям окружающей среды,
входные данные или расчеты и т. д. Система или проект являются «надежными», если они могут справляться с такими
изменения с минимальной потерей функциональности.
Этот вид тестирования обычно проводится с определенной целью. Например, система как
целое может быть запущено на многих различных конфигурациях системы, чтобы продемонстрировать, что оно может
корректно работать в большом количестве сред.
Систему также можно подвергнуть нагрузке, если она будет работать на пределе своих возможностей, генерируя
или моделирование исчерпания ресурсов различных видов. Этот вид тестирования называется
''Стресс-тестирование.''
Система и ее компоненты могут подвергаться так называемым «чистым тестам», которые демонстрируют
положительный результат, то есть система работает правильно в ответ на большое
изменение ожидаемых конфигураций.
Система и ее компоненты также могут подвергаться «грязным тестам», которые предоставляют входные данные.
вне ожидаемого диапазона. Например, если модуль ожидает строку с завершающим нулем
представление целого числа, грязный тест может предоставить непрерывную строку случайных
символов, чтобы убедиться, что система не выйдет из строя в результате этого неожиданного ввода.
К сожалению, обнаружение таких «грязных» входных данных и принятие превентивных мер для обеспечения
система не выходит из строя катастрофически, может потребовать огромных накладных расходов на разработку.
Чтобы сократить время разработки, на раннем этапе проекта было принято решение
свести к минимуму количество проверок параметров и обработки ошибок в нс-3 кодовая база. За
по этой причине мы не тратим много времени на грязное тестирование — оно просто раскроет
результаты дизайнерского решения, которое, как мы знаем, мы приняли.
Мы хотим продемонстрировать, что нс-3 программное обеспечение работает при определенных условиях. Мы
позаимствуйте пару определений, чтобы немного сузить круг вопросов. То домен of применимость is
набор предписанных условий, для которых модель была протестирована по сравнению с
насколько это возможно, и признаны пригодными для использования. То ассортимент of точность есть
соответствие между компьютеризированной моделью и реальностью в пределах области применимости.
" нс-3 Среда тестирования предоставляет инструменты, позволяющие настроить и запустить тест.
среды в нескольких системах (buildbot) и предоставляет классы для поощрения чистого
тесты для проверки работы системы в ожидаемой «области применимости»
и «диапазон точности».
производительный
Ладно, "исполнитель" - это не совсем английское слово. Однако это очень лаконичный неологизм.
который довольно часто используется для описания того, что мы хотим нс-3 быть: мощным и достаточно быстрым, чтобы
справиться с работой.
Это действительно касается широкого предмета тестирования производительности программного обеспечения. Один из ключевых
что делается, так это сравнивает две системы, чтобы найти, какая из них работает лучше (см.
ориентиры). Это используется для демонстрации того, что, например, нс-3 может выполнять базовый вид
моделирования, по крайней мере, так же быстро, как конкурирующий инструмент, или может использоваться для идентификации частей
система, которая работает плохо.
В нс-3 test framework, мы предоставляем поддержку для определения времени различных видов тестов.
Ремонтопригодность
Программный продукт должен быть ремонтопригодным. Это, опять же, очень широкое утверждение, но
среда тестирования может помочь с задачей. После того, как модель разработана, утверждена и
проверено, мы можем повторно выполнить набор тестов для всей системы, чтобы убедиться
что он остается действительным и проверенным в течение всего срока службы.
Когда функция перестает функционировать должным образом после внесения каких-либо изменений в систему.
интегрированный, он обычно называется регресс. Первоначально термин регресс
относится к изменению, которое вызвало повторное появление ранее исправленной ошибки, но термин
разработан для описания любых изменений, которые нарушают существующую функциональность. Есть много
виды регрессий, которые могут иметь место на практике.
A локальным регресс это тот, в котором изменение влияет непосредственно на измененный компонент. За
например, если компонент изменен для выделения и освобождения памяти, но устаревшие указатели
используется, сам компонент выходит из строя.
A удаленные регресс это тот, в котором изменение одного компонента нарушает функциональность в
другой компонент. Это отражает нарушение подразумеваемого, но, возможно, непризнанного
договор между компонентами.
An разоблаченный регресс это тот, который создает ситуацию, когда ранее существовавшая ошибка
который не оказал никакого влияния, внезапно подвергается воздействию в системе. Это может быть так же просто, как упражнение
путь кода в первый раз.
A производительность регресс это тот, который приводит к тому, что требования к производительности системы
быть нарушена. Например, выполнение некоторой работы в низкоуровневой функции, которая может повторяться.
большое количество раз может внезапно сделать систему непригодной для использования с определенных точек зрения.
" нс-3 среда тестирования предоставляет инструменты для автоматизации процесса, используемого для проверки и
проверяйте код в ночных наборах тестов, чтобы быстро выявить возможные регрессии.
Тестирование рамки
ns-3 состоит из ядра симулятора, набора моделей, примеров программ и тестов.
Со временем новые участники вносят модели, тесты и примеры. Тестовая программа Python
test.py выступает в роли менеджера выполнения тестов; test.py может запускать тестовый код и примеры для
искать регрессии, может выводить результаты в несколько форм и может управлять кодом
инструменты анализа покрытия. Сверху наносим слой Билдботы это автоматизированная сборка
роботы, которые выполняют тестирование надежности, запуская тестовую среду в разных системах
и с различными вариантами конфигурации.
Билдботы
На высшем уровне тестирования ns-3 находятся билдботы (build robots). Если ты
незнаком с этой системой, посмотрите на http://djmitche.github.com/buildbot/docs/0.7.11/.
Это автоматизированная система с открытым исходным кодом, которая позволяет нс-3 перестраиваться и тестироваться каждый
время что-то изменилось. Запустив билдботы на нескольких разных системах, мы
может гарантировать, что нс-3 корректно строится и выполняется на всех поддерживаемых им системах.
Пользователи (и разработчики) обычно не взаимодействуют с системой buildbot, кроме как для
прочитайте его сообщения о результатах теста. Если обнаружена неисправность в одном из
автоматические задания сборки и тестирования, строительный бот отправит электронное письмо на нс-разработчики
список рассылки. Это письмо будет выглядеть примерно так
В URL-адресе с полной информацией, показанном в электронном письме, можно выполнить поиск по ключевому слову не удалось и
выберите STDIO ссылку на соответствующий шаг, чтобы увидеть причину сбоя.
Билдбот спокойно сделает свою работу, если ошибок нет, а система подвергнется
создавать и тестировать циклы каждый день, чтобы убедиться, что все в порядке.
Тест.py
Билдботы используют программу Python, test.py, который отвечает за запуск всех
тесты и сбор итоговых отчетов в человекочитаемый вид. Эта программа
также доступны для использования пользователями и разработчиками.
test.py является очень гибким, позволяя пользователю указать количество и тип тестов для
бегать; а также количество и вид продукции для создания.
Перед запуском test.py, убедитесь, что примеры и тесты ns3 созданы, выполнив
следующие
$ ./waf настроить --enable-examples --enable-tests
$ ./ваф
По умолчанию test.py прогонит все доступные тесты и сообщит о состоянии в очень сжатой форме.
форма. Выполнение команды
$ ./test.py
приведет к ряду ПАСС, FAIL, CRASH or ПРОПУСКАТЬ указания, за которыми следует вид
запущенный тест и его отображаемое имя.
Waf: Вход в каталог `/home/craigdo/repos/ns-3-allinone-test/ns-3-dev/build'
Waf: Выход из каталога `/home/craigdo/repos/ns-3-allinone-test/ns-3-dev/build'
'build' успешно завершена (0.939 с)
ОШИБКА: TestSuite ns3-wifi-распространение-потери-модели
PASS: служба имен объектов TestSuite
ПРОЙДИТЕ: TestSuite pcap-файл-объект
ПРОШЕЛ: TestSuite ns3-tcp-cwnd
...
ПРОЙДЕНО: TestSuite ns3-tcp-interoperability
PASS: пример csma-трансляции
PASS: пример csma-multicast
Этот режим предназначен для использования пользователями, которые хотят определить,
дистрибутив работает правильно, и разработчиками, которые заинтересованы в
внесенные ими изменения вызвали какие-либо регрессии.
Существует несколько вариантов управления поведением test.py. если ты побежишь
test.py --Помогите вы должны увидеть сводку команды, например:
Использование: test.py [параметры]
Опции:
-h, --help показать это справочное сообщение и выйти
-b ПУТЬ ПОСТРОЙКИ, --buildpath=ПУТЬ ПОСТРОЙКИ
указать путь, по которому был собран ns-3 (по умолчанию
каталог сборки для текущего варианта)
-c ВИД, --constrain=ВИД
ограничивать бегуна теста типом теста
-e ПРИМЕР, --example=ПРИМЕР
указать один пример для запуска (относительный путь не указан).
необходимо)
-g, --grind запустить наборы тестов и примеры, используя valgrind
-k, --kinds вывести доступные типы тестов
-l, --list вывести список известных тестов
-m, --multiple сообщать о множественных сбоях тестовых наборов и
случаев
-n, --nowaf не запускать waf до начала тестирования
-p ПРИМЕР, --pyexample=ПРИМЕР
указать один пример Python для запуска (с относительным
путь)
-r, --retain сохранить все временные файлы (которые обычно
удалено)
-s ТЕСТ-КОМПЛЕКТ, --suite=ТЕСТ-КОМПЛЕКТ
указать один набор тестов для запуска
-t ТЕКСТОВЫЙ ФАЙЛ, --text=ТЕКСТ-ФАЙЛ
записать подробные результаты тестирования в TEXT-FILE.txt
-v, --verbose печатать ход выполнения и информационные сообщения
-w HTML-ФАЙЛ, --web=HTML-ФАЙЛ, --html=HTML-ФАЙЛ
записать подробные результаты теста в HTML-FILE.html
-x XML-ФАЙЛ, --xml=XML-ФАЙЛ
записать подробные результаты теста в XML-FILE.xml
Если указать необязательный стиль вывода, можно создать подробные описания
тесты и статус. Доступные стили текст и HTML. Билдботы выберут HTML
возможность генерировать отчеты о тестировании HTML для ночных сборок с использованием
$ ./test.py --html=nightly.html
В этом случае HTML-файл с именем nightly.html будет создан с красивым резюме.
проведенного тестирования. Для пользователей, заинтересованных в
$ ./test.py --text=results.txt
В приведенном выше примере набор тестов, проверяющий нс-3 потеря распространения беспроводного устройства
модели провалились. По умолчанию дополнительная информация не предоставляется.
Для дальнейшего изучения отказа, test.py позволяет указать один набор тестов.
Запуск команды
$ ./test.py --suite=ns3-wifi-propagation-loss-models
или эквивалентно
$ ./test.py -s ns3-wifi-propagation-loss-models
приводит к запуску этого единственного набора тестов.
ОШИБКА: TestSuite ns3-wifi-распространение-потери-модели
Чтобы найти подробную информацию о сбое, необходимо указать тип вывода
желанный. Например, большинству людей наверняка будет интересен текстовый файл:
$ ./test.py --suite=ns3-wifi-propagation-loss-models --text=results.txt
Это приведет к тому, что одиночный набор тестов будет запущен со статусом теста, записанным в
файл ''results.txt''.
Вы должны найти что-то похожее на следующее в этом файле
FAIL: Test Suite ''ns3-wifi-propagation-loss-models'' (реальный 0.02 пользователь 0.01 система 0.00)
ПРОЙДЕН: Тестовый кейс "Проверить... Friis... модель..." (реальный 0.01 пользователь 0.00 система 0.00)
НЕУДАЧА: контрольный пример "Проверить... Log Distance... модель" (реальный 0.01 пользователь 0.01 система 0.00)
Детали:
Сообщение: получено неожиданное значение SNR
Условие: [длинное описание того, что на самом деле не удалось]
Фактический: 176.395 XNUMX
Лимит: 176.407 +- 0.0005
Файл: ../src/test/ns3wifi/propagation-loss-models-test-suite.cc
Линия: 360
Обратите внимание, что Test Suite состоит из двух Test Cases. Первый тестовый пример проверил
Модель потерь при распространении Friis и прошла. Во втором тестовом случае не удалось проверить журнал
Модель распространения на расстояние. В этом случае было найдено отношение сигнал-шум 176.395, и тест
ожидаемое значение 176.407 с точностью до трех знаков после запятой. Файл, который реализовал
указан неудачный тест, а также строка кода, вызвавшая сбой.
При желании вы могли бы так же легко написать HTML-файл, используя --html вариант
как описано выше.
Обычно пользователь запускает все тесты хотя бы один раз после загрузки. нс-3 для обеспечения того, чтобы
его или ее среда была построена правильно и дает правильные результаты
судя по наборам тестов. Разработчики обычно запускают наборы тестов до и
после внесения изменений, чтобы убедиться, что они не ввели регрессию с их
изменения. В этом случае разработчики могут захотеть запускать не все тесты, а только их подмножество. За
Например, разработчик может захотеть лишь периодически запускать модульные тесты при создании
изменения в репозиторий. В таком случае, test.py можно сказать, чтобы ограничить типы
тесты, выполняемые для определенного класса тестов. Следующая команда приведет только к
выполняемые модульные тесты:
$ ./test.py --constrain=единица измерения
Точно так же следующая команда приведет к запуску только примеров дымовых тестов:
$ ./test.py --constrain=единица измерения
Чтобы увидеть краткий список допустимых видов ограничений, вы можете попросить их указать.
Следующая команда
$ ./test.py --виды
приведет к отображению следующего списка:
Waf: Вход в каталог `/home/craigdo/repos/ns-3-allinone-test/ns-3-dev/build'
Waf: Выход из каталога `/home/craigdo/repos/ns-3-allinone-test/ns-3-dev/build'
«сборка» завершена успешно (0.939 с) Waf: Вход в каталог «/home/craigdo/repos/ns-3-allinone-test/ns-3-dev/build»
bvt: тесты проверки сборки (чтобы убедиться, что сборка завершена успешно)
core: запустить все тесты на основе TestSuite (исключая примеры)
пример: Примеры (чтобы увидеть, успешно ли работают примеры программ)
производительность: тесты производительности (проверьте, работает ли система так быстро, как ожидалось)
система: Системные тесты (объединяет модули для проверки интеграции модулей)
unit: модульные тесты (внутри модулей для проверки базовой функциональности)
Любой из этих видов теста может быть предоставлен в качестве ограничения с использованием - ограничение опцию.
Чтобы увидеть краткий список всех доступных наборов тестов, вы можете попросить их
перечислено. Следующая команда,
$ ./test.py --список
приведет к отображению списка наборов тестов, похожего на
Waf: Вход в каталог `/home/craigdo/repos/ns-3-allinone-test/ns-3-dev/build'
Waf: Выход из каталога `/home/craigdo/repos/ns-3-allinone-test/ns-3-dev/build'
'build' успешно завершена (0.939 с)
Гистограмма
ns3-wifi-помехи
ns3-tcp-cwnd
ns3-tcp-совместимость
образец
устройства-сетка-пламя
устройства-сетка-dot11s
устройства-сетка
...
служба имени объекта
Перезвони
Атрибуты
конфиг
глобальное значение
командной строки
основное случайное число
объект
Любой из этих перечисленных наборов можно выбрать для самостоятельного запуска с помощью - люкс вариант как
показано выше.
Как и в случае с наборами тестов, можно запустить один пример программы на C++, используя --пример
вариант. Обратите внимание, что относительный путь для примера указывать не обязательно.
исполняемые файлы, созданные для примеров C++, не имеют расширений. Вход
$ ./test.py --example=udp-эхо
приводит к запуску этого единственного примера.
PASS: примеры примеров/udp/udp-echo
Вы можете указать каталог, в котором был собран ns-3, используя --buildpath вариант как
следующим образом.
$ ./test.py --buildpath=/home/craigdo/repos/ns-3-allinone-test/ns-3-dev/build/debug --example=wifi-simple-adhoc
Можно запустить один пример программы Python, используя --pyпример вариант. Обратите внимание, что
относительный путь для примера должен быть включен, и что примеры Python нуждаются в своих
расширения. Вход
$ ./test.py --pyexample=examples/tutorial/first.py
приводит к запуску этого единственного примера.
ПРОЙДИТЕ: Примеры примеров/tutorial/first.py
Поскольку примеры Python не создаются, вам не нужно указывать каталог, в котором находится ns-3.
был построен, чтобы управлять ими.
Обычно, когда программы-примеры выполняются, они записывают большое количество данных файла трассировки.
Обычно он сохраняется в базовом каталоге дистрибутива (например,
/home/пользователь/ns-3-dev). Когда test.py запускает пример, это действительно совершенно безразлично
с файлами трассировки. Он просто хочет определить, можно ли построить и запустить пример.
без ошибки. Поскольку это так, файлы трассировки записываются в
/tmp/непроверенные следы каталог. Если вы запустите приведенный выше пример, вы сможете найти
связанный udp-echo.tr и udp-эхо-n-1.pcap файлы там.
Список доступных примеров определяется содержимым каталога «examples» в
распространение. Если выбрать пример для выполнения с помощью --пример вариант,
test.py не будет предпринимать никаких попыток решить, сконфигурирован пример или нет, он
просто попытается запустить его и сообщит о результате попытки.
После появления test.py работает, по умолчанию он сначала гарантирует, что система была полностью
построен. Это можно победить, выбрав --nowaf опцию.
$ ./test.py --list --nowaf
приведет к отображению списка созданных в настоящее время наборов тестов, аналогичному:
ns3-wifi-модели потерь распространения
ns3-tcp-cwnd
ns3-tcp-совместимость
pcap-файл-объект
служба имени объекта
генераторы случайных чисел
Обратите внимание на отсутствие Waf строить сообщения.
test.py также поддерживает запуск наборов тестов и примеров под valgrind. Вальгринд — это
гибкая программа для отладки и профилирования исполняемых файлов Linux. По умолчанию valgrind запускается
инструмент под названием memcheck, который выполняет ряд функций проверки памяти, включая
обнаружение обращений к неинициализированной памяти, неправильного использования выделенной памяти (двойное освобождение,
доступ после освобождения и т. д.) и обнаружение утечек памяти. Это можно выбрать с помощью
--молоть опцию.
$ ./test.py --шлифовать
Пока он работает, test.py и программы, которые он запускает косвенно, генерируют большое количество
временные файлы. Обычно содержимое этих файлов не представляет интереса, однако в некоторых
случаях может быть полезно (в целях отладки) просмотреть эти файлы. test.py обеспечивает
--удерживать вариант, который заставит эти временные файлы быть сохраненными после запуска
завершенный. Файлы сохраняются в каталоге с именем testpy-выход в подкаталоге
назван в соответствии с текущим универсальным координированным временем (также известным как среднее время по Гринвичу).
Время).
$ ./test.py --сохранить
Наконец, test.py обеспечивает --подробный вариант, который будет печатать большие объемы информации
о его продвижении. Не ожидается, что это будет ужасно полезно, если нет
ошибка. В этом случае вы можете получить доступ к стандартному выводу и стандартной ошибке
сообщается путем запуска наборов тестов и примеров. Выберите подробный следующим образом:
$ ./test.py --подробный
Все эти варианты можно смешивать и сочетать. Например, для запуска всего ядра ns-3
наборы тестов под valgrind, в подробном режиме, при создании выходного файла HTML один
сделал бы:
$ ./test.py --verbose --grind --constrain=core --html=results.html
ТестТаксономия
Как упоминалось выше, тесты сгруппированы в ряд широко определенных классификаций.
разрешить пользователям выборочно запускать тесты для различных видов тестирования, которые необходимы
быть сделано.
· Проверочные тесты сборки
· Модульные тесты
· Системные тесты
· Примеры
· Тесты производительности
Тесты проверки сборки
Это относительно простые тесты, которые строятся вместе с дистрибутивом и используются
чтобы убедиться, что сборка в значительной степени работает. Наши текущие модульные тесты находятся в
исходные файлы кода, который они тестируют и встраиваются в модули ns-3; и так подходит
описание БВЦ. BVT живут в том же исходном коде, который встроен в код ns-3.
Наши текущие тесты являются примерами такого рода тестов.
Ед. Tests
Модульные тесты — это более сложные тесты, которые подробно изучают, чтобы убедиться, что часть кода
работает, как рекламируется в изоляции. На самом деле нет причин для такого рода испытаний
встроен в модуль ns-3. Выходит, например, что юнит-тесты для объекта
службы имен примерно того же размера, что и код службы имен объектов. Модульные тесты
это тесты, которые проверяют один бит функциональности, не встроенной в код ns-3,
но жить в том же каталоге, что и код, который он тестирует. Возможно, эти тесты
также проверьте интеграцию нескольких файлов реализации в модуль. Файл
src/core/test/names-test-suite.cc — пример такого теста. Файл
src/network/test/pcap-file-test-suite.cc — еще один пример, в котором используется заведомо исправный pcap.
файл как тестовый векторный файл. Этот файл хранится локально в каталоге src/network.
Система Tests
Системные тесты — это те, которые включают более одного модуля в системе. У нас много
такого рода тесты выполняются в нашей текущей структуре регрессии, но они, как правило,
перегруженные примеры. Мы предоставляем новое место для такого рода испытаний в каталоге
src / test. Файл src/test/ns3tcp/ns3-interop-test-suite.cc является примером такого рода.
теста. Он использует NSC TCP для тестирования реализации ns-3 TCP. Часто будет тест
векторы, необходимые для этого вида теста, и они хранятся в каталоге, где
испытать жизнь. Например, ns3tcp-interop-response-vectors.pcap — это файл, состоящий из
количество заголовков TCP, которые используются в качестве ожидаемых ответов тестируемого TCP ns-3
к стимулу, генерируемому NSC TCP, который используется в качестве «заведомо исправной» реализации.
Примеры
Примеры тестируются фреймворком, чтобы убедиться, что они построены и будут работать. Ничего
проверено, и в настоящее время файлы pcap просто списаны в / Tmp быть отброшенным. Если
примеры работают (не падают), они проходят этот дымовой тест.
эффективности Tests
Тесты производительности — это тесты, которые проверяют определенную часть системы и определяют
если тесты были завершены в разумные сроки.
Бег Tests
Тесты обычно запускаются с использованием высокого уровня test.py программа. Чтобы получить список
доступные параметры командной строки, запустите test.py --Помогите
Программа испытаний test.py запустит как тесты, так и те примеры, которые были добавлены в
список для проверки. Отличие тестов от примеров заключается в следующем. Тесты
обычно проверяют, соответствуют ли конкретные выходные данные или события моделирования ожидаемому поведению.
Напротив, вывод примеров не проверяется, а тестовая программа просто проверяет
выход из примера программы, чтобы убедиться, что она работает без ошибок.
Вкратце, чтобы запустить все тесты, сначала нужно настроить тесты на этапе конфигурации, а затем
также (необязательно) примеры, если примеры должны быть проверены:
$ ./waf --configure --enable-examples --enable-тесты
Затем соберите ns-3, а после сборки просто запустите test.py. test.py -h покажет число
параметров конфигурации, которые изменяют поведение test.py.
Программа test.py вызывает для тестов и примеров C++ программу нижнего уровня C++, называемую
испытатель для фактического запуска тестов. Как обсуждается ниже, это испытатель может быть
полезный способ отладки тестов.
Отладка Tests
Отладку тестовых программ лучше всего выполнять с помощью низкоуровневой программы запуска тестов.
программа. Тест-раннер — это мост от общего кода Python к нс-3 код. это
написан на C++ и использует процесс автоматического обнаружения тестов в нс-3 код, чтобы найти и
разрешить выполнение всех различных тестов.
Основная причина, почему test.py не подходит для отладки в том, что он не разрешен для
ведение журнала можно включить с помощью НС_ЛОГ переменная окружения при запуске test.py. Этот
ограничение не распространяется на исполняемый файл test-runner. Следовательно, если вы хотите увидеть ведение журнала
вывод из ваших тестов, вы должны запускать их напрямую с помощью средства запуска тестов.
Чтобы запустить test-runner, вы запускаете его, как и любой другой исполняемый файл ns-3, используя
WAF. Чтобы получить список доступных опций, вы можете ввести:
$ ./waf --run "test-runner --help"
Вы должны увидеть что-то вроде следующего
Waf: Вход в каталог `/home/craigdo/repos/ns-3-allinone-test/ns-3-dev/build'
Waf: Выход из каталога `/home/craigdo/repos/ns-3-allinone-test/ns-3-dev/build'
'build' успешно завершена (0.353 с)
--assert: Сообщить тестам о segfault (например, assert) при обнаружении ошибки
--basedir=dir: установить базовый каталог (где найти src) в ''dir''
--tempdir=dir: установить временный каталог (где найти файлы данных) в ''dir''
--constrain=test-type: Ограничить проверки наборами тестов типа ''test-type''
--help: распечатать это сообщение
--kinds: перечислить все доступные виды тестов
--list: перечислить все наборы тестов (необязательно ограниченные типом теста)
--out=имя-файла: установить для выходного файла состояния теста значение ''имя-файла''
--suite=suite-name: запустить набор тестов с именем ''suite-name''
--verbose: включить сообщения в наборах тестов запуска
Вам доступен ряд вещей, которые будут вам знакомы, если у вас есть
посмотрела на test.py. Этого следовало ожидать, так как средство запуска тестов — это всего лишь интерфейс.
между test.py и нс-3. Вы можете заметить, что здесь отсутствуют команды, относящиеся к примерам.
Это потому, что примеры действительно не нс-3 тесты. test.py управляет ими, как если бы они были
представить единую среду тестирования, но они действительно совершенно разные и не
быть найденным здесь.
Первая новая опция, которая появляется здесь, но не в test.py, — это --утверждать вариант. Этот
опция полезна при отладке тестового примера при запуске под отладчиком, например GDB. Когда
выбран, эта опция сообщает основному тестовому сценарию, что он вызовет нарушение сегментации, если
обнаружена ошибка. У этого есть приятный побочный эффект, вызывающий остановку выполнения программы.
(взломать отладчик) при обнаружении ошибки. Если вы используете gdb, вы можете использовать
этот вариант что-то вроде,
$ ./ваф оболочка
$ cd сборка/отладка/утилиты
$ gdb тестовый запуск
$ запустить --suite=глобальное значение --assert
Если затем в наборе тестов глобального значения будет обнаружена ошибка, будет сгенерирован segfault.
и отладчик (уровня исходного кода) остановится на NS_TEST_ASSERT_MSG который обнаружил
ошибка.
Еще одна новая опция, которая появляется здесь, это --basinir вариант. Оказывается, некоторые
тестам может потребоваться ссылка на исходный каталог нс-3 дистрибутив, чтобы найти местный
data, поэтому для запуска теста всегда требуется базовый каталог.
Если вы запустите тест из test.py, программа Python предоставит параметр baseir для
ты. Чтобы запустить один из тестов непосредственно из бегуна тестов, используя WAF, вам нужно будет
укажите набор тестов для запуска вместе с базовым каталогом. Таким образом, вы можете использовать оболочку
и делать:
$ ./waf --run "test-runner --basedir=`pwd` --suite=pcap-file-object"
Обратите внимание на «обратные» кавычки в PWD команда.
Если вы запускаете набор тестов из отладчика, вспоминать об этом может быть довольно болезненно.
и постоянно вводите абсолютный путь к базовому каталогу дистрибутива. Потому что
это, если вы опустите baseir, тестовый бегун попытается вычислить его для вас. Это
начинается в текущем рабочем каталоге и проходит вверх по дереву каталогов в поисках
файл каталога с файлами с именем Версия и ЛИЦЕНЗИЯ. Если он находит его, он предполагает, что
должен быть baseir и предоставляет его для вас.
Тест выходной
Многие наборы тестов требуют записи временных файлов (например, файлов pcap) в процессе работы.
запускаем тесты. Затем тестам требуется временный каталог для записи. Питон
тестовая утилита (test.py) автоматически предоставит временный файл, но при автономном запуске
этот временный каталог должен быть предоставлен. Так же, как и в случае с базисом, это может быть
раздражает необходимость постоянно предоставлять --tempdir, так что бегун теста поймет один
для вас, если вы не предоставите один. Сначала он ищет переменные среды с именем TMP
и TEMP и использует их. Если ни TMP ни TEMP определены, он выбирает / Tmp, Код
затем добавляет идентификатор, указывающий, что создал каталог (ns-3), затем время
(чч.мм.сс), за которым следует большое случайное число. Средство запуска тестов создает каталог этого
имя, которое будет использоваться в качестве временного каталога. Затем временные файлы помещаются в каталог, который
будет называться как-то так
/tmp/ns-3.10.25.37.61537845
Время указано в качестве подсказки, чтобы вы могли относительно легко восстановить то, что
каталог был использован, если вам нужно вернуться и просмотреть файлы, которые были помещены в этот
каталог.
Другой класс выходных данных — это тестовые выходные данные, такие как трассировки pcap, которые генерируются для сравнения с
справочный вывод. Тестовая программа обычно удаляет их после того, как все наборы тестов
бегать. Чтобы отключить удаление тестового вывода, запустите test.py с опцией «сохранить»:
$ ./test.py -r
и результаты теста можно найти в testpy-выход/ каталог.
Отчетность of тестXNUMX сбои
Когда вы запускаете набор тестов с помощью средства запуска тестов, по умолчанию он запускает тест тихо.
Единственным признаком того, что вы получите, что тест пройден, является отсутствие сообщения
от WAF говоря, что программа вернула что-то отличное от нулевого кода выхода. Получить
некоторый вывод из теста, вам нужно указать выходной файл, в который тесты будут
записать свой XML-статус, используя --из вариант. Вы должны быть осторожны в интерпретации
результаты, потому что наборы тестов будут добавлять результаты в этот файл. Пытаться,
$ ./waf --run "test-runner --basedir=`pwd` --suite=pcap-file-object --out=myfile.xml"
Если вы посмотрите файл мой файл.xml вы должны увидеть что-то вроде
pcap-файл-объект
Убедитесь, что PcapFile::Open с режимом ''w'' работает
ПРОХОДЯТ
реальный 0.00 пользовательский 0.00 системный 0.00
Убедитесь, что PcapFile::Open с режимом ''r'' работает
ПРОХОДЯТ
реальный 0.00 пользовательский 0.00 системный 0.00
Убедитесь, что PcapFile::Open с режимом ''a'' работает
ПРОХОДЯТ
реальный 0.00 пользовательский 0.00 системный 0.00
Убедитесь, что PcapFileHeader управляется правильно.
ПРОХОДЯТ
реальный 0.00 пользовательский 0.00 системный 0.00
Убедитесь, что PcapRecordHeader управляется правильно.
ПРОХОДЯТ
реальный 0.00 пользовательский 0.00 системный 0.00
Убедитесь, что PcapFile может считывать заведомо исправный файл pcap.
ПРОХОДЯТ
реальный 0.00 пользовательский 0.00 системный 0.00
ПРОХОДЯТ
реальный 0.00 пользовательский 0.00 системный 0.00
Если вы знакомы с XML, это должно быть достаточно понятно. Это также не
полный XML-файл, поскольку наборы тестов разработаны таким образом, чтобы их выходные данные добавлялись к основному
XML-файл состояния, как описано в test.py .
Отладка тестXNUMX suite сбои
Для отладки тестовых сбоев, таких как
АВАРИЙНЫЙ СБОЙ: TestSuite ns3-wifi-интерференция
Вы можете получить доступ к базовой программе запуска тестов через gdb следующим образом, а затем передать
Аргумент "--basedir=`pwd`" для запуска (вы также можете передать другие аргументы по мере необходимости, но
baseir — необходимый минимум):
$ ./waf --command-template="gdb %s" --run "исполнитель тестов"
Waf: Вход в каталог `/home/tomh/hg/sep09/ns-3-allinone/ns-3-dev-678/build'
Waf: Выход из каталога `/home/tomh/hg/sep09/ns-3-allinone/ns-3-dev-678/build'
'build' успешно завершена (0.380 с)
GNU gdb 6.8-дебиан
Авторское право (C) 2008 Free Software Foundation, Inc.
L cense GPLv3+: GNU GPL версии 3 или вышеhttp://gnu.org/licenses/gpl.html>
Это бесплатное программное обеспечение: вы можете изменять и распространять его.
НИКАКИХ ГАРАНТИЙ, насколько это разрешено законом. Введите "показать копирование"
и "показать гарантию" для подробностей.
Этот GDB был сконфигурирован как "x86_64-linux-gnu"...
(gdb) r --basedir=`pwd`
Запуск программы: <..>/build/debug/utils/test-runner --basedir=`pwd`
[Отладка потоков с использованием libthread_db включена]
утверждать не удалось. file=../src/core/model/type-id.cc, line=138, cond="uid <= m_information.size () && uid != 0"
...
Вот еще один пример того, как использовать valgrind для отладки проблемы с памятью, такой как:
VALGR: устройства TestSuite-mesh-dot11s-регрессия
$ ./waf --command-template="valgrind %s --basedir=`pwd` --suite=devices-mesh-dot11s-regression" --run test-runner
Класс ТестРаннер
Исполняемые файлы, запускающие специальные тестовые программы, используют класс TestRunner. Этот класс
обеспечивает автоматическую регистрацию и листинг тестов, а также способ выполнения
индивидуальные тесты. Отдельные наборы тестов используют глобальные конструкторы C++ для добавления самих себя в
набор наборов тестов, которыми управляет средство запуска тестов. Тестовый бегун используется для перечисления
все доступные тесты и выбрать тест для запуска. Это довольно простой класс
который предоставляет три статических метода для предоставления или добавления и получения наборов тестов в
сборник тестов. См. doxygen для класса ns3::TestRunner для получения информации.
Тест Люкс
Все нс-3 тесты подразделяются на наборы тестов и тестовые наборы. Набор тестов — это
набор тестовых случаев, которые полностью реализуют заданную функциональность. В виде
описанные выше, наборы тестов можно классифицировать как
· Проверочные тесты сборки
· Модульные тесты
· Системные тесты
· Примеры
· Тесты производительности
Эта классификация экспортируется из класса TestSuite. Этот класс довольно простой,
существует только как место для экспорта этого типа и для накопления тестовых случаев. От пользователя
точки зрения, чтобы создать новый TestSuite в системе, нужно только определить новый
класс, который наследуется от класса Тестирование и выполнять эти две обязанности.
Следующий код определяет новый класс, который может быть запущен с помощью test.py как «модульный» тест
с отображаемым именем, имя моего-набора-тестов.
класс MySuite: общедоступный TestSuite
{
общественности:
МойТестСюит ();
};
MyTestSuite::MyTestSuite ()
: TestSuite ("мое-название-набора-тестов", UNIT)
{
AddTestCase (новый MyTestCase);
}
MyTestSuite мойTestSuite;
Базовый класс берет на себя всю регистрацию и отчетность, необходимые для хорошей работы.
гражданин в рамках теста.
Тест Кейсы
Отдельные тесты создаются с использованием класса TestCase. Общие модели использования теста
case включают «один тестовый пример для каждой функции» и «один тестовый пример для каждого метода». Смеси
эти модели можно использовать.
Чтобы создать новый тестовый пример в системе, все, что нужно сделать, это наследоваться от
Прецедент базовый класс, переопределить конструктор, чтобы дать тестовому случаю имя и переопределить
ДоРун способ запуска теста.
класс MyTestCase: общедоступный TestCase
{
Мой тестовый случай ();
виртуальная пустота DoRun (пустота);
};
MyTestCase::MyTestCase ()
: TestCase ("Проверить функциональность")
{
}
аннулировать
MyTestCase::DoRun (недействительно)
{
NS_TEST_ASSERT_MSG_EQ (true, true, "Некоторое сообщение об ошибке");
}
Утилиты
Существует ряд утилит разного рода, которые также являются частью тестирования.
рамки. Примеры включают обобщенный файл pcap, полезный для хранения тестовых векторов; а
общий контейнер, полезный для временного хранения тестовых векторов во время выполнения теста; и
инструменты для создания презентаций на основе результатов валидации и проверочного тестирования.
Эти утилиты здесь не задокументированы, но, например, посмотрите, как тесты TCP
найти в источник/тест/ns3tcp/ используйте файлы pcap и справочный вывод.
Как в записывать тестов
Основная цель проекта ns-3 — помочь пользователям повысить достоверность и
достоверность их результатов. Есть много элементов для получения действительных моделей и
моделирование, и тестирование является основным компонентом. Если вы предоставляете модели или примеры для
ns-3 вас могут попросить предоставить тестовый код. Предоставленные вами модели будут использованы
в течение многих лет другими людьми, которые, вероятно, на первый взгляд не имеют ни малейшего представления о том,
модель правильная. Тестовый код, который вы пишете для своей модели, поможет избежать ошибок в будущем.
регрессий в выводе и поможет будущим пользователям понять проверку и
границы применимости ваших моделей.
Существует много способов проверить правильность реализации модели. В этом
мы надеемся охватить некоторые распространенные случаи, которые можно использовать в качестве руководства по написанию новых
тесты.
Образец Тестирование скелет
При запуске с нуля (т. е. без добавления TestCase в существующий TestSuite) эти
вещи должны быть решены заранее:
· Как будет называться набор тестов
· Какой тип теста это будет (проверочный тест сборки, модульный тест, системный тест или
Тест производительности)
· Где будет жить тестовый код (либо в существующем модуле ns-3, либо отдельно в
каталог src/test/). Вам нужно будет отредактировать файл wscript в этом каталоге, чтобы
скомпилируйте новый код, если это новый файл.
Программа называется источник/создать-module.py является хорошей отправной точкой. Эта программа может быть
вызывается, например создать-module.py маршрутизатор для гипотетического нового модуля под названием маршрутизатор, однажды
вы сделаете это, вы увидите маршрутизатор каталог и тест/маршрутизатор-test-suite.cc тестирование.
Этот файл может стать отправной точкой для вашего начального теста. Это рабочий набор тестов,
хотя фактические проведенные тесты тривиальны. Скопируйте его в тест вашего модуля
каталог и выполните глобальную замену «Маршрутизатор» в этом файле на что-то, относящееся к
к модели, которую вы хотите протестировать. Вы также можете редактировать такие вещи, как более описательный
название тестового случая.
Вам также нужно добавить блок в свой wscript, чтобы этот тест скомпилировался:
модуль_test.source = [
'test/router-test-suite.cc',
]
Прежде чем вы на самом деле начнете делать из этого полезные вещи, попробуйте запустить
скелет. Убедитесь, что для ns-3 настроена опция --enable-tests.
Предположим, что ваш новый набор тестов называется «маршрутизатор», как здесь:
RouterTestSuite:: RouterTestSuite ()
: TestSuite ("маршрутизатор", UNIT)
Попробуйте эту команду:
$ ./test.py -s маршрутизатор
Должен быть получен вывод, подобный приведенному ниже:
ПРОХОД: маршрутизатор TestSuite
Пройдено 1 из 1 тестов (1 пройдено, 0 пропущено, 0 не выполнено, 0 аварийно завершено, 0 ошибок valgrind)
См. src/lte/test/test-lte-antenna.cc для рабочего примера.
Тест Макрос
Существует ряд макросов, доступных для проверки выходных данных тестовой программы с ожидаемыми значениями.
вывод. Эти макросы определены в источник/ядро/модель/test.h.
Основной набор макросов, которые используются, включает следующее:
NS_TEST_ASSERT_MSG_EQ(факт, лимит, сообщение)
NS_TEST_ASSERT_MSG_NE(факт, лимит, сообщение)
NS_TEST_ASSERT_MSG_LT(факт, лимит, сообщение)
NS_TEST_ASSERT_MSG_GT(факт, лимит, сообщение)
NS_TEST_ASSERT_MSG_EQ_TOL(фактический, лимит, пропуск, сообщение)
Первый аргумент фактического соединения это тестируемое значение, второе значение предел ожидаемый
значение (или значение для проверки) и последний аргумент MSG это сообщение об ошибке для
распечатать, если тест не пройден.
Первые четыре макроса выше проверяют на равенство, неравенство, меньше или больше,
соответственно. Пятый макрос выше проверяет равенство, но в пределах определенного допуска.
Этот вариант полезен при проверке чисел с плавающей запятой на равенство с пределом,
где вы хотите избежать сбоя теста из-за ошибок округления.
Наконец, есть варианты вышеприведенного, где ключевое слово УТВЕРЖДАТЬ заменяется на ОЖИДАТЬ.
Эти варианты разработаны специально для использования в методах (особенно обратных вызовах), возвращающих
пустота. Зарезервируйте их использование для обратных вызовов, которые вы используете в своих тестовых программах; в противном случае используйте
УТВЕРЖДАТЬ варианты.
Как в an пример программа в тестXNUMX suite
Можно «дымить тест», чтобы примеры компилировались и успешно выполнялись до завершения (без
утечки памяти) с помощью примеры для запуска.py script, расположенный в тестовом каталоге вашего модуля.
Вкратце, включив экземпляр этого файла в ваш тестовый каталог, вы можете вызвать
средство запуска тестов для выполнения перечисленных примеров. Обычно лучше убедиться, что вы
выберите примеры с достаточно коротким временем выполнения, чтобы не увязнуть в тестах. Видеть
пример в src/lte/тест/ каталог.
Тестирование для логический Результаты
Тестирование Результаты когда хаотичность is вовлеченный
Тестирование выходной данным против которого выступает большинство исследователей в области общественного здравоохранения. a известный распределение
Обеспечение нетривиальный вход векторы of данным
Хранение и привязка нетривиальный выходной данным
Представляя выходной тестXNUMX данным
Поддержка
Создающий a new нс-3 модель
В этой главе рассматривается процесс проектирования нс-3 модель. Во многих исследовательских случаях
пользователи не будут удовлетворены простой адаптацией существующих моделей, но могут захотеть расширить
ядро симулятора по-новому. Мы будем использовать пример добавления ErrorModel в
декриминализовано нс-3 ссылка как мотивирующий пример того, как можно подойти к этой проблеме и
перейти к проектированию и реализации.
ПРИМЕЧАНИЕ:
Документация
Здесь мы сосредоточимся на процессе создания новых моделей и новых модулей, а некоторые из
участие в выборе дизайна. Для ясности мы отложим обсуждение механика
документирования моделей и исходного кода в Документация главы.
Дизайн Подход
Подумайте, как вы хотите, чтобы это работало; что он должен делать. Подумайте об этих вещах:
· функциональность: Какой функционал он должен иметь? Какие атрибуты или конфигурация
выставлены пользователю?
· возможность повторного использования: Насколько другие должны иметь возможность повторно использовать мой дизайн? Могу ли я повторно использовать код из
нс-2 для начала? Как пользователь интегрирует модель с остальными другими
симуляция?
· зависимости: Как я могу уменьшить введение внешних зависимостей в мой новый код
насколько это возможно (чтобы сделать его более модульным)? Например, следует ли мне избегать каких-либо
зависимость от IPv4, если я хочу, чтобы он также использовался IPv6? Должен ли я избегать любой зависимости
по ИП вообще?
Не стесняйтесь обращаться к ns-3-пользователи or нс-разработчики список, если у вас есть вопросы.
В частности, важно подумать об общедоступном API вашей новой модели и запросить
Обратная связь. Это также помогает сообщить другим о вашей работе, если вы заинтересованы в ней.
коллаборационисты.
Пример: Модель ошибки
Модель ошибки существует в нс-2. Он позволяет передавать пакеты объекту с состоянием, который
определяет на основе случайной величины, поврежден ли пакет. Звонящий может
затем решите, что делать с пакетом (отбросить его и т. д.).
Основной API модели ошибок — это функция для передачи пакета, а возвращаемое значение
эта функция является логическим значением, которое сообщает вызывающей стороне, произошло ли какое-либо повреждение. Примечание
что в зависимости от модели ошибки буфер пакетных данных может быть поврежден или не поврежден.
Назовем эту функцию "IsCorrupt()".
На данный момент в нашем проекте мы имеем:
класс ErrorModel
{
общественности:
/ **
* \возвращает true, если пакет считается ошибочным/поврежденным
* \param pkt Пакет, к которому применяется модель ошибок
*/
bool IsCorrupt (Ptr пкт);
};
Обратите внимание, что мы не передаем константный указатель, тем самым позволяя функции изменять
package, если IsCorrupt() возвращает true. Не все модели ошибок фактически изменяют пакет;
следует задокументировать, поврежден ли буфер пакетных данных.
Нам также могут понадобиться специализированные версии этого, например, в нс-2, так что хотя это и не
единственный выбор дизайна для полиморфизма, мы предполагаем, что мы создадим подкласс базового класса
ErrorModel для специализированных классов, таких как RateErrorModel, ListErrorModel и т. д., таких как
сделано в нс-2.
В этот момент вы можете подумать: «Почему бы не сделать IsCorrupt() виртуальным методом?». Это
один подход; другой — сделать публичную невиртуальную функцию косвенной через
частная виртуальная функция (в C++ она известна как идиома невиртуального интерфейса и
принят в нс-3 класс ErrorModel).
Далее, должно ли это устройство иметь какие-либо зависимости от IP или других протоколов? Мы не хотим
для создания зависимостей от интернет-протоколов (модель ошибок должна быть применима к
протоколы, отличные от Интернета), так что мы будем иметь это в виду позже.
Еще одно соображение заключается в том, как объекты будут включать эту модель ошибки. Мы предполагаем поставить
явный установщик в некоторых реализациях NetDevice, например:
/ **
* Прикрепите полученную ErrorModel к PointToPointNetDevice.
*
* PointToPointNetDevice может дополнительно включать ErrorModel в
* цепочка приема пакетов.
*
* @см. ErrorModel
* @param em Ptr для ErrorModel.
*/
void PointToPointNetDevice::SetReceiveErrorModel(Ptr Эм);
Опять же, это не единственный выбор, который у нас есть (модели ошибок могут быть объединены во множество
другие объекты), но он удовлетворяет нашему основному варианту использования, который заключается в том, чтобы позволить пользователю принудительно
ошибки при успешной передаче пакетов на уровне NetDevice.
Немного подумав и посмотрев на существующие нс-2 код, вот пример API базы
класс и первый подкласс, которые могут быть опубликованы для первоначального просмотра:
класс ErrorModel
{
общественности:
Модель ошибки ();
виртуальная модель ~ErrorModel();
bool IsCorrupt (Ptr пкт);
void Сброс (void);
недействительным Включить (пусто);
void Отключить (недействительно);
bool IsEnabled (недействительный) const;
частный:
виртуальный логический DoCorrupt (Ptr пкт) = 0;
виртуальная пустота DoReset (void) = 0;
};
перечисление ErrorUnit
{
ЕС_БИТ,
ЕС_БАЙТЕ,
ЕС_ПКТ
};
// Определяем, какие пакеты содержат ошибки в соответствии с базовым
// Распределение случайных величин, частота ошибок и единица измерения скорости.
класс RateErrorModel: общедоступная ErrorModel
{
общественности:
Модель ОценкиОшибки();
виртуальный ~RateErrorModel ();
перечисление ErrorUnit GetUnit (void) const;
void SetUnit (перечисление ErrorUnit error_unit);
двойной GetRate (void) const;
void SetRate (двойная ставка);
void SetRandomVariable (const RandomVariable &randomVariable);
частный:
виртуальный логический DoCorrupt (Ptr пкт);
виртуальная пустота DoReset (недействительность);
};
строительные леса
Допустим, вы готовы приступить к реализации; у вас есть достаточно четкое представление о
что вы хотите построить, и, возможно, вы запросили первоначальный обзор или предложения от
список. Один из способов приблизиться к следующему шагу (реализации) — это создать каркас и
заполните детали по мере созревания дизайна.
В этом разделе рассматриваются многие шаги, которые вы должны учитывать при определении строительных лесов, или
нефункциональный скелет того, что ваша модель в конечном итоге реализует. Обычно это хорошо
потренируйтесь не ждать, пока эти детали будут интегрированы в конце, а вместо этого отвесить
скелет вашей модели в систему на ранней стадии, а затем добавьте функции позже, как только API и
интеграция кажется правильной.
Обратите внимание, что вы захотите изменить несколько вещей в приведенной ниже презентации для вашей модели.
поскольку, если вы будете следовать модели ошибок дословно, код, который вы создаете, будет сталкиваться с
существующая модель ошибки. Ниже приведено лишь краткое описание того, как была построена модель ErrorModel.
можно адаптировать к другим моделям.
Обзор нс-3 Кодирование Стиль Документ
На этом этапе вы можете сделать паузу и прочитать нс-3 документ стиля кодирования, особенно
если вы планируете внести свой код обратно в проект. Стиль кодирования
документ связан с главной страницы проекта: нс-3 кодирование стиль.
Решение (Decide): где in Источник дерево Модель Должен жить
Все нс-3 исходный код модели находится в каталоге SRC /. Вам нужно будет выбрать, какие
подкаталог, в котором он находится. Если это какой-то новый код модели, имеет смысл поместить его
в SRC / каталог где-нибудь, особенно для простоты интеграции со сборкой
системы.
В случае с моделью ошибок она очень связана с классом пакета, поэтому имеет смысл
реализовать это в источник/сеть/ модуль, где нс-3 пакеты реализованы.
WAF и wскрипт
нс-3 использует Waf система сборки. Вы захотите интегрировать свой новый нс-3 использует ваф
система сборки. Вы захотите интегрировать ваши новые исходные файлы в эту систему. Этот
требует, чтобы вы добавили свои файлы в wскрипт файл, найденный в каждом каталоге.
Начнем с пустых файлов error-model.h и error-model.cc и добавим их в
источник/сеть/wscript. На самом деле это просто вопрос добавления файла .cc к остальным файлам.
исходные файлы и файл .h в список файлов заголовков.
Теперь откройте каталог верхнего уровня и введите «./test.py». Вы не должны были сломаться
что-либо этой операцией.
Включают Охранники
Далее добавим немного включают гвардия в нашем заголовочном файле.:
#ifndef ОШИБКА_MODEL_H
#определить ERROR_MODEL_H
...
#endif
Пространство имен ns3
нс-3 использует нс-3 Пространство имен чтобы изолировать его символы от других пространств имен. Как правило,
затем пользователь поместит нс-3 блок пространства имен в файлах cc и h.:
пространство имен ns3 {
...
}
На данный момент у нас есть несколько файлов скелета, в которых мы можем начать определять наши новые классы.
Заголовочный файл выглядит так:
#ifndef ОШИБКА_MODEL_H
#определить ERROR_MODEL_H
пространство имен ns3 {
} // пространство имен ns3
#endif
в то время как ошибка-model.cc файл просто выглядит так:
#include "error-model.h"
пространство имен ns3 {
} // пространство имен ns3
Эти файлы должны компилироваться, так как в них нет никакого содержимого. Теперь мы готовы
начать добавлять классы.
Начальный Реализация
На данный момент мы все еще работаем над каркасом, но мы можем приступить к определению нашего
классы, функциональность которых будет добавлена позже.
унаследовать от объект Класс?
Это важный этап проектирования; использовать ли класс объект в качестве базового класса для вашего нового
классов.
Как описано в главе о нс-3 Объектная модель, классы, которые наследуются от класса
объект получить специальные свойства:
· В нс-3 система типов и атрибутов (см. Атрибуты)
· Система агрегирования объектов
· Интеллектуальная система подсчета ссылок (класс Ptr)
Классы, производные от класса объектная база} получить первые два свойства выше, но не
получить умные указатели. Классы, производные от класса РефКаунтБасе получить только смарт-указатель
система подсчета ссылок.
На практике класс объект это вариант из трех вышеупомянутых, что нс-3 разработчик будет
чаще всего встречаются.
В нашем случае мы хотим использовать систему атрибутов, и мы будем передавать экземпляры
этого объекта через нс-3 общедоступный API, поэтому класс объект подходит для нас.
Начальный Классы
Один из способов — начать с определения минимальных функций и посмотреть, будут ли они работать.
компилировать. Давайте рассмотрим, что нужно реализовать, когда мы наследуем от класса Object.:
#ifndef ОШИБКА_MODEL_H
#определить ERROR_MODEL_H
#include "ns3 / object.h"
пространство имен ns3 {
класс ErrorModel: общедоступный объект
{
общественности:
статический TypeId GetTypeId (void);
Модель ошибки ();
виртуальная модель ~ErrorModel();
};
класс RateErrorModel: общедоступная ErrorModel
{
общественности:
статический TypeId GetTypeId (void);
Модель ОценкиОшибки();
виртуальный ~RateErrorModel ();
};
#endif
Несколько вещей, на которые следует обратить внимание. Нам нужно включить объект.h. Конвенция в нс-3 это если
файл заголовка находится в том же каталоге, он может быть включен без указания пути
префикс. Следовательно, если бы мы реализовывали ErrorModel в источник/ядро/модель каталог, мы
можно было просто сказать"#включают "объект.ч"". Но мы в источник/сеть/модель, поэтому мы должны
включить его как "#включают "ns3/object.h"". Также обратите внимание, что это выходит за пределы пространства имен
декларация.
Во-вторых, каждый класс должен реализовать статическую общедоступную функцию-член, называемую GetTypeId (пустота).
В-третьих, рекомендуется реализовать конструкторы и деструкторы, а не
компилятор их сгенерирует, а деструктор сделает виртуальным. Обратите внимание, что в C++ копия
оператор присваивания и конструкторы копирования генерируются автоматически, если они не определены, поэтому
если они вам не нужны, вы должны реализовать их как частные члены. Этот аспект
C++ обсуждается в книге Скотта Мейерса «Эффективный C++». пункт 45.
Давайте теперь посмотрим на соответствующий скелетный код реализации в файле .cc:
#include "error-model.h"
пространство имен ns3 {
NS_OBJECT_ENSURE_REGISTERED (модель ошибки);
TypeId ErrorModel::GetTypeId (недействительно)
{
статический TypeId tid = TypeId ("ns3::ErrorModel")
.SetParent ()
;
вернуть tid;
}
ErrorModel::ErrorModel ()
{
}
ErrorModel::~ErrorModel ()
{
}
NS_OBJECT_ENSURE_REGISTERED (RateErrorModel);
TypeId RateErrorModel::GetTypeId (пусто)
{
статический TypeId tid = TypeId ("ns3::RateErrorModel")
.SetParent ()
.AddConstructor ()
;
вернуть tid;
}
РатеErrorModel::RateErrorModel ()
{
}
РатеErrorModel::~RateErrorModel ()
{
}
В чём GetTypeId (пустота) функция? Эта функция делает несколько вещей. Он регистрирует
уникальная строка в систему TypeId. Он устанавливает иерархию объектов в
система атрибутов (через SetParent). Он также объявляет, что определенные объекты могут быть созданы с помощью
фреймворк создания объекта (ДобавитьКонструктор).
Макрос NS_OBJECT_ENSURE_RIGN (имя класса) требуется также один раз для каждого класса, который
определяет новый метод GetTypeId и выполняет фактическую регистрацию класса в
система. В главе «Объектная модель» это обсуждается более подробно.
В том числе Внешний Файлы
Запись Поддержка
Здесь, записывать a бит в отношении добавить | ns3 | каротаж макросы. Внимание который LOG_COMPONENT_DEFINE is
сделанный внешнюю Пространство имен ns3
Конструктор, пустой Функция Прототипы
Основные Переменные (Дефолт Ценности, Атрибуты)
Тест Программа 1
объект Рамки
Добавление a Образец Сценарий
На этом этапе можно попробовать взять базовые строительные леса, определенные выше, и добавить их.
в систему. Выполнение этого шага теперь позволяет использовать более простую модель при сантехнике.
в систему, а также может показать, нужно ли вносить какие-либо изменения в дизайн или API.
сделал. Как только это будет сделано, мы вернемся к построению функциональности
Сами ErrorModels.
Добавить Базовый Поддержка in Класс
/* точка-точка-сетевое-устройство.h */
класс ErrorModel;
/ **
* Модель ошибок для событий приема пакетов
*/
Птр m_receiveErrorModel;
Добавить Аксессуар
аннулировать
PointToPointNetDevice::SetReceiveErrorModel (Ptr Эм)
{
NS_LOG_FUNCTION (это << em);
m_receiveErrorModel = em;
}
.AddAttribute("ReceiveErrorModel",
«Модель ошибки приемника, используемая для имитации потери пакетов»,
значение указателя (),
MakePointerAccessor (&PointToPointNetDevice::m_receiveErrorModel),
MakePointerChecker ())
отвес В Система
void PointToPointNetDevice::Receive (Ptr пакет)
{
NS_LOG_FUNCTION (данный << пакет);
протокол uint16_t = 0;
если (m_receiveErrorModel && m_receiveErrorModel->IsCorrupt (пакет))
{
//
// Если у нас есть модель ошибки, и это указывает на то, что пора терять
// поврежденный пакет, не пересылайте этот пакет, отпустите его.
//
m_dropTrace (пакет);
}
еще
{
//
// Нажимаем на ловушку трассировки получения, удаляем заголовок протокола точка-точка
// и пересылаем этот пакет вверх по стеку протоколов.
//
m_rxTrace (пакет);
ProcessHeader(пакет, протокол);
m_rxCallback(это, пакет, протокол, GetRemote());
если (!m_promiscCallback.IsNull ())
{ m_promiscCallback(это, пакет, протокол, GetRemote(),
ПолучитьАдрес(), NetDevice::PACKET_HOST);
}
}
}
Создавай Значение Null функциональная Сценарий
/* простая-ошибка-модель.cc */
// Модель ошибки
// Мы хотим добавить модель ошибки в NetDevice узла 3
// Мы можем получить дескриптор NetDevice через канал и узел
// указатели
Птр nd3 = PointToPointTopology::GetNetDevice
(n3, канал2);
Птр эм = Создать ();
nd3->SetReceiveErrorModel (em);
BOOL
ErrorModel::DoCorrupt (пакет&p)
{
НС_LOG_FUNCTION;
NS_LOG_UNCOND("Повреждён!");
возвращение ложным;
}
На этом этапе мы можем запустить программу с нашей тривиальной ErrorModel, встроенной в получатель.
путь PointToPointNetDevice. Он выводит строку "Коррумпировано!" за каждый пакет
полученный в узле n3. Затем мы возвращаемся к модели ошибок, чтобы добавить подкласс, который выполняет
более интересное моделирование ошибок.
Добавить a Подкласс
Тривиальный базовый класс ErrorModel не делает ничего интересного, но предоставляет
полезный интерфейс базового класса (Corrupt() и Reset()), перенаправленный на виртуальные функции, которые
может быть подклассом. Давайте теперь рассмотрим то, что мы называем BasicErrorModel, основанное на
нс-2 Класс ErrorModel (в ns-2/queue/errmodel.{cc,h}).
Какие свойства мы хотим, чтобы это имело, с точки зрения пользовательского интерфейса? Мы бы хотели
чтобы пользователь мог тривиально поменять тип ErrorModel, используемый в
NetDevice. Мы также хотели бы иметь возможность устанавливать настраиваемые параметры.
Вот несколько простых требований, которые мы рассмотрим:
· Возможность установить случайную переменную, определяющую потери (по умолчанию — UniformVariable)
· Возможность установки единицы (бит, байт, пакет, время) детализации, по которой ошибки
применяется.
· Возможность установить скорость ошибок (например, 10^-3), соответствующую указанной выше единице измерения.
зернистость.
· Возможность включения/выключения (по умолчанию включено)
Как в Подкласс
Мы объявляем BasicErrorModel подклассом ErrorModel следующим образом:
класс BasicErrorModel: общедоступная модель ошибок
{
общественности:
статический TypeId GetTypeId (void);
...
частный:
// Реализовать чисто виртуальные функции базового класса
виртуальный логический DoCorrupt (Ptr п);
виртуальное логическое значение DoReset (недействительно);
...
}
и настройте функцию GetTypeId подкласса, установив уникальную строку TypeId и
установка Parent в ErrorModel:
TypeId RateErrorModel::GetTypeId (пусто)
{
статический TypeId tid = TypeId ("ns3::RateErrorModel")
.SetParent ()
.AddConstructor ()
...
Построить Основные функции и Ед. Tests
Утверждай Макрос
Writing Ед. Tests
Добавление a Новое Модули в нс-3
Когда вы создали группу связанных классов, примеров и тестов, их можно
объединены вместе в нс-3 модуль, чтобы их можно было использовать с существующими нс-3 модули
и другими исследователями.
В этой главе описаны шаги, необходимые для добавления нового модуля в нс-3.
Шаг 0 - Модули Планировка
Все модули можно найти в SRC каталог. Каждый модуль можно найти в каталоге
который имеет то же имя, что и модуль. Например, спектр модуль можно найти здесь:
источник/спектр. Мы будем цитировать из спектр модуль для иллюстрации.
Прототип модуля имеет следующую структуру каталогов и необходимые файлы:
SRC /
имя-модуля/
привязки/
doc /
Примеры/
wскрипт
помощник/
модель/
тестирование /
примеры для запуска.py
wскрипт
Не все каталоги будут присутствовать в каждом модуле.
Шаг 1 - Создавай a Модули Скелет
В исходном каталоге находится программа на Python, которая создаст основу для нового
модуль. Для целей этого обсуждения мы предположим, что ваш новый модуль называется
новый модуль. С SRC каталог, сделайте следующее, чтобы создать новый модуль:
$ ./create-module.py новый модуль
Далее, cd в новый модуль; вы найдете этот макет каталога:
$ cd новый модуль
$ лс
doc примеры вспомогательная модель тест wscript
Более подробно создать-module.py script создаст каталоги, а также начальный
скелет wскрипт, .h, .cc и .первый файлы. Полный модуль с файлами каркаса выглядит
как это:
SRC /
новый модуль/
doc /
новый-module.rst
Примеры/
новый модуль-example.cc
wскрипт
помощник/
новый модуль-helper.cc
новый-модуль-helper.h
модель/
новый-module.cc
новый-module.h
тестирование /
новый-модуль-test-suite.cc
wскрипт
(При необходимости привязки/ каталог, указанный в Шаг 0 будет создан автоматически во время
сборка.)
Далее мы рассмотрим, как настроить этот модуль. Информирование WAF о файлах, которые
составить свой модуль, отредактировав два wскрипт файлы. Мы пройдем через
основные шаги в этой главе.
Все нс-3 модули зависят от ядро модуле и обычно на других модулях. Эта зависимость
указано в wскрипт файл (на верхнем уровне модуля, а не в отдельном wскрипт
подать в Примеры реализованных проектов каталог!). В скелете wскрипт вызов, который объявит ваш
новый модуль для WAF будет выглядеть так (до редактирования):
деф билд(блд):
модуль = bld.create_ns3_module('новый-модуль', ['ядро'])
Предположим, что новый модуль зависит от интернет, мобильностьи АОДВ модули. После
редактируя это wскрипт файл должен выглядеть так:
деф билд(блд):
модуль = bld.create_ns3_module('новый-модуль', ['интернет', 'мобильность', 'aodv'])
Обратите внимание, что должны быть перечислены только зависимости модуля первого уровня, поэтому мы удалили
ядро; интернет модуль, в свою очередь, зависит от ядро.
Ваш модуль, скорее всего, будет иметь исходные файлы модели. Начальные скелеты (которые будут
компилируется успешно) создаются в модель/новый-module.cc и модель/новый-module.h.
Если в вашем модуле будут вспомогательные исходные файлы, то они попадут в помощник/
справочник; опять же, в этом каталоге создаются начальные скелеты.
Наконец, хорошей практикой является написание тестов и примеров. Это почти наверняка будут
требуется для того, чтобы новые модули были приняты в официальный нс-3 исходное дерево. Скелет
набор тестов и тестовый пример создаются в тестирование / каталог. Скелетный набор тестов будет
содержат приведенный ниже конструктор, который объявляет новый модульный тест с именем новый модуль, С
один тестовый пример, состоящий из класса Ньюмодулетесткейс1:
Ньюмодулетестсуите::ньюмодулетестсуите ()
: TestSuite ("новый модуль", UNIT)
{
AddTestCase (новый NewModuleTestCase1);
}
Шаг 3 - Объявлять Источник Файлы
Публичные заголовочные файлы и файлы исходного кода для вашего нового модуля должны быть указаны в
wскрипт файл, изменив его в текстовом редакторе.
Например, после объявления спектр модуль, источник/спектр/wscript указывает на
файлы исходного кода со следующим списком:
деф билд(блд):
module = bld.create_ns3_module('спектр', ['интернет', 'распространение', 'антенна', 'приложения'])
модуль.источник = [
'модель/спектр-модель.cc',
'модель/спектр-значение.cc',
.
.
.
'модель/микроволновая печь-спектр-значение-помощник.cc',
'помощник/спектр-helper.cc',
'helper/adhoc-aloha-noack-ideal-phy-helper.cc',
'helper/waveform-generator-helper.cc',
'helper/spectrum-analyzer-helper.cc',
]
Объекты, полученные в результате компиляции этих исходников, будут собраны в библиотеку ссылок,
который будет связан с любыми программами, использующими этот модуль.
Но как такие программы узнают публичный API нашего нового модуля? Читать дальше!
Шаг 4 - Объявлять Общая заголовок Файлы
Файлы заголовков, определяющие общедоступный API вашей модели и помощников, также должны быть
указано в wскрипт .
Продолжая с спектр иллюстрация модели, указаны общедоступные заголовочные файлы
со следующей строфой. (Обратите внимание, что аргумент зд функция сообщает WAF в
установить заголовки этого модуля с другим нс-3 заголовки):
заголовки = bld (особенности = 'ns3header')
headers.module = 'спектр'
заголовки. источник = [
'модель/спектр-модель.h',
'модель/спектр-значение.h',
.
.
.
'модель/микроволновая печь-спектр-значение-помощник.h',
'помощник/спектр-помощник.h',
'helper/adhoc-aloha-noack-ideal-phy-helper.h',
'helper/waveform-generator-helper.h',
'помощник/спектр-анализатор-помощник.h',
]
Заголовки, опубликованные таким образом, будут доступны пользователям вашей модели с включением
заявления вроде
#include "ns3/spectrum-model.h"
Заголовки, используемые исключительно внутри вашей реализации, не должны быть включены сюда. Они
по-прежнему доступны для вашей реализации с помощью операторов include, таких как
#include "my-module-implementation.h"
Шаг 5 - Объявлять Tests
Если в вашем новом модуле есть тесты, то они должны быть указаны в вашем wскрипт файл
изменить его с помощью текстового редактора.
" спектр Модельные тесты указаны в следующей строфе:
module_test = bld.create_ns3_module_test_library('спектр')
модуль_test.source = [
'тест/спектр-интерференция-test.cc',
'тест/спектр-значение-test.cc',
]
Увидеть Tests для получения дополнительной информации о том, как писать тестовые примеры.
Шаг 6 - Объявлять Примеры
Если в вашем новом модуле есть примеры, то они должны быть указаны в вашем примеры/скрипт
файл. (Скелет верхнего уровня wскрипт будет рекурсивно включать примеры/скрипт только если
примеры были включены во время настройки.)
" спектр модель определяет свой первый пример в источник/спектр/примеры/wscript
деф билд(блд):
obj = bld.create_ns3_program('adhoc-aloha-ideal-phy',
['спектр', 'подвижность'])
obj.source = 'adhoc-aloha-ideal-phy.cc'
Обратите внимание, что второй аргумент функции create_ns3_program() это список модулей
от чего зависит создаваемая программа; опять же, не забудьте включить новый модуль in
список. Лучше всего перечислять только прямые зависимости модуля, и пусть WAF
вывести полное дерево зависимостей.
Иногда, для ясности, вы можете захотеть разделить реализацию вашего примера между
несколько исходных файлов. В этом случае просто включите эти файлы как дополнительные явные
исходники примера:
obj = bld.create_ns3_program('пример нового модуля', [новый модуль])
obj.source = ['новый-модуль-пример.cc', 'новый-модуль-пример-часть.cc']
Примеры Python задаются с помощью следующего вызова функции. Обратите внимание, что второй
аргумент для функции Register_ns3_script() список модулей, которые Python
пример зависит от:
bld.register_ns3_script('новый-модуль-example.py', ['новый-модуль'])
Шаг 7 - Примеры Run as Tests
В дополнение к запуску явного тестового кода тестовая среда также может быть приспособлена для
запускайте полные примеры программ, чтобы попытаться поймать регрессии в примерах. Тем не менее, не все
примеры подходят для регрессионных тестов. Файл тест/примеры-to-run.py контролирует
вызов примеров при запуске тестовой среды.
" спектр примеры моделей test.py указаны в
src/spectrum/test/examples-to-run.py используя следующие два списка C++ и Python
Примеры:
# Список примеров C++ для запуска, чтобы убедиться, что они остаются
# сборка и запуск с течением времени. Каждый кортеж в списке содержит
#
# (имя_примера, do_run, do_valgrind_run).
#
# См. test.py для получения дополнительной информации.
cpp_examples = [
("adhoc-aloha-ideal-phy", "Правда", "Правда"),
(«adhoc-aloha-ideal-phy-with-microwave-печь», «Правда», «Правда»),
("adhoc-aloha-ideal-phy-matrix-propagation-loss-model", "True", "True"),
]
# Список примеров Python для запуска, чтобы убедиться, что они остаются
# работает с течением времени. Каждый кортеж в списке содержит
#
# (имя_примера, do_run).
#
# См. test.py для получения дополнительной информации.
python_examples = [
("sample-simulator.py", "Истина"),
]
Как указано в комментарии, каждая запись в списке примеров C++ для запуска содержит
кортеж (имя_примера, делай_беги, do_valgrind_run), Где
· имя_примера исполняемый файл для запуска,
· do_run условие, при котором выполняется пример, и
· do_valgrind_run это условие запуска примера под valgrind. (Этот
необходим, потому что NSC вызывает недопустимые сбои инструкций с некоторыми тестами, когда они
выполняются под управлением valgrind.)
Обратите внимание, что эти два условия являются операторами Python, которые могут зависеть от WAF конфигурация
переменные. Например,
("tcp-nsc-lfn", "NSC_ENABLED == True", "NSC_ENABLED == False"),
Каждая запись в списке примеров Python для запуска содержит кортеж (имя_примера,
делать_бежать), где, как и в примерах C++,
· имя_примера скрипт Python, который нужно запустить, и
· do_run условие, при котором выполняется пример.
Опять же, условие — это оператор Python, который может зависеть от WAF переменные конфигурации.
Например,
("realtime-udp-echo.py", "ENABLE_REAL_TIME == False"),
Шаг 8 - Настроить и Построить
Теперь вы можете настроить, собрать и протестировать свой модуль как обычно. Вы должны переконфигурировать
проект в качестве первого шага, чтобы WAF кэширует новую информацию в вашем wскрипт файлы или
иначе ваш новый модуль не будет включен в сборку.
$ ./waf настроить --enable-examples --enable-tests
Сборка $ ./waf
$ ./test.py
Найдите набор тестов вашего нового модуля (и примеры программ, если они есть в вашем модуле).
включен) в тестовом выводе.
Шаг 9 - Питон Наручники
Добавление привязок Python к вашему модулю необязательно, и этот шаг закомментирован
по умолчанию в создать-module.py скрипты.
# bld.ns3_python_bindings()
Если вы хотите включить привязки Python (необходимы, только если вы хотите написать Python ns-3
программы вместо программ C++ ns-3), вы должны раскомментировать приведенное выше и установить
систему сканирования Python API (описанную в другом месте этого руководства) и отсканируйте ваш модуль, чтобы
генерировать новые привязки.
Создающий Документация
нс-3 предоставляет два вида документации: пояснительные главы в стиле «руководства пользователя» и
документация по API с исходным кодом.
Главы «руководства пользователя» написаны от руки на ReStructuredText формат (.первый), который
обрабатывается системой документации Python Сфинкс для создания веб-страниц и файлов PDF.
Документация по API генерируется из самого исходного кода с использованием Доксиген, генерировать
веб-страницы с перекрестными ссылками. Оба они важны: главы о Сфинксе объясняют почему
и обзор использования модели; документация API объясняет это
В этой главе дается краткий обзор этих инструментов с акцентом на предпочтительное использование и
настройки для нс-3.
Чтобы собрать всю стандартную документацию:
$ ./ваф документы
Чтобы узнать о более специализированных опциях, читайте дальше.
Документирование Сфинкс
МЫ ИСПОЛЬЗУЕМ Сфинкс для создания пояснительных глав, описывающих дизайн и использование каждого
модуль. Прямо сейчас вы читаете Документация Глава. То Показать Источник ссылка в
боковая панель покажет вам источник reStructuredText для этой главы.
Добавление Новое Главы
Добавление новой главы выполняется в три этапа (более подробно описано ниже):
1. выберите Где? файл(ы) документации будет жить.
2. Ссылка с существующей страницы на новую документацию.
3. Добавьте новый файл в Makefile.
Где?
Документация по конкретному модулю, Foo, обычно должен входить источник/foo/doc/, Например
источник/foo/doc/foo.rst будет документом верхнего уровня для модуля. То
источник/создать-module.py script создаст этот файл для вас.
Для некоторых моделей требуется несколько .первый файлы и рисунки; все это должно идти в
источник/foo/doc/ каталог. Документы на самом деле создаются с помощью файла Makefile Sphinx. Для особо
связанной с документацией, может быть полезно иметь местный Makefile в источник/foo/doc/
каталог, чтобы упростить создание документации для этого модуля (Антенна это пример).
Настройка этого не особенно сложна, но выходит за рамки этой главы.
В некоторых случаях документация охватывает несколько моделей; в Cеть глава является примером. В
эти случаи добавляют .первый файлы непосредственно в документ/модели/источник/ может быть уместным.
Ссылка
Сфинкс должен знать в котором должна появиться ваша новая глава. В большинстве случаев новая модель
глава должна появиться в Модели книга. Чтобы добавить туда свою главу, отредактируйте
документ/модели/источник/index.rst
.. toctree::
:максимальная глубина: 1
организация
анимация
антенна
АОДВ
Приложения
...
Добавьте название вашего документа (без .первый расширение) в этот список. Пожалуйста, держите
Смоделируйте главы в алфавитном порядке, чтобы облегчить визуальное сканирование определенных глав.
Makefile
Вы также должны добавить свой документ в соответствующий Makefile, так сделать знает, чтобы проверить это
для обновлений. Книга о моделях Makefile документ/модели/Makefile, Инструкция Makefile есть
документ/руководство/Makefile.
# список всех файлов .rst библиотеки моделей, которые необходимо скопировать в $SOURCETEMP
ИСТОЧНИКИ =
источник/conf.py
источник/_статический
источник/index.rst
источник/заменить.txt
источник/organization.rst
...
$(SRC)/антенна/doc/source/antenna.rst
...
Вы добавляете свой .первый файлы в ИСТОЧНИКИ Переменная. Чтобы добавить цифры, читайте комментарии в
Makefile чтобы увидеть, какая переменная должна содержать ваши файлы изображений. Еще раз, пожалуйста, сохраните эти
в алфавитном порядке.
Здание Сфинкс Документация
Собрать документацию Sphinx довольно просто. Чтобы построить всех сфинксов
документация:
$ ./ваф сфинкс
Чтобы создать только документацию по моделям:
$ make -C документ/модели
Чтобы увидеть сгенерированную документацию, укажите в браузере документ/модели/сборка/html.
Как видите, Sphinx использует Make для управления процессом. Цель по умолчанию строит все
включены выходные формы, которые в нс-3 являются многостраничными HTML, одна страница синглhtmlи
пдф (латекс). Чтобы построить только многостраничный html, вы добавляете HTML цель:
$ make -C документ/модель HTML
Это может быть полезно для сокращения времени сборки (и размера болтовни сборки) по мере того, как вы
пишем вашу главу.
Прежде чем отправлять документацию в репозиторий, убедитесь, что она собрана без
ошибки или предупреждения. Процесс сборки генерирует много выходных данных (в основном обычная болтовня).
из LaTeX), что может затруднить просмотр предупреждений Sphinx или
ошибки. Чтобы найти важные предупреждения и ошибки, создайте только HTML версия, затем поиск
журнал сборки для предупреждение or ошибка.
нс-3 конкретика
Сфинкс документации и учебник довольно хороши. Мы не будем дублировать основы
здесь, вместо того, чтобы сосредоточиться на предпочтительном использовании для нс-3.
· Начинайте документы с этих двух строк:
.. включить:: replace.txt
.. выделить:: cpp
Первая строка допускает несколько простых замен. Например, набрав | ns3 | отображается как
нс-3. Второй устанавливает язык подсветки исходного кода по умолчанию явно для
файл, так как догадка синтаксического анализатора не всегда точна. (Также можно установить
язык явно для одного блока кода, см. ниже.)
· Разделы:
Sphinx довольно либерально относится к маркировке заголовков разделов. По соглашению мы предпочитаем это
иерархия:
.. Иерархия заголовков:
------------- Глава
************* Раздел (#.#)
============= Подраздел (#.#.#)
############# Подподраздел
· Подсветка синтаксиса:
Чтобы использовать подсветку синтаксиса по умолчанию, просто запустите блок исходного кода:
┌───────────────────────────────────────────────────── ───────────────────────────────┐
│Исходный код Sphinx │ Визуализированный вывод │
├───────────────────────────────────────────────────── ───────────────────────────────┤
│ │ Фробниц получают доступ: │
│ Доступ к ``Frobnitz`` осуществляется через:: │ │
│ │ Foo::Frobnitz frob; │
│ Foo::Frobnitz frob; │ frob.Set(...); │
│ frob.Set(...); │ │
└───────────────────────────────────────────────── ── ───────────────────────────────┘
Например, чтобы использовать определенную подсветку синтаксиса, колотить команды оболочки:
┌───────────────────────────────────┬───────────────── ───┐
│Исходный код Sphinx │ Визуализированный вывод │
├───────────────────────────────────┼───────────────── ───┤
│ │ │
│ .. исходный код::bash │ $ls │
│ │ │
│ $ лс │ │
└──────────────────────────────────────────────────── ───┘
· Сокращенные обозначения:
Эти сокращения определены:
┌────────────────────────┬─────────────────
│Исходный код Sphinx │ Визуализированный вывод │
├────────────────────────┼─────────────────
│ │ нс-3 │
│ |ns3| │ │
├────────────────────────┼─────────────────
│ │ нс-2 │
│ |ns2| │ │
├────────────────────────┼─────────────────
│ │ │
│ |проверить| │ │
├────────────────────────┼─────────────────
│ │ RFC 6282 │
│ :rfc:`6282` │ │
└────────────────────────┴─────────────────
Документирование Доксиген
МЫ ИСПОЛЬЗУЕМ Доксиген генерировать просматриваемый Документация по API. Doxygen предоставляет ряд
полезные функции:
· Сводная таблица всех участников класса.
· Графики наследования и сотрудничества для всех классов.
· Ссылки на исходный код, реализующий каждую функцию.
· Ссылки на каждое место, где используется член.
· Ссылки на каждый объект, используемый при реализации функции.
· Группировка связанных классов, таких как все классы, относящиеся к конкретному протоколу.
Кроме того, мы используем Идентификатор типа система для добавления в документацию для каждого класса
· The Конфиг пути, по которым такие объекты могут быть достигнуты.
· Документация на любой Атрибутыв том числе Атрибуты определены в родительских классах.
· Документация на любой Прослеживать источники, определенные классом.
Doxygen работает путем сканирования исходного кода в поисках специально помеченных комментариев. Это
также создает перекрестную ссылку, указывающую в котором каждый файл, класс, метод и переменная
используемый.
Привилегированный Стиль
Предпочтительным стилем для комментариев Doxygen является стиль JavaDoc:
/ **
* Краткое описание этого класса или метода.
* Смежные строки становятся одним абзацем.
*
* Подробное описание с большим количеством деталей.
*
* Пустые строки отделяют абзацы.
*
* Объясните, что делает класс или метод, используя какой алгоритм.
* Объясните единицы аргументов и возвращаемых значений.
*
* \note Обратите внимание на любые ограничения или ошибки.
*
* (Для функций с аргументами или возвращаемым значением:)
* \param foo Краткое словосочетание, описывающее этот аргумент.
* \param bar Примечание. Регистр предложения и точка окончания.
* \return Краткое словосочетание, описывающее значение.
*
* \внутренний
*
* Вы также можете обсудить детали внутренней реализации.
* Понимание этого материала не обязательно для использования
* класс или метод.
*/
пример класса
В этом стиле блок комментариев Doxygen начинается с двух символов `*': / **, и предшествует
объект, который документируется.
Для элементов, требующих только краткого описания, подходит любая из этих кратких форм:
/** Реализация деструктора. */
недействительным DoDispose();
интервал m_count; //!< Счетчик...
Обратите внимание на особую форму комментария в конце строки, //!, указывая на то, что он относится к
предшествующий пункт.
Некоторые пункты, на которые стоит обратить внимание:
· Используйте регистр предложений, в том числе начальный капитал.
· Используйте знаки препинания, особенно `.' в конце предложений или фраз.
· The \краткий тег не нужен; первое предложение будет использоваться как краткое
описание.
Каждый класс, метод, typedef, переменная-член, аргумент функции и возвращаемое значение должны
документироваться во всех файлах исходного кода, формирующих формальный API и реализацию для
нс-3, Такие, как источник/ /модель/*, источник/ /помощник/* и источник/ /утилиты/*.
Документация по предметам в источник/ /контрольная работа/* и источник/ /Примеры/* является предпочтительным,
но не обязательно.
Полезное Особенности
· Унаследованные участники автоматически наследуют документы от родителя (но могут быть заменены
по местной документации).
1. Задокументируйте базовый класс.
2. В подклассе отметить унаследованные функции обычным комментарием:
// Унаследованные методы
виртуальная пустота FooBar (пустота);
виртуальный int BarFoo (двойной баз);
Обратите внимание, что подписи должны точно совпадать, поэтому включите формальный аргумент (пустота)
Это не работает для статических функций; видеть GetTypeId, ниже, для примера.
Здание Доксиген Документация
Собрать документацию Doxygen довольно просто:
$ ./ваф
Это сборка с использованием конфигурации по умолчанию, которая создает разделы документации для
ВСЕ элементы, даже если они не имеют явных блоков документации комментариев. Это имеет
эффект подавления предупреждений для недокументированных элементов, но гарантирует, что все отображается
в сгенерированном выводе.
При написании документации часто бывает полезнее увидеть, какие элементы генерируются.
предупреждения, как правило, об отсутствии документации. Чтобы увидеть полный список предупреждений, используйте
doc/doxygen.warnings.report.sh сценарий:
$ doc/doxygen.warnings.report.sh
Waf: Вход в каталог `build'
...
Waf: Выход из каталога `build'
'build' успешно завершена (3 мин. 24.094 сек.)
Восстановление документов doxygen с полными ошибками... Готово.
Отчет о предупреждениях Doxygen
----------------------------------------
(Все подсчеты являются нижними границами.)
Предупреждения по модулю/каталогу:
Справочник графов
----- ----------------------------------
3844 src/lte/модель
1718 src/wimax/модель
1423 src/ядро/модель
....
138 дополнительных недокументированных параметров.
----------------------------------------
15765 всего предупреждений
126 каталогов с предупреждениями
Предупреждения по файлам (в алфавитном порядке)
Файл подсчета
----- ----------------------------------
17 doc/introspected-doxygen.h
15 примеров/routing/manet-routing-compare.cc
26 примеров/статистика/wifi-example-apps.h
....
----------------------------------------
967 файлов с предупреждениями
Предупреждения по файлам (числовые)
Файл подсчета
----- ----------------------------------
374 источник/lte/модель/lte-asn1-header.h
280 источник/lte/модель/lte-rrc-sap.h
262 источник/lte/модель/lte-rrc-header.h
....
----------------------------------------
967 файлов с предупреждениями
Сводка предупреждений Doxygen
----------------------------------------
126 каталогов
967 файлы
15765 предупреждений
Сценарий изменяет конфигурацию для отображения всех предупреждений и сокращения времени выполнения.
Как видите, на момент написания этой статьи у нас есть a много недокументированных объектов. Отчет
суммирует предупреждения по модулям источник/*/*и по файлам в алфавитном и числовом порядке.
В сценарии есть несколько опций, позволяющих упростить процесс и сделать его более управляемым. За помощью,
использовать -h вариант. Запустив его один раз, чтобы выполнить сборку Doxygen и сгенерировать полный
журнал предупреждений, вы можете повторно обрабатывать файл журнала с помощью различных «фильтров», не выполняя
полная сборка Doxygen, опять же с использованием -s вариант. Вы можете исключить предупреждения из
*/Примеры/* файлы (-e вариант) и/или */контрольная работа/* файлы (-t).
Пожалуй, самая полезная опция при написании комментариев к документации — это -m , который
ограничит отчет только файлами, соответствующими источник/ /*, и следуйте за отчетом с
настоящие предупреждающие строки. Комбинировать с -И и вы можете сосредоточиться на предупреждениях, которые
самое срочное в одном модуле:
$ doc/doxygen.warnings.report.sh -m сетка/помощник
...
Сводка предупреждений Doxygen
----------------------------------------
1 каталогов
3 файлы
149 предупреждений
Отфильтрованные предупреждения
========================================
src/mesh/helper/dot11s/dot11s-installer.h:72: предупреждение: элемент m_root (переменная) класса ns3::Dot11sStack не задокументирован.
src/mesh/helper/dot11s/dot11s-installer.h:35: предупреждение: возвращаемый тип члена ns3::Dot11sStack::GetTypeId не задокументирован
src/mesh/helper/dot11s/dot11s-installer.h:56: предупреждение: возвращаемый тип члена ns3::Dot11sStack::InstallStack не задокументирован
src/mesh/helper/flame/lfame-installer.h:40: предупреждение: Член GetTypeId() (функция) класса ns3::FlameStack не задокументирован.
src/mesh/helper/flame/flame-installer.h:60: предупреждение: возвращаемый тип члена ns3::FlameStack::InstallStack не задокументирован
src/mesh/helper/mesh-helper.h:213: предупреждение: член m_nInterfaces (переменная) класса ns3::MeshHelper не задокументирован.
src/mesh/helper/mesh-helper.h:214: предупреждение: член m_spreadChannelPolicy (переменная) класса ns3::MeshHelper не задокументирован.
src/mesh/helper/mesh-helper.h:215: предупреждение: член m_stack (переменная) класса ns3::MeshHelper не задокументирован.
src/mesh/helper/mesh-helper.h:216: предупреждение: элемент m_stackFactory (переменная) класса ns3::MeshHelper не задокументирован.
src/mesh/helper/mesh-helper.h:209: предупреждение: параметры члена ns3::MeshHelper::CreateInterface не (все) задокументированы
src/mesh/helper/mesh-helper.h:119: предупреждение: параметры члена ns3::MeshHelper::SetStandard не (все) задокументированы
Теперь осталось только понять код и написать несколько документов!
нс-3 конкретика
Что касается Сфинкса, Doxygen Документы и ссылка довольно хороши. Мы не будем дублировать
основы здесь, вместо того, чтобы сосредоточиться на предпочтительном использовании для нс-3.
· Используйте Доксиген Модули группировать связанные элементы.
В главном заголовке модуля создайте группу Doxgyen:
/ **
* \defgroup foo Протокол Foo.
*/
Отметьте каждый связанный класс как принадлежащий группе:
/ **
* \ingroup фу
*
* Тип пакета Foo.
*/
класс Foo
· Вы знали Определения типов может есть формальные аргументы? Это позволяет документировать функцию
подписи указателя:
/ **
* Сигнатура функции обратного вызова бара.
*
* \param ale Размер пинты эля в имперских унциях.
*/
typedef void (* BarCallback) (const int ale);
· Скопируйте Атрибут строки справки из GetTypeId метод использования в качестве брифа
описания ассоциированных членов.
· \bugid{298} создаст ссылку на ошибку 298 в нашей Bugzilla.
· \pname{фу} в описании будет формат Foo как \ param Foo параметр, чтобы было понятно
что вы имеете в виду реальный спор.
· \RFC{301} создаст ссылку на RFC 301.
· \внутренний следует использовать только для начала обсуждения деталей реализации, а не для
отметка частная функции (они уже отмечены, т.к. частная!)
· Не создавайте классы с тривиальными именами, такими как класс A, даже в наборах тестов. Эти
привести к тому, что все экземпляры литерала имени класса `A' будут отображаться как ссылки.
Как отмечалось выше, статические функции не наследуют документацию тех же функций в
родительский класс. нс-3 повсеместно использует несколько статических функций; предложенный
блок документации для этих случаев:
· Конструктор/деструктор по умолчанию:
Мои занятия (); //!< Конструктор по умолчанию
~МойКласс(); //!< Деструктор
· Деструктор-пустышка и DoDispose:
/** Деструктор-пустышка, см. DoDispose. */
~МойКласс();
/** Реализация деструктора */
виртуальная пустота DoDispose();
· ПолучитьИдентификатор Типа:
/ **
* Зарегистрируйте этот тип.
* \ return Объект TypeId.
*/
статический TypeId GetTypeId (void);
Включение Подгруппы of нс-3 Модули
Как и в большинстве программных проектов, нс-3 становится все больше с точки зрения количества модулей,
строк кода и объема памяти. Однако пользователи могут использовать только некоторые из этих модулей.
вовремя. По этой причине пользователи могут захотеть явно включить только подмножество
возможное нс-3 модули, которые им действительно нужны для их исследований.
В этой главе обсуждается, как включить только нс-3 модули, которые вас интересуют
используя.
Как в включить a подмножество of нс-3's модули
Если создаются разделяемые библиотеки, то включение модуля приведет как минимум к одному
библиотека, которая будет построена:
libns3-modulename.so
Если в модуле есть тестовая библиотека и идет сборка тестовых библиотек, то
libns3-имя-модуля-test.so
тоже будет строиться. Другие модули, от которых зависит модуль, и их тестовые библиотеки
также будет построен.
По умолчанию все модули встроены нс-3. Есть два способа включить подмножество этих
модули:
1. Использование параметра waf --enable-modules
2. Используя нс-3 файл конфигурации
Включите модули через ваф --enable-модули вариант
Чтобы включить только основной модуль с примерами и тестами, например, попробуйте эти команды:
$. / ваф чистый
$ ./waf configure --enable-examples --enable-tests --enable-modules=core
Сборка $ ./waf
$ cd сборка/отладка/
$ лс
и должны присутствовать следующие библиотеки:
привязки libns3-core.so утилиты для царапин ns3
примеры libns3-core-test.so образцы src
Обратите внимание ./ваф чистым шаг сделан здесь только для того, чтобы было более очевидно, какие библиотеки модулей
были построены. Вам не нужно делать ./ваф чистым чтобы включить подмножества модулей.
Запуск test.py приведет к запуску только тех тестов, которые зависят от ядра модуля:
Пройдено 24 из 24 тестов (24 пройдено, 0 пропущено, 0 не выполнено, 0 аварийно завершено, 0 ошибок valgrind)
Повторите вышеописанные шаги для «сетевого» модуля вместо «базового».
будет построено следующее, так как сеть зависит от ядра:
привязки libns3-core.so libns3-network.so утилиты для царапин ns3
примеры libns3-core-test.so libns3-network-test.so примеры src
Запуск test.py приведет к тому, что те тесты, которые зависят только от модулей ядра и сети, будут
запускать:
Пройдено 31 из 31 тестов (31 пройдено, 0 пропущено, 0 не выполнено, 0 аварийно завершено, 0 ошибок valgrind)
Включите модули через нс-3 конфигурация файл
Файл конфигурации .ns3rc был добавлен в нс-3 который позволяет пользователям указать, какие
модули должны быть включены в сборку.
При включении подмножества нс-3 модули, правила приоритета следующие:
1. строка конфигурации --enable-modules переопределяет любой файл .ns3rc
2. файл .ns3rc на верхнем уровне нс-3 затем выполняется обращение к каталогу, если он присутствует
3. система ищет ~/.ns3rc если два вышеуказанных не указаны
Если ни одно из вышеперечисленных ограничений не ограничивает модули для сборки, все модули, о которых знает waf, будут
быть построенным.
Поддерживаемая версия файла .ns3rc в нс-3 репозиторий исходного кода находится в
Utils каталог. Причина этого в том, что если бы он находился в каталоге верхнего уровня
репозиторий, он может быть подвержен случайным проверкам со стороны сопровождающих, которые позволяют
модули, которые они хотят использовать. Поэтому пользователям необходимо вручную скопировать .ns3rc из
Utils каталог в предпочитаемое место (каталог верхнего уровня или их домашний каталог), чтобы
включить постоянную модульную конфигурацию сборки.
Предполагая, что вы находитесь на верхнем уровне нс-3 каталог, вы можете получить копию .ns3rc
файл, который находится в Utils каталог следующим образом:
$ cp утилиты/.ns3rc .
Файл .ns3rc теперь должен быть на вашем верхнем уровне. нс-3 каталог, и он содержит
следующие:
#! / usr / bin / env питон
# Список модулей, которые будут включены при запуске ns-3.
# Модули, которые зависят от перечисленных модулей, также будут включены.
#
# Все модули можно включить, выбрав «all_modules».
modules_enabled = ['все_модули']
# Установите это значение равным true, если вы хотите, чтобы примеры выполнялись.
examples_enabled = Ложь
# Установите это значение равным true, если вы хотите, чтобы тесты выполнялись.
test_enabled = Ложь
Используйте свой любимый редактор, чтобы изменить файл .ns3rc, чтобы включить только основной модуль с
такие примеры и тесты:
#! / usr / bin / env питон
# Список модулей, которые будут включены при запуске ns-3.
# Модули, которые зависят от перечисленных модулей, также будут включены.
#
# Все модули можно включить, выбрав «all_modules».
modules_enabled = ['ядро']
# Установите это значение равным true, если вы хотите, чтобы примеры выполнялись.
examples_enabled = Истина
# Установите это значение равным true, если вы хотите, чтобы тесты выполнялись.
test_enabled = Истина
Только основной модуль будет включен, если вы попробуете эти команды:
$. / ваф чистый
$ ./ваф настроить
Сборка $ ./waf
$ cd сборка/отладка/
$ лс
и должны присутствовать следующие библиотеки:
привязки libns3-core.so утилиты для царапин ns3
примеры libns3-core-test.so образцы src
Обратите внимание ./ваф чистым шаг сделан здесь только для того, чтобы было более очевидно, какие библиотеки модулей
были построены. Вам не нужно делать ./ваф чистым чтобы включить подмножества модулей.
Запуск test.py приведет к запуску только тех тестов, которые зависят от ядра модуля:
Пройдено 24 из 24 тестов (24 пройдено, 0 пропущено, 0 не выполнено, 0 аварийно завершено, 0 ошибок valgrind)
Повторите вышеописанные шаги для «сетевого» модуля вместо «базового».
будет построено следующее, так как сеть зависит от ядра:
привязки libns3-core.so libns3-network.so утилиты для царапин ns3
примеры libns3-core-test.so libns3-network-test.so примеры src
Запуск test.py приведет к тому, что те тесты, которые зависят только от модулей ядра и сети, будут
запускать:
Пройдено 31 из 31 тестов (31 пройдено, 0 пропущено, 0 не выполнено, 0 аварийно завершено, 0 ошибок valgrind)
Включение/отключение нс-3 Tests и Примеры
" нс-3 дистрибутив включает в себя множество примеров и тестов, которые используются для проверки нс-3
система. Однако пользователи могут не всегда хотеть запускать эти примеры и тесты для своих целей.
установка нс-3.
В этой главе обсуждается, как построить нс-3 с его примерами и тестами или без них.
Как в включить выключить Примеры реализованных проектов и тестов in нс-3
Есть 3 способа включить/отключить примеры и тесты в нс-3:
1. Использование build.py, когда нс-3 строится впервые
2. Использование waf один раз нс-3 был построен
3. Используя нс-3 файл конфигурации один раз нс-3 был построен
Включить выключить Примеры реализованных проектов и тестов через build.py
Вы можете использовать build.py для включения/отключения примеров и тестов, когда нс-3 построен для первого
времени.
По умолчанию примеры и тесты не встроены нс-3.
Из каталога ns-3-allinone вы можете собрать нс-3 без всяких примеров и тестов просто
при выполнении:
$ ./build.py
Запуск test.py на верхнем уровне нс-3 каталог теперь не приведет к тому, что примеры или тесты будут
бег:
Пройдено 0 из 0 тестов (0 пройдено, 0 пропущено, 0 не выполнено, 0 аварийно завершено, 0 ошибок valgrind)
Если вы хотите построить нс-3 с примерами и тестами, затем выполните следующие действия из
Каталог ns-3-allinone:
$ ./build.py --enable-examples --enable-тесты
Запуск test.py на верхнем уровне нс-3 каталог вызовет все примеры и тесты
для запуска:
Пройдено 170 из 170 тестов (170 пройдено, 0 пропущено, 0 не выполнено, 0 аварийно завершено, 0 ошибок valgrind)
Включить выключить Примеры реализованных проектов и тестов через WAF
Вы можете использовать waf для включения/отключения примеров и тестов один раз нс-3 был построен.
По умолчанию примеры и тесты не встроены нс-3.
С верхнего уровня нс-3 каталог, вы можете построить нс-3 без всяких примеров и тестов просто
при выполнении:
$ ./ваф настроить
Сборка $ ./waf
Запуск test.py сейчас не приведет к запуску примеров или тестов:
Пройдено 0 из 0 тестов (0 пройдено, 0 пропущено, 0 не выполнено, 0 аварийно завершено, 0 ошибок valgrind)
Если вы хотите построить нс-3 с примерами и тестами, затем сделайте следующее сверху
уровень нс-3 каталог:
$ ./waf настроить --enable-examples --enable-tests
Сборка $ ./waf
Запуск test.py приведет к запуску всех примеров и тестов:
Пройдено 170 из 170 тестов (170 пройдено, 0 пропущено, 0 не выполнено, 0 аварийно завершено, 0 ошибок valgrind)
Включить выключить Примеры реализованных проектов и тестов через нс-3 конфигурация файл
Файл конфигурации .ns3rc был добавлен в нс-3 который позволяет пользователям указать,
примеры и тесты должны быть построены или нет. Вы можете использовать этот файл для включения/отключения
примеры и тесты один раз нс-3 был построен.
При включении отключения примеров и тестов применяются следующие правила приоритета:
1. Строки конфигурации --enable-examples/--disable-examples переопределяют любой файл .ns3rc
2. Строки конфигурации --enable-tests/--disable-tests переопределяют любой файл .ns3rc
3. файл .ns3rc на верхнем уровне нс-3 затем выполняется обращение к каталогу, если он присутствует
4. система ищет ~/.ns3rc если файл .ns3rc не был найден на предыдущем шаге
Если ничего из вышеперечисленного не существует, то примеры и тесты построены не будут.
Поддерживаемая версия файла .ns3rc в нс-3 репозиторий исходного кода находится в
Utils каталог. Причина этого в том, что если бы он находился в каталоге верхнего уровня
репозиторий, он может быть подвержен случайным проверкам со стороны сопровождающих, которые позволяют
модули, которые они хотят использовать. Поэтому пользователям необходимо вручную скопировать .ns3rc из
Utils каталог в предпочитаемое место (каталог верхнего уровня или их домашний каталог), чтобы
включить постоянное включение примеров и тестов.
Предполагая, что вы находитесь на верхнем уровне нс-3 каталог, вы можете получить копию .ns3rc
файл, который находится в Utils каталог следующим образом:
$ cp утилиты/.ns3rc .
Файл .ns3rc теперь должен быть на вашем верхнем уровне. нс-3 каталог, и он содержит
следующие:
#! / usr / bin / env питон
# Список модулей, которые будут включены при запуске ns-3.
# Модули, которые зависят от перечисленных модулей, также будут включены.
#
# Все модули можно включить, выбрав «all_modules».
modules_enabled = ['все_модули']
# Установите это значение равным true, если вы хотите, чтобы примеры выполнялись.
examples_enabled = Ложь
# Установите это значение равным true, если вы хотите, чтобы тесты выполнялись.
test_enabled = Ложь
С верхнего уровня нс-3 каталог, вы можете построить нс-3 без всяких примеров и тестов просто
при выполнении:
$ ./ваф настроить
Сборка $ ./waf
Запуск test.py сейчас не приведет к запуску примеров или тестов:
Пройдено 0 из 0 тестов (0 пройдено, 0 пропущено, 0 не выполнено, 0 аварийно завершено, 0 ошибок valgrind)
Если вы хотите построить нс-3 с примерами и тестами, используйте свой любимый редактор, чтобы изменить
значения в файле .ns3rc для файлов examples_enabled и test_enabled равны True:
#! / usr / bin / env питон
# Список модулей, которые будут включены при запуске ns-3.
# Модули, которые зависят от перечисленных модулей, также будут включены.
#
# Все модули можно включить, выбрав «all_modules».
modules_enabled = ['все_модули']
# Установите это значение равным true, если вы хотите, чтобы примеры выполнялись.
examples_enabled = Истина
# Установите это значение равным true, если вы хотите, чтобы тесты выполнялись.
test_enabled = Истина
С верхнего уровня нс-3 каталог, вы можете построить нс-3 с примерами и тестами просто
делать:
$ ./ваф настроить
Сборка $ ./waf
Запуск test.py приведет к запуску всех примеров и тестов:
Пройдено 170 из 170 тестов (170 пройдено, 0 пропущено, 0 не выполнено, 0 аварийно завершено, 0 ошибок valgrind)
УСТРАНЕНИЕ НЕПОЛАДОК
В этой главе публикуется некоторая информация о возможных распространенных ошибках при построении или запуске
нс-3 программ.
Обратите внимание, что вики (http://www.nsnam.org/wiki/Troubleshooting), возможно, способствовал
предметы.
Построить Ошибки
Во время выполнения Ошибки
Иногда в программе могут возникать ошибки после успешной сборки. Это время выполнения
ошибок и обычно может возникать, когда память повреждена или значения указателя неожиданно
значение NULL.
Вот пример того, что может произойти:
$ ./waf --запустить tcp-точка-точка
Вход в каталог '/home/tomh/ns-3-nsc/build'
Компиляция завершена успешно
Команда ['/home/tomh/ns-3-nsc/build/debug/examples/tcp-точка-точка'] завершилась с кодом -11
Сообщение об ошибке говорит, что программа завершилась неудачно, но это не ясно
из этой информации, что может быть не так. Для более тщательного изучения попробуйте запустить его под
GDB отладчик:
$ ./waf --run tcp-точка-точка --command-template="gdb %s"
Вход в каталог '/home/tomh/ns-3-nsc/build'
Компиляция завершена успешно
GNU GDB Red Hat Linux (6.3.0.0-1.134.fc5rh)
Авторское право 2004 Free Software Foundation, Inc.
GDB - это бесплатное программное обеспечение, на которое распространяется Стандартная общественная лицензия GNU, и вы
добро пожаловать, чтобы изменить его и / или распространять его копии при определенных условиях.
Введите "показать копирование", чтобы увидеть условия.
Абсолютно никаких гарантий на GDB нет. Введите "показать гарантию" для получения подробной информации.
Этот GDB был сконфигурирован как "i386-redhat-linux-gnu"... с использованием хоста libthread_db.
библиотека "/lib/libthread_db.so.1".
(gdb) запустить
Стартовая программа: /home/tomh/ns-3-nsc/build/debug/examples/tcp-точка-точка
Чтение символов из общего объекта, считанного из целевой памяти... выполнено.
Загруженная система предоставила DSO по адресу 0xf5c000
Программа получила сигнал SIGSEGV, Ошибка сегментации.
0x0804aa12 в основном (argc=1, argv=0xbfdfefa4)
в ../examples/tcp-точка-точка.cc:136
136 тр localSocket = socketFactory->CreateSocket();
(gdb) p локальный сокет
$1 = {m_ptr = 0x3c5d65}
(gdb) p фабрика сокетов
$2 = {m_ptr = 0x0}
(GDB) выйти
Программа работает. Все равно выйти? (г или п) г
Сначала обратите внимание на то, как была вызвана программа — передайте команду для запуска в качестве аргумента
шаблон команды "gdb %s".
Это говорит нам о том, что была попытка разыменовать нулевой указатель socketFactory.
Давайте посмотрим на строку 136 tcp-точка-точка, как предлагает gdb:
Птр socketFactory = n2->GetObject (TCP::iid);
Птр localSocket = socketFactory->CreateSocket();
локальный сокет->привязать ();
Виновником здесь является то, что возвращаемое значение GetObject не проверяется и может быть
значение NULL.
Иногда вам может понадобиться использовать Valgrind Память шашка для более тонких ошибок. Снова,
вы аналогично вызываете использование valgrind:
$ ./waf --run tcp-точка-точка --command-template="valgrind %s"
ИСТОЧНИК
Этот документ написан на ReStructuredText для Сфинкс и поддерживается в
документ/руководство каталог исходного кода ns-3.
Используйте ns-3-manual онлайн с помощью сервисов onworks.net