GoGPT Best VPN GoSearch

Значок OnWorks

ns-3-manual - Онлайн у хмарі

Запустіть ns-3-manual у постачальника безкоштовного хостингу OnWorks через Ubuntu Online, Fedora Online, онлайн-емулятор Windows або онлайн-емулятор MAC OS

Це команда ns-3-manual, яку можна запустити в постачальнику безкоштовного хостингу OnWorks за допомогою однієї з наших численних безкоштовних робочих станцій, таких як Ubuntu Online, Fedora Online, онлайн-емулятор Windows або онлайн-емулятор MAC OS.

ПРОГРАМА:

ІМ'Я


ns-3-manual - Керівництво нс-3

Це нс-3 Мануал. Первинна документація для проекту ns-3 доступна в п'яти
форми:

· нс-3 Doxygen: Документація загальнодоступних API симулятора

· Підручник, Посібник (це документ), і бібліотека моделей для останній звільнити та
розробка дерево

· нс-3 вики

ЗМІСТ


Organization
У цьому розділі описано загальне нс-3 організація програмного забезпечення та відповідні
організація цього посібника.

нс-3 є симулятором мережі з дискретними подіями, в якому є ядро ​​моделювання та моделі
реалізовано на C++. нс-3 будується як бібліотека, яка може бути статично або динамічно
пов’язаний з основною програмою C++, яка визначає топологію моделювання та запускає
тренажер. нс-3 також експортує майже весь свій API на Python, що дозволяє програмам на Python
імпортуйте модуль "ns3" майже так само, як і модуль нс-3 бібліотека пов'язана за допомогою виконуваних файлів
в C ++.
[зображення] Організація програмного забезпечення нс-3.НЕЗАХІДНИЙ

Вихідний код для нс-3 в основному організовується в SRC каталог і можна описати
за схемою в Софтвер організація of нс-3. Ми будемо працювати знизу
вгору; загалом, модулі мають залежності лише від модулів під ними на малюнку.

Спочатку опишемо ядро ​​симулятора; ті компоненти, які є спільними для всіх
моделі протоколу, обладнання та середовища. Ядро моделювання реалізовано в
src/core. Пакети є основними об’єктами в симуляторі мережі і реалізуються в
src/мережа. Ці два модулі моделювання самі по собі мають включати a
загальне ядро ​​моделювання, яке може використовуватися не тільки різними типами мереж
Мережі на базі Інтернету. Перераховані вище модулі нс-3 не залежать від конкретної мережі
і моделі пристроїв, які розглядаються в наступних частинах цього посібника.

На додаток до вищесказаного нс-3 core, вводимо також у початкову частину
посібник, два інших модуля, які доповнюють основний API на основі C++. нс-3 програми можуть
отримати доступ до всього API безпосередньо або використовувати т.зв helper API що забезпечує
зручні обгортки або інкапсуляція низькорівневих викликів API. Справа в тому, що нс-3 програми
може бути записаний до двох API (або їх комбінації) є фундаментальним аспектом
тренажер. Ми також описуємо, як підтримується Python нс-3 перш ніж перейти до конкретного
моделі, що мають відношення до мережевого моделювання.

Інша частина посібника зосереджена на документуванні моделей та підтримці
можливості. Наступна частина зосереджується на двох фундаментальних об’єктах нс-3: вузол та
NetDevice. Два спеціальних типи NetDevice призначені для підтримки використання емуляції мережі
випадків, а емуляція описана далі. Наступний розділ присвячений
Моделі, пов’язані з Інтернетом, включаючи API сокетів, що використовуються Інтернет-додатками. The
наступний розділ охоплює програми, а наступний розділ описує додаткову підтримку
для моделювання, наприклад для аніматорів і статистики.

У проекті є окремий посібник, присвячений тестуванню та валідації нс-3 код
(Див нс-3 Тестування та Перевірка керівництво).

випадковий Змінні
нс-3 містить вбудований генератор псевдовипадкових чисел (PRNG). Це важливо для
серйозні користувачі симулятора, щоб зрозуміти функціональність, конфігурацію та використання
цього PRNG, і вирішити, чи достатньо це для його чи її дослідницького використання.

Швидко Про платформу
нс-3 випадкові числа надаються через екземпляри ns3::RandomVariableStream.

· за замовчуванням, нс-3 моделювання використовує фіксоване насіння; якщо є якась випадковість в
симуляції, кожен запуск програми дасть ідентичні результати, якщо початкове та/або
номер прогону змінено.

· в нс-3.3 і раніше, нс-3 моделювання використовувало випадкове початкове значення за замовчуванням; це позначає а
зміна політики починаючи з нс-3.4.

· в нс-3.14 і раніше, нс-3 симуляції використовували інший клас обгортки під назвою
ns3::Випадкова змінна. Як на нс-3.15, цей клас замінено на
ns3::RandomVariableStream; базовий генератор псевдовипадкових чисел не має
змінено.

· щоб отримати випадковість у кількох запусках моделювання, ви повинні або встановити початкове значення
інакше або встановіть номер прогону по-іншому. Щоб посадити насіння, дзвоніть
ns3::RngSeedManager::SetSeed() на початку програми; для встановлення номера прогону
те саме насіння, дзвоніть ns3::RngSeedManager::SetRun() на початку програми; подивитися
створення випадковий змінні.

· кожен RandomVariableStream, який використовується в нс-3 має пов'язаний віртуальний генератор випадкових чисел
з цим; всі випадкові величини використовують або фіксоване, або випадкове початкове значення на основі використання
глобальне насіння (попередня куля);

· якщо ви маєте намір виконати кілька запусків за одним сценарієм з різними випадковими параметрами
числа, будь ласка, прочитайте розділ про те, як виконувати незалежні реплікації:
створення випадковий змінні.

Читайте далі, щоб отримати додаткові пояснення про можливість випадкових чисел для нс-3.

фон
Симуляції використовують багато випадкових чисел; Одне дослідження показало, що більшість мережевих симуляцій
витрачають до 50% ЦП на генерацію випадкових чисел. Користувачі-симулятори повинні бути
стосуються якості (псевдо) випадкових чисел і незалежності між ними
різні потоки випадкових чисел.

Користувачів мають турбувати кілька проблем, як-от:

· використання генератора випадкових чисел і чи є результат моделювання
детермінований чи ні,

· як отримати різні потоки випадкових чисел, які не залежать від одного
інший, і

· скільки часу потрібно для циклу потоків

Тут ми введемо кілька термінів: ГСЧ надає довгу послідовність (псевдо) випадкових
числа. Довжина цієї послідовності називається цикл or period, після чого
ГСЧ повториться. Цю послідовність можна розбити на неперехідні потоки.
потік ГСЧ – це безперервна підмножина або блок послідовності ГСЧ. Наприклад, якщо
Період ГСЧ має довжину 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.6x10^{22}. Період всього генератора 3.1x10^{57}.

Клас ns3::RandomVariableStream є відкритим інтерфейсом цього базового випадкового числа
генератор. Коли користувачі створюють нові випадкові величини (наприклад ns3::UniformRandomVariable,
ns3::ExponentialRandomVariable, тощо), вони створюють об’єкт, який використовує один із
окремі, незалежні потоки генератора випадкових чисел. Тому кожен об’єкт о
тип ns3::RandomVariableStream має, концептуально, свій «віртуальний» ГСЧ. Крім того,
кожен ns3::RandomVariableStream можна налаштувати на використання одного з набору намальованих підпотоків
від основного потоку.

Альтернативною реалізацією було б дозволити кожній RandomVariable мати свою власну
(різний засіяний) ГСЧ. Однак ми не можемо гарантувати, що вони відрізняються
в такому випадку послідовності були б некорельованими; отже, ми вважаємо за краще використовувати один ГСЧ і
потоки та підпотоки з нього.

створення випадковий змінні
нс-3 підтримує ряд об'єктів випадкових змінних з базового класу
RandomVariableStream. Ці об’єкти походять від ns3::Об'єкт і обробляються розумними
покажчики.

Правильним способом створення цих об’єктів є використання шаблонів CreateObject<> Метод,
такої як:

Ptr x = Створити об'єкт ();

тоді ви можете отримати доступ до значень, викликавши методи для об'єкта, такі як:

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 = Створити об'єкт ();
Ptr y = Створити об'єкт ();
...

Що краще, встановити нове початкове значення чи розширити стан підпотоку? Немає
гарантувати, що потоки, створені двома випадковими насінням, не перекриватимуться. Єдиний шлях до
Гарантувати, що два потоки не перекриваються, є використання можливостей підпотоку, наданих
реалізація ГСЧ. Таким чином, використання підпотік можливості до виробляти множинний
незалежний пробіжки of то ж симуляція Іншими словами, статистично більш строгий
Спосіб конфігурації кількох незалежних реплікацій полягає в тому, щоб використовувати фіксований початковий код і просуватися
номер прогону. Ця реалізація допускає незалежність максимум 2.3x10^{15}
реплікації з використанням підпотоків.

Для зручності використання немає необхідності контролювати кількість посівного матеріалу та прогону зсередини
програма; користувач може встановити NS_GLOBAL_VALUE змінна середовища наступним чином:

$ NS_GLOBAL_VALUE="RngRun=3" ./waf --запустити назву програми

Інший спосіб контролювати це – передати аргумент командного рядка; оскільки це нс-3
Примірник GlobalValue еквівалентно робиться так:

$ ./waf --command-template="%s --RngRun=3" --виконати назву програми

або, якщо ви запускаєте програми безпосередньо за межами waf:

$ ./build/optimized/scratch/program-name --RngRun=3

Наведені вище варіанти командного рядка дозволяють легко запускати багато різних запусків з оболонки
сценарій, просто передаючи інший індекс RngRun.

Клас RandomVariableStream
Усі випадкові величини мають походити від класу Випадкова змінна. Цей базовий клас забезпечує a
кілька методів глобального налаштування поведінки генератора випадкових чисел. Похідне
класи надають API для малювання випадкових змін від конкретного дистрибутива
підтримується.

Кожен RandomVariableStream, створений під час моделювання, отримує новий генератор
RNGSstream із базового PRNG. Використовується таким чином реалізація L'Ecuyer
дозволяє використовувати максимум 1.8x10^19 випадкових величин. Кожна випадкова величина в одній
реплікація може створити до 7.6x10^22 випадкових чисел перед накладанням.

База клас громадськість API
Нижче наведено кілька відкритих методів класу RandomVariableStream які мають доступ до
наступне значення в підпотоці.

/ **
* \brief Повертає випадкове подвійне значення з базового розподілу
* \return Випадкове значення з плаваючою комою
*/
подвійне GetValue (void) const;

/ **
* \brief Повертає випадкове ціле число з основного розподілу
* \return Цілочисельне приведення ::GetValue()
*/
uint32_t GetInteger (void) const;

Ми вже описали конфігурацію висіву вище. Різна випадкова змінна
підкласи можуть мати додатковий API.

типи of Випадкові змінні
Наведені такі типи випадкових величин, які задокументовані в нс-3
Доксиген або читаючи src/core/model/random-variable-stream.h. Користувачі також можуть створювати
їхні власні випадкові величини, отримані від класу RandomVariableStream.

· клас UniformRandomVariable

· клас ConstantRandomVariable

· клас Послідовна RandomVariable

· клас Експоненціальна RandomVariable

· клас Випадкова змінна Парето

· клас WeibullRandomVariable

· клас Нормальна RandomVariable

· клас LogNormalRandomVariable

· клас GammaRandomVariable

· клас ErlangRandomVariable

· клас Трикутна RandomVariable

· клас ZipfRandomVariable

· клас ZetaRandomVariable

· клас Детермінована Випадкова змінна

· клас Емпірична RandomVariable

Семантика of RandomVariableStream об'єкти
Об’єкти RandomVariableStream є похідними від ns3::Об'єкт і обробляються розумними покажчиками.

Примірники RandomVariableStream також можна використовувати в нс-3 атрибути, що означає, що
значення можуть бути встановлені для них за допомогою нс-3 атрибутивна система. Приклад є в
моделі поширення для WifiNetDevice:

TypeId
RandomPropagationDelayModel::GetTypeId (недійсний)
{
static TypeId tid = TypeId ("ns3::RandomPropagationDelayModel")
.SetParent ()
.AddConstructor ()
.AddAttribute ("Змінна",
"Випадкова величина, яка генерує випадкові затримки (s).",
StringValue ("ns3::UniformRandomVariable"),
MakePointerAccessor (&RandomPropagationDelayModel::m_variable),
MakePointerChecker ())
;
повертатися до їжі;
}

Ось тут нс-3 користувач може змінити випадкову величину за замовчуванням для цієї моделі затримки (яка
UniformRandomVariable в діапазоні від 0 до 1) через систему атрибутів.

використання Інше PRNG
Наразі немає підтримки заміни іншого базового випадкового числа
генератор (наприклад, Наукова бібліотека GNU або пакет Akaroa). Патчі вітаються.

Установка потік номер
Базовий генератор MRG32k3a забезпечує 2^64 незалежних потоку. У ns-3 це
призначаються послідовно, починаючи з першого потоку як нові екземпляри RandomVariableStream
зробити перший виклик GetValue().

У результаті того, як ці об’єкти RandomVariableStream призначаються основним потокам,
призначення є чутливим до збурень конфігурації моделювання. The
Наслідком є ​​те, що якщо будь-який аспект конфігурації моделювання змінюється, відображення
випадкових змінних до потоків може (або не може) змінитися.

Як конкретний приклад, користувач, який проводить порівняльне дослідження між протоколами маршрутизації, може
виявити, що акт зміни одного протоколу маршрутизації на інший помітить, що
основний шаблон мобільності також змінився.

Починаючи з 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 означає, що значення буде
автоматично розподіляється).

Видавничий ваш результати
Коли ви публікуєте результати моделювання, ключову частину конфігураційної інформації ви
завжди має вказувати, як ви використовували генератор випадкових чисел.

· яке насіння ви використовували,

· який ГСЧ ви використовували, якщо не стандартний,

· як виконувались самостійні забіги,

· для великих симуляцій, як ви перевірили, що ви не робите цикл.

Дослідник, який публікує результати, зобов’язаний включити достатньо інформації, щоб
дозволити іншим відтворити його чи її результати. На дослідника також покладається обов’язок
переконати себе, що використані випадкові числа були статистично дійсними, і заявити в
папір, чому припускається така впевненість.

Підсумки
Давайте розглянемо, що потрібно робити під час створення симуляції.

· Вирішіть, чи працюєте ви з фіксованим початковим чи випадковим; фіксованим насінням є
за замовчуванням,

· Вирішіть, як ви збираєтеся керувати незалежними реплікаціями, якщо це можливо,

· Переконайте себе, що ви малюєте не більше випадкових значень, ніж довжина циклу, якщо
ви виконуєте дуже довге моделювання, і

· Коли ви публікуєте, дотримуйтесь наведених вище вказівок щодо документування використання випадкових даних
генератор чисел.

Мішанина Функції
нс-3 надає загальний інтерфейс до хеш-функцій загального призначення. У найпростішому
використання, хеш-функція повертає 32-розрядний або 64-розрядний хеш буфера даних або рядка.
Базовою хеш-функцією за замовчуванням є бурчання3, вибрано, тому що має гарну хеш-функцію
властивостей і пропонує 64-розрядну версію. Поважний FNV1a також доступний хеш.

Існує простий механізм для додавання (або надання під час виконання) альтернативного хешу
реалізації функцій.

Базовий Використання
Найпростіший спосіб отримати хеш-значення буфера даних або рядка:

#include "ns3/hash.h"

використання простору імен ns3;

char * буфер = ...
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 * буфер;
size_t buffer_size;

хешер хешер; // Використовувати хеш-функцію за замовчуванням

для ( )
{
буфер = get_next_buffer ();
хешер (buffer, buffer_size);
}
uint32_t combination_hash = hasher.GetHash32 ();

За замовчуванням Хешер зберігає внутрішній стан, щоб увімкнути інкрементне хешування. Якщо ти хочеш
повторно використовувати а Хешер об'єкта (наприклад, тому що він налаштований на хеш, який не є за замовчуванням
функція), але не хочете додавати до раніше обчисленого хешу, вам потрібно ясно ()
перший:

hasher.clear ().GetHash32 (буфер, розмір_буфера);

Це повторно ініціалізує внутрішній стан перед хешуванням буфера.

використання an Alternative Мішанина функція
Хеш-функцією за замовчуванням є бурчання3. FNV1a також доступний. Щоб вказати хеш
функції явно, використовуйте цей конструктор:

Хешер хешер = Хешер (Створити () );

Додавання Нові Мішанина функція Впровадження
Щоб додати хеш-функцію Foo, дотримуйтесь hash-murmur3.h/. CC Візерунок:

· Створити декларацію класу (.h) і визначення (. CC) успадкування від
Хеш::Реалізація.

· включати декларація в hash.h (у місці, де hash-murmur3.h включено.

· У вашому власному коді створіть екземпляр a Хешер об'єкт через конструктор Хешер
(Птр ())

Якщо ваша хеш-функція є однією функцією, напр хашф, вам навіть не потрібно створювати a
новий клас, отриманий від HashImplementation:

Хешер хешер =
Хешер (Створити (&hashf) );

Щоб це скомпілювати, ваш хашф має відповідати одній із сигнатур вказівника функції:

typedef uint32_t (*Hash32Function_ptr) (const char *, const size_t);
typedef uint64_t (*Hash64Function_ptr) (const char *, const size_t);

Джерела та цінності Мішанина Функції
Джерела для інших реалізацій хеш-функції включають:

· Петро Канковскі: http://www.strchr.com

· Араш Партоу: http://www.partow.net/programming/hashfunctions/index.html

· SMHasher: http://code.google.com/p/smhasher/

· Санмайце: http://www.sanmayce.com/Fastest_Hash/index.html

Події та імітатор
нс-3 є симулятором мережі з дискретними подіями. Концептуально, симулятор відстежує a
кількість подій, які планується виконати в заданий час моделювання. Робота
симулятор повинен виконувати події в послідовному часовому порядку. Після завершення
настає подія, симулятор перейде до наступної події (або вийде, якщо її немає
більше подій у черзі подій). Якщо, наприклад, подія, запланована на час моделювання
«100 секунд» виконується, і наступна подія не запланована до «200 секунд»,
симулятор негайно перескочить зі 100 секунд до 200 секунд (часу симуляції) до
виконати наступну подію. Саме це мається на увазі під симулятором «дискретних подій».

Щоб усе це сталося, симулятору потрібно кілька речей:

1. об'єкт-симулятор, який може отримати доступ до черги подій, де зберігаються події
керувати виконанням заходів

2. планувальник, відповідальний за вставку та видалення подій з черги

3. спосіб представлення часу моделювання

4. самі події

У цьому розділі посібника описані ці фундаментальні об’єкти (симулятор, планувальник,
час, подія) і як вони використовуються.

Event
До be завершений

імітатор
Клас Simulator є загальнодоступною точкою входу для доступу до засобів планування подій. один раз
Для початку моделювання заплановано кілька подій, які користувач може почати
виконати їх, увійшовши в головний цикл симулятора (виклик Симулятор::Біг). Після основної петлі
почне працювати, він послідовно виконуватиме всі заплановані події в порядку від найстарішого до
останнє, доки в черзі подій більше не залишиться, або
Симулятор::Стоп викликано.

Для планування подій для виконання головним циклом симулятора передбачено клас 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 Schedule автоматично розпізнають функції та методи, лише якщо вони
взяти менше 5 аргументів. Якщо вам потрібні додаткові аргументи, подайте а
повідомлення про помилку.

· Читачі, знайомі з терміном «повністю зв'язані функтори», впізнають
Методи Simulator::Schedule як спосіб автоматичного створення таких об'єктів.

2. Загальні операції планування

Симулятор API був розроблений, щоб спростити планування більшості подій. Це
надає три варіанти для цього (впорядковані від найбільш часто використовуваного до найменш вживаного):

· Методи розкладу, які дозволяють вам запланувати подію на майбутнє, надавши
затримка між поточним часом моделювання та датою закінчення цільової події.

· Методи ScheduleNow, які дозволяють запланувати подію для поточної симуляції
час: вони виконуватимуться _після_ завершення поточної події, але _до_
час моделювання змінюється для наступної події.

· Методи ScheduleDestroy, які дозволяють підключити процес вимкнення Симулятора
для очищення ресурсів моделювання: кожна подія 'destroy' виконується, коли користувач викликає
метод Simulator::Destroy.

3. Підтримка контексту моделювання

Існує два основних способи планування подій: з і без контекст. Що це робить
значить?

Симулятор::Розклад (Time const &time, MEM mem_ptr, OBJ obj);

проти

Симулятор::ScheduleWithContext (контекст uint32_t, Time const &time, MEM mem_ptr, OBJ obj);

Читачі, які вкладають час і зусилля в розробку або використання нетривіальної імітаційної моделі
знатимуть цінність фреймворку реєстрування ns-3 для налагодження простих і складних симуляцій
однаково. Однією з важливих функцій, які надає ця структура ведення журналів, є
автоматичне відображення ідентифікатора мережевого вузла, пов'язаного з подією, що виконується "на даний момент".

Ідентифікатор вузла поточного виконуваного вузла мережі фактично відстежується Симулятором
клас. До нього можна отримати доступ за допомогою методу Simulator::GetContext, який повертає
"контекст" (32-розрядне ціле число), пов'язаний і збережений у події, що виконується в даний момент. в
деякі рідкісні випадки, коли подія не пов’язана з певним вузлом мережі, її
"контекст" має значення 0xffffffff.

Для автоматичного зв’язування контексту з кожною подією методи Schedule і ScheduleNow
повторно використовувати контекст події, що виконується, як контекст запланованої події
для виконання пізніше.

У деяких випадках, особливо при моделюванні передачі пакету від вузла до
інша, така поведінка небажана, оскільки очікуваний контекст події прийому є
вузла-одержувача, а не вузла-відправника. Щоб уникнути цієї проблеми, симулятор
клас забезпечує конкретний метод розкладу: ScheduleWithContext, який дозволяє надати
явно ідентифікатор вузла одержувача, пов'язаного з подією отримання.

XXX: код приклад

У деяких дуже рідкісних випадках розробникам може знадобитися змінити або зрозуміти, як контекст
(ідентифікатор вузла) першої події встановлюється на відповідний вузол. Це досягнуто
класом NodeList: щоразу, коли створюється новий вузол, використовується клас NodeList
ScheduleWithContext, щоб запланувати подію "ініціалізації" для цього вузла. Подія «ініціалізація».
таким чином, виконується з контекстом, встановленим у контексті ідентифікатора вузла, і може використовувати звичайну різноманітність
Методи розкладу. Він викликає метод Node::Initialize, який поширює 'initialize'
події шляхом виклику методу DoInitialize для кожного об’єкта, пов’язаного з вузлом. The
Метод DoInitialize замінено в деяких з цих об’єктів (особливо в Application
базовий клас) планує деякі події (зокрема Application::StartApplication), які
у свою чергу планує події генерації трафіку, які в свою чергу планують
події на рівні мережі.

Примітки:

· Користувачі повинні бути обережними, щоб поширювати методи DoInitialize між об'єктами шляхом виклику
Явно ініціалізуйте їх об’єкти-члени

· Ідентифікатор контексту, пов'язаний з кожним методом ScheduleWithContext, має інші можливості використання
реєстрація: використовується експериментальною гілкою ns-3 для виконання паралельного моделювання на
багатоядерні системи, що використовують багатопоточність.

Функції Simulator::* не знають, що таке контекст: вони лише переконаються в цьому
будь-який контекст, який ви вкажете за допомогою ScheduleWithContext, доступний, коли відповідний
подія виконується за допомогою ::GetContext.

Інтерпретація значення контексту залежить від моделей, реалізованих поверх Simulator::*.
У ns-3 моделі мережі інтерпретують контекст як ідентифікатор вузла вузла, який
створив подію. Ось чому важливо викликати ScheduleWithContext
ns3::Channel підкласи, оскільки ми генеруємо подію від вузла i до вузла j, і ми
ви хочете переконатися, що подія, яка запускатиметься на вузлі j, має правильний контекст.

Time
До be завершений

Планувальник
До be завершений

Зворотні дзвінки
Деякі нові користувачі нс-3 не знайомі з широко використовуваною програмною ідіомою
по всьому коду: the нс-3 Як передзвонити. Цей розділ містить певну мотивацію щодо
зворотний виклик, рекомендації щодо використання та деталі щодо його реалізації.

Зворотні дзвінки мотивація
Вважайте, що у вас є дві імітаційні моделі A і B, і ви хочете, щоб вони проходили
інформацію між ними під час моделювання. Один із способів зробити це – це ви
може зробити A і B чітко обізнаними про іншого, щоб вони могли викликати
методи один на одного:

клас A {
громадськості:
void ReceiveInput ( // параметри);
...
}

(в іншому вихідному файлі :)

клас B {
громадськості:
void DoSomething (пустота);
...

private:
A* a_instance; // вказівник на A
}

анулювати
B::Зробіть щось()
{
// Повідомити a_instance, що щось сталося
a_instance->ReceiveInput ( // параметри);
...
}

Це, безумовно, працює, але має той недолік, що вводить залежність від А і В
знати про іншого під час компіляції (це ускладнює створення незалежного
одиниці складання в тренажері) і не є узагальненим; якщо в наступному сценарії використання,
B повинен спілкуватися з абсолютно іншим об'єктом C, вихідний код для B повинен бути
змінено, щоб додати a c_екземпляр і так далі. Легко помітити, що це груба сила
Механізм зв'язку, який може призвести до програмування крихти в моделях.

Це не означає, що об’єкти не повинні знати один про одного, якщо є жорсткий
залежність між ними, але часто модель можна зробити більш гнучкою, якщо її
взаємодії менш обмежені під час компіляції.

Це не абстрактна проблема для дослідження мережевого моделювання, а скоріше це була проблема
джерело проблем у попередніх симуляторах, коли дослідники хочуть розширити або змінити
система робити різні речі (як вони схильні робити в дослідженні). Розглянемо, наприклад,
користувач, який хоче додати підрівень протоколу безпеки IPsec між TCP та IP:

------------ -----------
| TCP | | TCP |
------------ -----------
| стає -> |
----------- -----------
| IP | | IPsec |
----------- -----------
|
-----------
| IP |
-----------

Якщо симулятор зробив припущення та жорстко запрограмований у код, цей IP завжди говорить
до транспортного протоколу вище, користувач може бути змушений зламати систему, щоб отримати
бажані взаємозв'язки. Очевидно, що це не оптимальний спосіб розробки генерика
тренажер.

Зворотні дзвінки фон
ПРИМІТКА:
Читачі, знайомі з програмуванням зворотних викликів, можуть пропустити цей розділ підручника.

Основний механізм, який дозволяє вирішити вищезазначену проблему, відомий як a Як передзвонити.
Кінцева мета - дозволити одному фрагменту коду викликати функцію (або метод в C++)
без будь-якої конкретної міжмодульної залежності.

Це в кінцевому підсумку означає, що вам потрібен якийсь непрямий напрямок - ви обробляєте адресу
називається функцією як змінною. Ця змінна називається змінною вказівника на функцію.
Зв'язок між функцією та вказівником вказівник на функцію насправді нічим не відрізняється
що для об’єкта та вказівника на об’єкт.

У C канонічним прикладом вказівника на функцію є a
покажчик на функцію, що повертає ціле число (PFI). Для PFI, що приймає один параметр int, це
може бути оголошено як:

int (*pfi)(int arg) = 0;

З цього ви отримуєте змінну з простим ім’ям pfi яке ініціалізовано значенням 0.
Якщо ви хочете ініціалізувати цей покажчик на щось значуще, вам потрібно мати a
функція з відповідним підписом. В цьому випадку:

int MyFunction (int arg) {}

Якщо у вас є ця ціль, ви можете ініціалізувати змінну, щоб вона вказувала на вашу функцію, наприклад:

pfi = Моя функція;

Потім ви можете викликати MyFunction опосередковано, використовуючи більш привабливу форму виклику:

int результат = (*pfi) (1234);

Це наводить на думку, оскільки схоже, що ви просто розіменовуєте покажчик функції
як ви б розіменували будь-який покажчик. Однак, як правило, люди користуються цим
факт, що компілятор знає, що відбувається, і буде використовувати коротшу форму:

int результат = pfi (1234);

Зверніть увагу, що вказівник функції підпорядковується семантиці значення, тому ви можете передавати його як будь-який інший
інше значення. Зазвичай, коли ви використовуєте асинхронний інтерфейс, ви передаєте якусь сутність
як це до функції, яка виконуватиме дію і call назад щоб ви це знали
завершено. Він здійснює зворотний виклик, дотримуючись інструкції та виконуючи надану функцію.

У C++ у вас є додаткова складність об’єктів. Наведена вище аналогія з PFI означає вас
мати вказівник на функцію-член, яка повертає int (PMI) замість покажчика на
функція, яка повертає int (PFI).

Оголошення змінної, що забезпечує опосередкованість, виглядає лише трохи інакше:

int (MyClass::*pmi) (int arg) = 0;

Це оголошує змінну з іменем PMI так само, як у попередньому прикладі було оголошено змінну з назвою
pfi. Оскільки метод буде викликати метод екземпляра певного класу, необхідно
оголосити цей метод у класі:

клас MyClass {
громадськості:
int MyMethod (int arg);
};

З огляду на це оголошення класу, можна було б ініціалізувати цю змінну таким чином:

pmi = &MyClass::MyMethod;

Це призначає адресу коду, що реалізує метод, змінній, що завершує
опосередкованість. Щоб викликати метод, код потребує a це покажчик. Це, у свою чергу,
означає, що має бути об’єкт MyClass, на який можна посилатися. Спрощений приклад цього просто
непрямий виклик методу (думайте, віртуальна функція):

int (MyClass::*pmi) (int arg) = 0; // Оголосити PMI
pmi = &MyClass::MyMethod; // Вказуємо на код реалізації

MyClass мійClass; // Потрібен екземпляр класу
(myClass.*pmi) (1234); // Викликаємо метод з об'єктом ptr

Як і в прикладі C, ви можете використовувати це в асинхронному виклику іншого модуля
який буде call назад використання методу та покажчика на об’єкт. Просте розширення
можна розглянути можливість передати покажчик на об’єкт і змінну PMI. Модуль
просто зробив би:

(*objectPtr.*pmi) (1234);

щоб виконати зворотний виклик для потрібного об’єкта.

У цей час можна запитати, що таке точка? Викликаний модуль повинен розібратися
конкретний тип об'єкта, що викликає, щоб правильно здійснити зворотний виклик. Чому ні
просто прийміть це, передайте правильно введений покажчик об’єкта та зробіть об'єкт->Метод(1234) in
код замість зворотного виклику? Це саме проблема, описана вище. Що
необхідний спосіб повністю відокремити функцію, що викликає, від викликаного класу. Це
вимога привела до розвитку с Функціонер.

Функтор є результатом чогось, винайденого в 1960-х роках, і називається замиканням. це є
в основному просто запакований виклик функції, можливо, з деяким станом.

Функтор має дві частини, специфічну частину і загальну частину, пов’язані через успадкування.
Код виклику (код, який виконує зворотний виклик) виконає загальний перевантажений
оператор () загального функтора, щоб викликати зворотний виклик. Код, що викликається (
код, який хоче бути викликаний) доведеться надати спеціалізовану реалізацію
оператор () який виконує специфічну для класу роботу, яка спричинила тісне з’єднання
проблема вище.

З конкретним функтором і його перевантаженим оператор () створений, викликаний код потім
надає спеціалізований код модулю, який буде виконувати зворотний виклик (виклик
код).

Викликаючий код візьме загальний функтор як параметр, тому виконується неявне приведення
у виклику функції для перетворення конкретного функтора в загальний функтор. Це означає
що модуль, що викликає, просто повинен зрозуміти загальний тип функтора. Він роз’єднаний
з коду виклику повністю.

Інформація, необхідна для створення конкретного функтора, — це вказівник на об’єкт і значення
адреса вказівника на метод.

Суть того, що має статися, полягає в тому, що система оголошує загальну частину
функтор:

шаблон
клас Функтор
{
громадськості:
virtual int operator() (T arg) = 0;
};

Викликаючий визначає конкретну частину функтора, яку дійсно потрібно реалізувати
конкретне Оператор () метод:

шаблон
клас SpecificFunctor : публічний Функтор
{
громадськості:
SpecificFunctor(T* p, int (T::*_pmi)(ARG arg))
{
m_p = p;
m_pmi = _pmi;
}

virtual int operator() (ARG arg)
{
(*m_p.*m_pmi)(arg);
}
private:
int (T::*m_pmi)(ARG arg);
T* m_p;
};

Ось приклад використання:

клас А
{
громадськості:
A (int a0) : a (a0) {}
int Привіт (int b0)
{
std::cout << "Привіт від A, a = " << a << " b0 = " << b0 << std::endl;
}
int a;
};

int main ()
{
A a(10);
SpecificFunctor sf(&a, &A::Привіт);
sf(5);
}

ПРИМІТКА:
Попередній код не є справжнім кодом ns-3. Це спрощений приклад коду, який використовується лише для
проілюструвати залучені концепції та допомогти вам краще зрозуміти систему. Не
очікуйте знайти цей код у будь-якому місці дерева ns-3.

Зверніть увагу, що в наведеному вище класі визначено дві змінні. Змінною m_p є
покажчик об'єкта, а m_pmi — змінна, що містить адресу функції
виконати.

Зверніть увагу, що коли Оператор () викликається, він, у свою чергу, викликає метод, наданий разом із
покажчик об'єкта з використанням синтаксису C++ PMI.

Щоб використовувати це, можна було б оголосити деякий код моделі, який приймає загальний функтор як a
параметр:

void LibraryFunction (функтор функтора);

Код, який буде спілкуватися з моделлю, буде створювати певний функтор і передавати його
Функція бібліотеки:

MyClass мійClass;
SpecificFunctor функтор (&myclass, MyClass::MyMethod);

Коли Функція бібліотеки виконано, він виконує зворотний виклик за допомогою Оператор () на загальний
функтор, який було передано, і в цьому конкретному випадку надає цілочисельний аргумент:

анулювати
LibraryFunction (функтор функтора)
{
// Виконати бібліотечну функцію
функтор(1234);
}

Зверніть увагу на це Функція бібліотеки повністю відокремлений від конкретного типу клієнта.
Зв'язок здійснюється через поліморфізм Функтора.

API зворотного дзвінка в нс-3 реалізує об'єктно-орієнтовані зворотні виклики за допомогою механізму функтора.
Цей API зворотного виклику, заснований на шаблонах C++, є безпечним для типів; тобто виконує статику
перевірка типу для забезпечення належної сумісності підписів між абонентами та абонентами, які викликають. це є
тому безпечніший у використанні, ніж традиційні покажчики функцій, але синтаксис може
спочатку виглядати імпозантно. Цей розділ розроблено, щоб ознайомитися з системою зворотного дзвінка
щоб вам було зручно ним користуватися нс-3.

використання Callback API
API зворотного дзвінка досить мінімальний, надає лише дві послуги:

1. оголошення типу зворотного виклику: спосіб оголосити тип зворотного виклику з заданим підписом,
і,

2. Створення екземпляра зворотного виклику: спосіб створення екземпляра зворотного виклику переадресації, згенерованого шаблоном
який може переадресовувати будь-які виклики до іншого методу-члена класу C++ або функції C++.

Найкраще це спостерігати за допомогою огляду прикладу на основі samples/main-callback.cc.

використання Callback API з статичний Функції
Розглянемо функцію:

статичний подвійний
CbOne (подвійний a, подвійний b)
{
std::cout << "викликати cbOne a=" << a << ", b=" << b << std::endl;
повернути a;
}

Розглянемо також такий основний фрагмент програми:

int main (int argc, char *argv[])
{
// тип повернення: подвійний
// перший тип аргументу: подвійний
// другий тип аргументу: подвійний
Зворотній дзвінок один;
}

Це приклад зворотного виклику в стилі C, який не містить або потребує a це
покажчик. Шаблон функції Callback по суті, це оголошення змінної
містить вказівник на функцію. У наведеному вище прикладі ми явно показали покажчик
до функції, яка повертає ціле число і приймає одне ціле число як параметр, The
Callback Функція шаблону є загальною версією цього – вона використовується для оголошення типу
зворотного дзвінка.

ПРИМІТКА:
Читачі, які не знайомі з шаблонами C++, можуть отримати консультацію
http://www.cplusplus.com/doc/tutorial/templates/.

Команда Callback шаблон вимагає одного обов'язкового аргументу (типу повернення функції до
бути призначено цьому зворотному виклику) і до п’яти необов’язкових аргументів, кожен із яких визначає
тип аргументів (якщо ваша конкретна функція зворотного виклику має більше п'яти аргументів,
тоді це можна вирішити, розширивши реалізацію зворотного виклику).

Отже, у наведеному вище прикладі ми оголосили зворотний виклик з ім’ям «one», який зрештою буде
утримувати вказівник функції. Сигнатура функції, яку вона буде утримувати, повинна повернути
double і має підтримувати два подвійних аргументи. Якщо спробувати передати функцію чия
підпис не відповідає оголошеному зворотному виклику, виникне помилка компіляції. Також, якщо
хтось намагається призначити зворотному виклику несумісний, компіляція буде успішною, але a
часу виконання NS_FATAL_ERROR буде ініційовано. Зразок програми
src/core/examples/main-callback.cc демонструє обидва ці випадки помилки в кінці
main () програми.

Тепер нам потрібно зв’язати цей екземпляр зворотного виклику та фактичну цільову функцію
(CbOne). Зауважте вище, що CbOne має ті ж типи сигнатур функцій, що й зворотний виклик--
це важливо. Ми можемо передати будь-яку таку правильно набрану функцію до цього зворотного виклику.
Давайте розглянемо це докладніше:

статичний подвійний CbOne (подвійний a, подвійний b) {}
^ ^ ^
| | |
| | |
Зворотній дзвінок один;

Ви можете прив’язати функцію до зворотного виклику, лише якщо вона має відповідний підпис. Перший
Аргумент шаблону є типом повернення, а додаткові аргументи шаблону є типами
аргументів сигнатури функції.

Тепер давайте прив’яжемо наш зворотний виклик «один» до функції, яка відповідає її сигнатурі:

// створюємо екземпляр зворотного виклику, який вказує на функцію cbOne
one = MakeCallback (&CbOne);

Цей дзвінок до MakeCallback є, по суті, створенням одного із спеціалізованих функторів
вищезгаданий. Змінна, оголошена за допомогою Callback функція шаблону збирається
грати роль загального функтора. Завдання один = MakeCallback (&CbOne) is
приведення, яке перетворює спеціалізований функтор, відомий викликаному, у загальний функтор
відомий абоненту.

Потім, пізніше в програмі, якщо потрібен зворотний виклик, його можна використовувати наступним чином:

NS_ASSERT (!one.IsNull ());

// виклик функції cbOne через екземпляр зворотного виклику
подвійний retOne;
retOne = один (10.0, 20.0);

Чек на IsNull() гарантує, що зворотний виклик не є нульовим - що існує функція
щоб зателефонувати за цим зворотним викликом. Тоді, один () виконує загальний Оператор () що насправді є
перевантажений конкретною реалізацією Оператор () і повертає той самий результат, ніби
CbOne() був викликаний безпосередньо.

використання Callback API з член Функції
Як правило, ви будете викликати не статичні функції, а натомість публічні функції-члени
об'єкт. У цьому випадку для функції MakeCallback потрібен додатковий аргумент, щоб
вкажіть системі, на якому об’єкті слід викликати функцію. Розглянемо цей приклад,
також з main-callback.cc:

клас MyCb {
громадськості:
int CbTwo (double a) {
std::cout << "викликати cbTwo a=" << a << std::endl;
return -5;
}
};

intmain()
{
...
// тип повернення: int
// перший тип аргументу: подвійний
Зворотній дзвінок два;
MyCb cb;
// створюємо екземпляр зворотного виклику, який вказує на MyCb::cbTwo
два = MakeCallback (&MyCb::CbTwo, &cb);
...
}

Тут ми передаємо додатковий покажчик на об’єкт до MakeCallback<> функція. Відкликання з
розділ фону над цим Оператор() використовуватиме вказівник на синтаксис члена, коли він
виконує на об'єкті:

virtual int operator() (ARG arg)
{
(*m_p.*m_pmi)(arg);
}

Тому нам потрібно було надати дві змінні (m_p та m_pmi), коли ми зробили конкретне
функтор. Лінія:

два = MakeCallback (&MyCb::CbTwo, &cb);

робить саме це. В даному випадку, коли два () викликається:

int результат = два (1.0);

призведе до виклику CbTwo функція-член (метод) для об’єкта, на який вказує
&cb.

Обладнання для прокату Null Зворотні дзвінки
Зворотні виклики можуть бути нульовими; тому, можливо, буде розумно перевірити перед їх використанням.
Існує спеціальна конструкція для нульового зворотного виклику, яка краще, ніж просто передача
«0» як аргумент; це MakeNullCallback<> побудова:

два = MakeNullCallback ();
NS_ASSERT (два.IsNull ());

Виклик нульового зворотного виклику так само, як виклик нульового вказівника функції: він аварійно завершить роботу на
час виконання.

Кордон Зворотні дзвінки
Дуже корисним розширенням концепції функтора є зв'язаний зворотний виклик. Раніше це
було згадано, що закриття спочатку були викликами функцій, запакованими на потім
виконання. Зверніть увагу, що в усіх описах зворотного виклику, наведених вище, немає способу
упакуйте будь-які параметри для використання пізніше - коли Callback називається через Оператор ().
Усі параметри надаються функцією виклику.

Що робити, якщо потрібно дозволити клієнтській функції (тій, яка забезпечує зворотний виклик).
надати деякі параметри? Александреску викликає процес дозволу клієнту
вкажіть один з параметрів "зв'язування". Один з параметрів Оператор () було
зв'язаний (фіксований) клієнтом.

Деякі з наших кодів трасування pcap є гарним прикладом цього. Є функція, яка
потрібно викликати щоразу, коли отримується пакет. Ця функція викликає об’єкт that
фактично записує пакет на диск у форматі файлу pcap. Підпис одного з них
функції будуть:

static void DefaultSink (Ptr файл, Ptr р);

Ключове слово static означає, що це статична функція, яка не потребує a це покажчик, так
він буде використовувати зворотні виклики в стилі C. Ми не хочемо, щоб телефонний код знав про нього
будь-що, крім пакета. Те, що ми хочемо в коді виклику, це просто виклик, який виглядає так:

m_promiscSnifferTrace (m_currentPkt);

Те, що ми хочемо зробити, це зробити пов'язувати Ptr файл до конкретного зворотного виклику
реалізація, коли вона створюється та організовується Оператор () зворотного дзвінка до
надайте цей параметр безкоштовно.

Ми надаємо MakeBoundCallback функцію шаблону для цієї мети. Потрібно те ж саме
параметри як MakeCallback функцію шаблону, але також приймає параметри
зв'язаний. У випадку наведеного вище прикладу:

MakeBoundCallback (&DefaultSink, файл);

створить конкретну реалізацію зворотного виклику, яка знає, як додати додаткову межу
аргументи. Концептуально він розширює спеціальний функтор, описаний вище, одним або кількома
зв'язані аргументи:

шаблон
клас SpecificFunctor : публічний Функтор
{
громадськості:
SpecificFunctor(T* p, int (T::*_pmi)(ARG arg), BOUND_ARG boundArg)
{
m_p = p;
m_pmi = pmi;
m_boundArg = boundArg;
}

virtual int operator() (ARG arg)
{
(*m_p.*m_pmi)(m_boundArg, arg);
}
private:
void (T::*m_pmi)(ARG arg);
T* m_p;
BOUND_ARG m_boundArg;
};

Ви можете побачити, що коли створено певний функтор, зв’язаний аргумент зберігається в файлі
сам функтор/об'єкт зворотного виклику. Коли Оператор () викликається разом із синглом
параметр, як у:

m_promiscSnifferTrace (m_currentPkt);

здійснення Оператор () додає параметр bound до фактичного виклику функції:

(*m_p.*m_pmi)(m_boundArg, arg);

Також можна зв’язати два або три аргументи. Скажімо, у нас є функція з
підпис:

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 відповідно.

Цей вид прив'язки можна використовувати для обміну інформацією між об'єктами в симуляції;
зокрема, зв’язані зворотні виклики можна використовувати як відстежені зворотні виклики, які будуть описані в
наступний розділ.

Простежити Зворотні дзвінки
Заповнювач підрозділ

Callback місць in нс-3
Де часто використовуються зворотні виклики нс-3? Ось деякі з найбільш помітних
типові користувачі:

· API сокетів

· API рівня 2/3 рівня

· Підсистема трасування

· API між IP і підсистемами маршрутизації

Реалізація деталі
Наведені вище фрагменти коду спрощені та призначені лише для ілюстрації механізму
себе. Фактичний код зворотного виклику є досить складним і дуже інтенсивним шаблоном
глибоке розуміння коду не потрібно. Якщо буде цікаво, досвідчені користувачі можуть знайти
наступне корисне.

Спочатку код був написаний на основі методів, описаних в
http://www.codeproject.com/cpp/TTLFunction.asp. Згодом його було переписано
архітектура, окреслена в Modern 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 Address & address);
Адреса &оператор = (постійна адреса &адреса);
...
private:
uint8_t m_type;
uint8_t m_len;
...
};

Об'єкт база класів
Використовуються три спеціальні базові класи нс-3. Класи, які успадковують від цієї бази
класи можуть створювати екземпляри об'єктів зі спеціальними властивостями. Ці базові класи:

· клас Об'єкт

· клас ObjectBase

· клас SimpleRefCount

Цього не вимагається нс-3 об’єкти успадковують від цих класів, але ті, які отримують
особливі властивості. Класи, що походять від класу Об'єкт отримати наступні властивості.

· нс-3 тип і система атрибутів (див. Атрибути)

· система агрегації об'єктів

· система підрахунку посилань розумного вказівника (клас Ptr)

Класи, що походять від класу ObjectBase отримати перші два властивості вище, але цього не робити
отримати розумні вказівники. Класи, що походять від класу SimpleRefCount: отримати тільки
система підрахунку посилань розумного покажчика.

На практиці клас Об'єкт є варіантом трьох вищезазначених нс-3 розробник буде
найчастіше зустрічаються.

пам'ять управління та клас Ptr
Управління пам’яттю в програмі C++ є складним процесом, який часто виконується неправильно або
непослідовно. Ми зупинилися на схемі підрахунку посилань, описаній нижче.

Усі об’єкти, які використовують підрахунок посилань, підтримують внутрішній підрахунок посилань для визначення
коли об’єкт може безпечно видалити сам себе. Кожен раз, коли отримується покажчик на
інтерфейсу, кількість посилань об’єкта збільшується за допомогою виклику Ref(). Це
обов'язок користувача покажчика явно Unref() покажчик, коли закінчено. Коли
кількість посилань падає до нуля, об’єкт видаляється.

· Коли клієнтський код отримує вказівник від самого об'єкта шляхом створення об'єкта,
або через GetObject, йому не потрібно збільшувати кількість посилань.

· Коли клієнтський код отримує вказівник з іншого джерела (наприклад, копіюючи покажчик), він повинен
call Ref() щоб збільшити кількість посилань.

· Усі користувачі покажчика об'єкта повинні викликати Unref() щоб випустити посилання.

Тягар дзвінків Unref() дещо полегшується використанням підрахунку посилань
клас розумного покажчика, описаний нижче.

Користувачі, які використовують API низького рівня, які хочуть явно виділити об’єкти, які не враховуються посилання
у купі, використовуючи оператор new, відповідають за видалення таких об'єктів.

Посилання підрахунок розумний покажчик (Ptr)
покликання Ref() та Unref() весь час було б громіздким, тому нс-3 забезпечує смарт
клас вказівника Ptr схожий на Boost::intrusive_ptr. Цей клас розумних покажчиків передбачає це
базовий тип забезпечує пару посилання та Unref методи, які очікуються
збільшувати та зменшувати внутрішній рахунок екземпляра об’єкта.

Ця реалізація дозволяє маніпулювати розумним вказівником так, ніби він був звичайним
покажчик: ви можете порівняти його з нулем, порівняти з іншими покажчиками, призначити нуль
це тощо

З цього розумного вказівника можна витягти необроблений покажчик за допомогою GetPointer()
та PeekPointer() методи

Якщо ви хочете зберегти новий об’єкт у розумному покажчику, ми рекомендуємо вам використовувати
Функції шаблону CreateObject для створення об’єкта та збереження його в розумному покажчику
уникнути витоку пам'яті. Ці функції дійсно невеликі зручні функції та їх мета
лише для того, щоб заощадити трішки тексту.

CreateObject та Створити
Об’єкти в C++ можуть створюватися статично, динамічно або автоматично. Це справедливо
та цінності нс-3 також, але деякі об’єкти в системі мають додаткові доступні рамки.
Зокрема, об’єкти, які підраховуються, зазвичай розподіляються за допомогою шаблону Create або
Метод CreateObject, як показано нижче.

Для об’єктів, що походять від класу Об'єкт:

Ptr пристрій = CreateObject ();

Будь ласка, не створюйте такі об'єкти за допомогою оператор new; створювати їх за допомогою CreateObject()
замість цього.

Для об’єктів, що походять від класу SimpleRefCount, або інші об'єкти, які підтримують використання
клас розумного покажчика, доступна шаблонна допоміжна функція, яку рекомендується використовувати:

Ptr b = Створити ();

Це просто обгортка навколо оператора new, яка правильно обробляє підрахунок посилань
системи.

Підсумовуючи, використовуйте Створюйте якщо B не є об’єктом, а лише використовує підрахунок посилань (наприклад
Пакет) і використовувати CreateObject якщо B походить від ns3::Об'єкт.

агрегування
Команда нс-3 Система агрегації об'єктів мотивується значною мірою визнанням того, що a
поширений варіант використання для нс-2 було використання успадкування та поліморфізму для розширення
протокольні моделі. Наприклад, походять спеціалізовані версії TCP, такі як RenoTcpAgent
з (і замінити функції з) класу TcpAgent.

Однак дві проблеми, які виникли в нс-2 модель – це зниження та «слабка база
класу." Пониження відноситься до процедури використання вказівника базового класу на об'єкт і
запитуючи його під час виконання, щоб дізнатися інформацію про тип, яка використовується для явного переведення покажчика
на покажчик підкласу, щоб можна було використовувати API підкласу. Слабкий базовий клас відноситься до
проблеми, які виникають, коли клас не може бути ефективно повторно використаний (похідний від), тому що це
не має необхідної функціональності, що змушує розробника змінювати базовий клас і
спричиняє поширення викликів API базового класу, деякі з яких можуть не бути семантично
правильно для всіх підкласів.

нс-3 використовує версію шаблону дизайну інтерфейсу запиту, щоб уникнути цих проблем.
Цей дизайн заснований на елементах Компонент Об'єкт Модель та GNOME Bonobo хоча
Повна сумісність змінних компонентів на двійковому рівні не підтримується і ми підтримуємо
намагалися спростити синтаксис і впливати на розробників моделей.

прикладів
агрегування приклад
вузол є хорошим прикладом використання агрегації в нс-3. Зауважте, що не є похідними
класи вузлів в нс-3 наприклад клас InternetNode. Натомість є компоненти (протоколи).
агреговані у вузол. Давайте подивимося, як деякі протоколи Ipv4 додаються до вузла.:

статична порожнеча
AddIpv4Stack(Ptr вузол)
{
Ptr ipv4 = Створити об'єкт ();
ipv4->SetNode (вузол);
node->AggregateObject (ipv4);
Ptr ipv4Impl = Створити об'єкт ();
ipv4Impl->SetIpv4 (ipv4);
node->AggregateObject (ipv4Impl);
}

Зверніть увагу, що протоколи Ipv4 створюються за допомогою CreateObject(). Потім вони агрегуються
до вузла. Таким чином базовий клас Node не потрібно редагувати, щоб дозволити користувачам
з покажчиком вузла базового класу для доступу до інтерфейсу Ipv4; користувачі можуть запитати у вузла a
покажчик на його інтерфейс Ipv4 під час виконання. Як користувач запитує вузол, описано в
наступний підрозділ.

Зауважте, що агрегувати більше ніж один об’єкт одного типу є помилкою програмування
an ns3::Об'єкт. Так, наприклад, агрегація не є варіантом для зберігання всього
активні розетки вузла.

GetObject приклад
GetObject — це безпечний для типів спосіб досягти безпечного пониження та дозволити інтерфейсам бути
знайдено на предметі.

Розглянемо покажчик вузла m_node що вказує на об’єкт Node, який має реалізацію
IPv4, раніше агрегований до нього. Клієнтський код бажає налаштувати маршрут за замовчуванням. До
зробити це, він повинен отримати доступ до об’єкта всередині вузла, який має інтерфейс для переадресації IP
конфігурації. Він виконує наступне:

Ptr ipv4 = m_node->GetObject ();

Якщо вузол насправді не має агрегованого об’єкта Ipv4, то метод буде
повернути нуль. Тому доцільно перевірити значення, що повертається з такої функції
дзвонити. У разі успіху користувач тепер може використовувати Ptr для об’єкта Ipv4, який був раніше
агреговані до вузла.

Іншим прикладом того, як можна використовувати агрегацію, є додавання необов'язкових моделей до об'єктів. Для
наприклад, існуючий об'єкт Node може мати об'єкт "Енергетична модель", агрегований до нього за адресою
час виконання (без модифікації та перекомпіляції класу вузла). Існуюча модель (наприклад, a
бездротовий мережевий пристрій) може потім «GetObject» для моделі енергії та діяти належним чином
якщо інтерфейс був або вбудований у базовий об’єкт Node, або агрегований до
це під час виконання. Однак іншим вузлам не потрібно нічого знати про енергетичні моделі.

Сподіваємося, що цей режим програмування вимагатиме від розробників набагато менше потреб у змінах
базові класи.

Об'єкт заводи
Поширеним варіантом використання є створення великої кількості об’єктів, налаштованих подібною конфігурацією. Можна неодноразово
call CreateObject() але також використовується фабрична модель дизайну нс-3 системи.
Він активно використовується в "допоміжному" API.

Клас ObjectFactory можна використовувати для створення екземплярів об’єктів та налаштування атрибутів на
ці об'єкти:

void SetTypeId (TypeId tid);
void Встановити (std::string name, const AttributeValue &value);
Ptr Створити (void) const;

Перший спосіб дозволяє використовувати нс-3 Система TypeId для визначення типу об'єктів
створений. Другий дозволяє встановлювати атрибути для об'єктів, що створюються, і
третій дозволяє створювати самі об'єкти.

Наприклад:

фабрика ObjectFactory;
// Змусити цю фабрику створювати об'єкти типу FriisPropagationLossModel
factory.SetTypeId ("ns3::FriisPropagationLossModel")
// Змусити цей заводський об'єкт змінити значення атрибута за замовчуванням, for
// згодом створені об'єкти
factory.Set ("SystemLoss", DoubleValue (2.0));
// Створити один такий об'єкт
Ptr об'єкт = фабрика.Створити ();
factory.Set ("SystemLoss", DoubleValue (3.0));
// Створити інший об'єкт з іншим SystemLoss
Ptr об'єкт = фабрика.Створити ();

Приниження
Питання, яке виникало кілька разів, таке: «Якщо у мене є покажчик базового класу (Ptr) на файл
об’єкта, і я хочу, щоб вказівник похідного класу, чи варто перевести його вниз (через динамічне переведення C++).
отримати похідний покажчик, або мені слід використовувати систему агрегації об’єктів GetObject<> ()
щоб знайти Ptr для інтерфейсу до підкласу API?"

Відповідь на це полягає в тому, що в багатьох ситуаціях обидві методики будуть працювати. нс-3 забезпечує
шаблонна функція, щоб зробити синтаксис динамічного переведення об'єктів набагато більш користувацьким
дружній:

шаблон
Ptr
DynamicCast (Ptr const&p)
{
повернути Ptr (dynamic_cast (PeekPointer (p)));
}

DynamicCast працює, коли програміст має вказівник базового типу і тестує на а
покажчик підкласу. GetObject працює під час пошуку різних агрегованих об’єктів, але також
працює з підкласами так само, як і DynamicCast. Якщо ви не впевнені, програміст повинен
використовуйте GetObject, оскільки він працює у всіх випадках. Якщо програміст знає ієрархію класів
об’єкта, що розглядається, більш прямим буде просто використовувати DynamicCast.

конфігурація та Attributes
In нс-3 симуляції, є два основних аспекти конфігурації:

· Топологія моделювання та спосіб з'єднання об'єктів.

· Значення, які використовуються моделями, створеними в топології.

У цьому розділі зосереджено на другому пункті вище: як багато значень, що використовуються в нс-3 він має
організовані, задокументовані та модифіковані нс-3 користувачів. нс-3 система атрибутів також є
підґрунтя того, як сліди та статистичні дані збираються в симуляторі.

У цій главі ми обговоримо різні способи встановлення або зміни значень
використаний нс-3 модельні об'єкти. У порядку збільшення специфічності це:

┌──────────────────────────────────┬────────────── ─────────────────────┐
│Метод │ Область застосування │
├──────────────────────────────────┼────────────── ────────────────────┤
│Встановлено значення атрибутів за замовчуванням │ Впливають на всі екземпляри │
│коли атрибути визначені в класі │. │
GetTypeId (). │ │
└─────────────────────────────────┴────────────── ─────────────────────┘

Командний рядок │ Впливати на всі майбутні випадки. │
Config::SetDefault() │ │
ConfigStore │ │
├──────────────────────────────────┼────────────── ────────────────────┤
ObjectFactory │ Впливає на всі створені екземпляри │
│ │ з заводом. │
├──────────────────────────────────┼────────────── ────────────────────┤
XHelperSetAttribute () │ Впливає на всі екземпляри, створені │
│ │ помічник. │
├──────────────────────────────────┼────────────── ────────────────────┤
MyClass::SetX () │ Змінює цей конкретний екземпляр. │
Object::SetAttribute () │ Загалом це єдина форма │
Config::Set() │ який можна запланувати змінити │
│ │ екземпляр після моделювання │
│ │ працює. │
└─────────────────────────────────┴────────────── ─────────────────────┘

Під «специфічністю» ми маємо на увазі, що методи в наступних рядках таблиці замінюють встановлені значення
за допомогою і зазвичай впливають на менше екземплярів, ніж попередні методи.

Перш ніж заглиблюватися в деталі системи значень атрибутів, допоможе переглянути деякі з них
основні властивості класу Об'єкт.

Об'єкт Про платформу
нс-3 по суті, це об'єктно-орієнтована система C++. Під цим ми маємо на увазі нові класи C++
(типи) можуть бути оголошені, визначені та підкласи, як зазвичай.

Багато нс-3 об'єкти успадковуються від Об'єкт базовий клас. Ці об’єкти мають деякі додаткові
властивості, які ми використовуємо для організації системи та покращення управління пам'яттю
наших об'єктів:

· Система «Метадані», яка пов'язує назву класу з великою кількістю мета-інформації про
об'єкт, у тому числі:

· Базовий клас підкласу,

· Набір доступних конструкторів у підкласі,

· Набір «атрибутів» підкласу,

· Чи можна встановити кожен атрибут, чи доступний лише для читання,

· Допустимий діапазон значень для кожного атрибута.

· Реалізація розумного покажчика підрахунку посилань для управління пам'яттю.

нс-3 об'єкти, які використовують систему атрибутів, є похідними від будь-якого Об'єкт or ObjectBase. Найбільш
нс-3 об’єкти, які ми обговорюватимемо Об'єкт, але деякі з них не є розумними
Структура керування пам'яттю покажчика походить від ObjectBase.

Давайте розглянемо кілька властивостей цих об'єктів.

Smart покажчики
Як введено в нс-3 підручник, нс-3 об’єкти – це пам’ять, керована a посилання
підрахунок розумний покажчик реалізація, клас Ptr.

Розумні покажчики широко використовуються в нс-3 API, щоб уникнути передачі посилань на
об’єкти, виділені в купі, які можуть спричинити витік пам’яті. Для більшості базових способів використання (синтаксису) трактуйте
розумний вказівник, як звичайний покажчик:

Ptr nd = ...;
nd->CallSomeFunction ();
// тощо

Отже, як отримати розумний покажчик на об’єкт, як у першому рядку цього прикладу?

CreateObject
Як ми обговорювали вище в Memory-management-and-class-Ptr, на API найнижчого рівня об’єкти
типу Об'єкт не створюються за допомогою оператор new як зазвичай, але натомість за шаблоном
викликана функція CreateObject ().

Типовий спосіб створення такого об'єкта полягає в наступному:

Ptr nd = Створити об'єкт ();

Ви можете вважати це функціонально еквівалентним:

WifiNetDevice* nd = новий WifiNetDevice ();

Об’єкти, які походять від Об'єкт необхідно розмістити в купі за допомогою CreateObject (). Ті
що походить від ObjectBase, Такі, як нс-3 допоміжні функції та заголовки пакетів і трейлери,
можна розмістити в стеку.

У деяких сценаріях ви можете не побачити багато CreateObject () дзвінки в коді; це є
тому що існують деякі допоміжні об’єкти, які діють CreateObject () дзвінки
для вас.

TypeId
нс-3 класи, що походять від класу Об'єкт може включати клас метаданих під назвою TypeId Що
записує мета-інформацію про клас для використання в агрегації об’єктів і компонентів
системи управління:

· Унікальний рядок, що ідентифікує клас.

· Базовий клас підкласу в системі метаданих.

· Набір доступних конструкторів у підкласі.

· Список загальнодоступних властивостей («атрибутів») класу.

Об'єкт Підсумки
Зібравши всі ці поняття разом, давайте розглянемо конкретний приклад: клас вузол.

Загальнодоступний заголовний файл node.h має декларацію, яка містить статику GetTypeId ()
виклик функції:

Вузол класу: публічний об'єкт
{
громадськості:
статичний TypeId GetTypeId (void);
...

Це визначено в node.cc файл наступним чином:

TypeId
Node::GetTypeId (недійсний)
{
статичний TypeId tid = TypeId ("ns3::Node")
.SetParent ()
.AddConstructor ()
.AddAttribute ("Список пристроїв",
"Список пристроїв, пов'язаних з цим вузлом.",
ObjectVectorValue (),
MakeObjectVectorAccessor (&Node::m_devices),
MakeObjectVectorChecker ())
.AddAttribute ("ApplicationList",
"Список програм, пов'язаних з цим вузлом.",
ObjectVectorValue (),
MakeObjectVectorAccessor (&Node::m_applications),
MakeObjectVectorChecker ())
.AddAttribute ("Id",
"Ідентифікатор (унікальне ціле число) цього вузла.",
TypeId::ATTR_GET, // дозволяє лише отримати його.
UintegerValue (0),
MakeUintegerAccessor (&Node::m_id),
MakeUintegerChecker ())
;
повертатися до їжі;
}

Розглянемо TypeId в нс-3 Об'єкт клас як розширена форма типу часу виконання
інформації (RTTI). Мова C++ включає простий тип RTTI для підтримки
динамічна передача та Напевний операторів.

Команда SetParent () call у визначенні вище використовується разом з нашим
Механізми агрегації об’єктів, що дозволяють безпечне переведення вгору та вниз у деревах успадкування
під час GetObject (). Це також дозволяє підкласам успадковувати атрибути своїх батьків
клас.

Команда AddConstructor () call використовується разом з нашою фабрикою абстрактних об'єктів
механізми, які дозволяють нам конструювати об’єкти C++, не змушуючи користувача знати
клас конкретного об'єкта, який вона будує.

Три дзвінки до AddAttribute () пов’язати заданий рядок із строго введеним значенням
клас. Зверніть увагу, що ви повинні надати довідковий рядок, який може відображатися, наприклад,
через процесори командного рядка. Кожен атрибут пов'язано з механізмами доступу
базова змінна члена в об'єкті (наприклад, MakeUintegerAccessor () розповідає
загальний атрибут код, як отримати ідентифікатор вузла вище). Є також "Шахир"
методи, які використовуються для перевірки значень щодо обмежень діапазону, таких як максимальні та
мінімально допустимі значення.

Коли користувачі хочуть створити вузли, вони зазвичай викликають певну форму CreateObject (),:

Ptr n = Створити об'єкт ();

або більш абстрактно, використовуючи фабрику об'єктів, ви можете створити a вузол об'єкт без пар
знаючи конкретний тип C++:

фабрика ObjectFactory;
const std::string typeId = "ns3::Node'';
factory.SetTypeId (typeId);
Ptr вузол = фабрика.Створити ();

Обидва ці методи призводять до того, що повністю ініціалізовані атрибути стають доступними в файлі
в результаті Об'єкт екземпляри.

Далі ми обговоримо, як атрибути (значення, пов’язані зі змінними-членами або функціями
класу) наведено вище TypeId.

Attributes
Метою системи атрибутів є організація доступу до внутрішніх об'єктів-членів a
моделювання. Ця мета виникає тому, що, як правило, під час моделювання користувачі скорочують і
вставити/змінити існуючі сценарії моделювання або використовувати конструкції моделювання вищого рівня,
але часто буде зацікавлений у вивченні або відстеженні конкретних внутрішніх змінних. Для
наприклад, такі випадки використання, як:

· "I хотіти до простежувати пакети on бездротової інтерфейс тільки on перший доступ точка».

· "I хотіти до простежувати значення of TCP скупчення вікно (кожна час it зміни) on a
приватність TCP розетка."

· "I хотіти a дамп of всі величини Що були використовуваний in my моделювання».

Аналогічно, користувачам може знадобитися детальний доступ до внутрішніх змінних у симуляції, або
може знадобитися в цілому змінити початкове значення, що використовується для певного параметра
згодом створені об'єкти. Нарешті, користувачі можуть захотіти знати, які змінні можна встановити
і доступний у конфігурації моделювання. Це не тільки для прямого моделювання
взаємодія в командному рядку; розглянемо також (майбутній) графічний інтерфейс користувача, який
хотів би мати можливість надати функцію, за допомогою якої користувач може клацнути правою кнопкою миші на вузлі
полотно та побачите ієрархічний, організований список параметрів, які можна встановити на
вузол та його складові об’єкти-члени, а також текст довідки та значення за замовчуванням для кожного
параметр.

Визначення Attributes
Ми надаємо користувачам можливість отримати доступ до значень глибоко в системі, не маючи на голові
засоби доступу (вказівники) через систему та обходять ланцюжки вказівників, щоб дістатися до них. Розглянемо а
клас DropTailQueue яка має змінну-член, яка є цілим числом без знака m_maxPackets;
ця змінна-член керує глибиною черги.

Якщо ми подивимося на декларацію DropTailQueue, ми бачимо наступне:

клас DropTailQueue : публічна черга {
громадськості:
статичний TypeId GetTypeId (void);
...

private:
std::queue > m_packets;
uint32_t m_maxPackets;
};

Давайте розглянемо речі, які користувач може захотіти зробити із значенням m_maxPackets:

· Встановити значення за замовчуванням для системи, щоб кожен раз, коли новий DropTailQueue створюється,
цей член ініціалізується за умовчанням.

· Встановити або отримати значення для вже створеної черги.

Перераховані вище речі зазвичай вимагають надання Установка () та отримати () функції та деякі типи
глобальне значення за замовчуванням.

Перейдіть на вкладку нс-3 системи атрибутів, ці визначення значень і реєстрації функцій доступу
переміщуються в TypeId клас; наприклад.:

NS_OBJECT_ENSURE_REGISTERED (DropTailQueue);

TypeId
DropTailQueue::GetTypeId (недійсний)
{
статичний TypeId tid = TypeId ("ns3::DropTailQueue")
.SetParent ()
.AddConstructor ()
.AddAttribute ("MaxPackets",
"Максимальна кількість пакетів, прийнятих цим DropTailQueue.",
UintegerValue (100),
MakeUintegerAccessor (&DropTailQueue::m_maxPackets),
MakeUintegerChecker ())
;

повертатися до їжі;
}

Команда AddAttribute () метод виконує ряд речей для m_maxPackets значення:

· Прив'язування (зазвичай приватної) змінної-члена m_maxPackets до загальнодоступного рядка
"MaxPackets".

· Надання значення за замовчуванням (100 пакетів).

· Надання довідкового тексту, що визначає значення значення.

· Надання "Checker" (не використовується в цьому прикладі), який можна використовувати для встановлення обмежень на
допустимий діапазон значень.

Ключовим моментом є те, що тепер доступне значення цієї змінної та її значення за замовчуванням
у просторі імен атрибутів, який базується на рядках, наприклад "MaxPackets" та TypeId ім'я
струни. У наступному розділі ми надамо приклад сценарію, який показує, як можуть користувачі
маніпулювати цими цінностями.

Зауважте, що ініціалізація атрибута залежить від макросу NS_OBJECT_ENSURE_REGISTERED
(DropTailQueue) бути викликаним; якщо ви виключите це з реалізації нового класу, ваш
атрибути не будуть ініціалізовані правильно.

Хоча ми описали, як створити атрибути, ми досі не описали, як отримати доступ
і керувати цими цінностями. Наприклад, немає globals.h заголовний файл, де вони
зберігається; атрибути зберігаються разом із їхніми класами. Природно виникають питання, як
чи легко користувачі дізнаються про всі атрибути своїх моделей і як це робить користувач
отримати доступ до цих атрибутів або задокументувати їх значення як частину їхнього запису
моделювання?

Детальна документація фактичних атрибутів, визначених для типу, і глобальний список
всі визначені атрибути доступні в документації API. Для решти цього
документ ми збираємося продемонструвати різні способи отримання та встановлення атрибута
значень.

Установка дефолт Цінності
Config::SetDefault та Командний рядок
Давайте подивимося, як сценарій користувача може отримати доступ до певного значення атрибута. Ми збираємося
використовувати src/point-to-point/examples/main-attribute-value.cc сценарій для ілюстрації, с
деякі деталі вилучені. The основний функція починається:

// Це основний приклад того, як використовувати систему атрибутів до
// встановити та отримати значення в базовій системі; а саме, непідписаний
// ціле число максимальної кількості пакетів у черзі
//

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;
// Це надає ще один спосіб встановити значення з командного рядка:
cmd.AddValue ("maxPackets", "ns3::DropTailQueue::MaxPackets");
cmd.Parse (argc, argv);

Головне, на що слід звернути увагу в наведеному вище, — це два еквівалентні виклики Config::SetDefault
(). Ось як ми встановлюємо значення за замовчуванням для всіх наступних екземплярів
DropTailQueueс. Ми проілюструємо, що два типи значення класи, а StringValue і
UintegerValue class, можна використовувати для призначення значення атрибуту, названому by
"ns3::DropTailQueue::MaxPackets".

Також можна маніпулювати атрибутами за допомогою Командний рядок; ми бачили кілька прикладів
на початку підручника. Зокрема, легко додати скорочений аргумент
ім'я, наприклад --maxPackets, для атрибута, який є особливо релевантним для вашої моделі,
в цьому випадку "ns3::DropTailQueue::MaxPackets". Це має додаткову функцію
рядок довідки для атрибута буде надруковано як частина повідомлення про використання сценарію.
Для отримання додаткової інформації див Командний рядок Документація API.

Тепер ми створимо кілька об’єктів за допомогою низькорівневого API. Наші новостворені черги будуть
не маю m_maxPackets ініціалізовано до 100 пакетів, як визначено в
DropTailQueue::GetTypeId () функції, але до 80 пакетів, через те, що ми робили вище
значення за замовчуванням.:

Ptr n0 = Створити об'єкт ();

Ptr net0 = Створити об'єкт ();
n0->AddDevice (net0);

Ptr q = Створити об'єкт ();
net0->AddQueue(q);

На даний момент ми створили сингл вузол (n0) і одиничний PointToPointNetDevice
(net0), і додав а DropTailQueue (q), Щоб net0.

конструктори, Помічники та ObjectFactory
Довільні комбінації атрибутів можуть бути встановлені та отримані з допоміжного та низькорівневого
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 вищого рівня, таких як:

mobility.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"));

Ми не ілюструємо це тут, але ви також можете налаштувати файл ObjectFactory з новими цінностями
для конкретних атрибутів. Примірники, створені за допомогою ObjectFactory будуть такі
атрибути, встановлені під час будівництва. Це дуже схоже на використання одного з допоміжних API
для класу.

Щоб переглянути, є кілька способів встановити значення для атрибутів для екземплярів класу до be
створений in майбутнє:

· Config::SetDefault ()

· Командний рядок::AddValue ()

· CreateObjectWithAttributes<> ()

· Різні допоміжні API

Але що робити, якщо ви вже створили екземпляр і хочете змінити значення
атрибут? У цьому прикладі, як ми можемо маніпулювати m_maxPackets значення вже
примірник DropTailQueue? Ось різні способи зробити це.

Зміна Цінності
SmartPointer
Припустимо, що розумний вказівник (Ptr) на відповідний мережевий пристрій у руках; в поточному
наприклад, це net0 вказівник.

Один із способів змінити значення — отримати доступ до покажчика на базову чергу та змінити її
атрибут.

Спочатку ми помічаємо, що ми можемо отримати вказівник на (базовий клас) Чергу через
PointToPointNetDevice атрибути, де він називається "TxQueue":

PointerValue tmp;
net0->GetAttribute ("TxQueue", tmp);
Ptr txQueue = tmp.GetObject ();

Використання GetObject () функції, ми можемо виконати безпечне пониження до a DropTailQueue, Де
"MaxPackets" є атрибутом:

Ptr dtq = txQueue->GetObject ();
NS_ASSERT (dtq != 0);

Далі ми можемо отримати значення атрибута в цій черзі. Ми ввели обгортку
значення класи для базових типів даних, подібні до обгорток Java навколо цих типів,
оскільки система атрибутів зберігає значення, серіалізовані в рядки, а не розрізнені типи.
Тут значення атрибута присвоюється a UintegerValue, А отримати () метод з цього приводу
значення створює (розгорнутий) uint32_t.:

межа UintegerValue;
dtq->GetAttribute ("MaxPackets", ліміт);
NS_LOG_INFO ("1. обмеження dtq: " << limit.Get () << " пакети");

Зауважте, що вищезгадане зниження насправді не потрібне; ми могли б отримати атрибут
значення безпосередньо з txQueue, що є ан Об'єкт:

txQueue->GetAttribute ("MaxPackets", обмеження);
NS_LOG_INFO ("2. обмеження txQueue: " << 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",
UintegerValue (25));
txQueue->GetAttribute ("MaxPackets", обмеження);
NS_LOG_INFO ("4. Обмеження txQueue змінено через простір імен: "
<< limit.Get () << " пакети");

Шлях конфігурації часто має вигляд ".../
ім'я>/ /.../ / " посилатися на певний екземпляр за індексом an
предмет у контейнері. У цьому випадку перший контейнер є списком усіх вузолs; в
другий контейнер - це список усіх NetDevices на обраному вузол. Нарешті,
шлях конфігурації зазвичай закінчується послідовністю атрибутів члена, у цьому випадку
"MaxPackets" атрибут "TxQueue" з обраних NetDevice.

Ми також могли б використовувати підстановочні знаки, щоб встановити це значення для всіх вузлів і всіх мережевих пристроїв
(що в цьому простому прикладі має той самий ефект, що й попередній Config::Set ()):

Config::Set ("/NodeList/*/DeviceList/*/TxQueue/MaxPackets",
UintegerValue (15));
txQueue->GetAttribute ("MaxPackets", обмеження);
NS_LOG_INFO ("5. Обмеження txQueue змінено через простір імен із підстановочними знаками: "
<< limit.Get () << " пакети");

Об'єкт ІМ'Я Обслуговування
Інший спосіб отримати атрибут — це використовувати засіб обслуговування імен об’єктів. The
Служба імен об'єктів дозволяє нам додавати елементи до простору імен конфігурації під файлом
"/Імена/" шлях із визначеним користувачем рядком імені. Цей підхід корисний, якщо це не так
мають доступ до основних покажчиків, і важко визначити потрібний
конкретна конфігурація шляху простору імен.

Імена::Додати ("сервер", n0);
Імена::Додати ("server/eth0", net0);

...

Config::Set ("/Names/server/eth0/TxQueue/MaxPackets", UintegerValue (25));

Тут ми додали елементи шляху "сервер" та "eth0" під "/Імена/" простір імен
використав отриманий шлях конфігурації для встановлення атрибута.

Дивіться назви об’єктів для більш повної обробки нс-3 простір імен конфігурації.

Реалізація ПОДРОБИЦІ
значення Класи
Читачі звернуть увагу на ТипЗначення класи, які є підкласами AttributeValue база
клас. Їх можна розглядати як проміжні класи, які використовуються для перетворення з необроблених
типи до AttributeValues, які використовуються системою атрибутів. Нагадаємо, що це
база даних містить об'єкти багатьох типів, серіалізовані в рядки. Перетворення до цього типу
можна зробити за допомогою проміжного класу (наприклад IntegerValueабо Подвійне значення та цінності
числа з плаваючою комою) або через струни. Пряме неявне перетворення типів до
AttributeValue насправді не практично. Таким чином, у наведеному вище, користувачі мають вибір використання
рядки або значення:

p->Set ("cwnd", StringValue ("100")); // сетер на основі рядків
p->Set ("cwnd", IntegerValue (100)); // Настановник на основі цілого числа

Система надає деякі макроси, які допомагають користувачам оголошувати та визначати новий атрибут AttributeValue
підкласи для нових типів, які вони хочуть ввести в систему атрибутів:

· ATTRIBUTE_HELPER_HEADER

· ATTRIBUTE_HELPER_CPP

Додаткову інформацію дивіться в документації API щодо цих конструкцій.

Ініціалізація замовлення
Атрибути в системі не повинні залежати від стану будь-якого іншого атрибута в цьому
системи. Це пов’язано з тим, що порядок ініціалізації атрибутів не вказано
примусово, системою. Конкретний приклад цього можна побачити в автоматизованій конфігурації
такі програми, як ConfigStore. Хоча дана модель може влаштувати її так, щоб атрибути
ініціалізуються в певному порядку, інший автоматичний конфігуратор може прийняти рішення
самостійно змінювати атрибути, наприклад, в алфавітному порядку.

Через такий неспецифічний порядок жоден атрибут у системі не може мати жодної залежності
на будь-який інший атрибут. Як наслідок, налаштування атрибутів ніколи не повинні виходити з ладу через стан
іншого атрибута. Жоден установник атрибутів не може змінювати (встановлювати) будь-яке інше значення атрибута як a
результат зміни його вартості.

Це дуже сильне обмеження, і в деяких випадках необхідно встановити атрибути
постійно, щоб забезпечити правильну роботу. З цією метою ми допускаємо перевірку узгодженості
коли атрибут is використовуваний (cf. NS_ASSERT_MSG or NS_ABORT_MSG).

Загалом, код атрибута для призначення значень базовим змінним-членам класу
виконується після побудови об’єкта. Але що робити, якщо вам потрібні присвоєні значення
перед виконанням тіла конструктора, тому що вони потрібні в логіці
конструктор? Є спосіб зробити це, який використовується, наприклад, у класі ConfigStore: дзвонити
ObjectBase::ConstructSelf () наступним чином:

ConfigStore::ConfigStore ()
{
ObjectBase::ConstructSelf (AttributeConstructionList ());
// продовжити за допомогою конструктора.
}

Майте на увазі, що об’єкт і всі його похідні класи також повинні реалізовувати a GetInstanceTypeId
() метод. Інакше ObjectBase::ConstructSelf () не зможе прочитати
атрибути.

Додавання Attributes
Команда нс-3 система помістить ряд внутрішніх значень під атрибут system, але
безсумнівно, користувачі захочуть розширити це, щоб вибрати ті, які ми пропустили, або додати свої
власні класи до системи.

Є три типові випадки використання:

· Зробити наявний член даних класу доступним як атрибут, якщо він ще не доступний.

· Зробити новий клас здатним надавати деякі члени даних як атрибути, надавши йому TypeId.

· Створення ан AttributeValue підклас для нового класу, щоб до нього можна було отримати доступ як
Атрибут.

існуючий Член Змінна
Розглянемо цю змінну в TcpSocket:

uint32_t m_cWnd; // Вікно перевантаження

Припустимо, що хтось, хто працює з TCP, хотів отримати або встановити значення цієї змінної
за допомогою системи метаданих. Якщо це ще не було надано нс-3, користувач може оголосити
наступне доповнення в системі метаданих часу виконання (до GetTypeId() визначення для
TcpSocket):

.AddAttribute ("Вікно перевантаження",
"Вікно перевантаження Tcp (байти)",
UintegerValue (1),
MakeUintegerAccessor (&TcpSocket::m_cWnd),
MakeUintegerChecker ())

Тепер користувач з вказівником на a TcpSocket екземпляр може виконувати такі операції, як
встановлення та отримання значення без необхідності додавати ці функції явно.
Крім того, можна застосувати контроль доступу, наприклад, дозволити зчитувати параметр і
не записано, або можна застосувати перевірку меж на допустимі значення.

Нові Клас TypeId
Тут ми обговорюємо вплив на користувача, який хоче додати новий клас нс-3. Що
потрібно зробити додаткові речі, щоб він міг утримувати атрибути?

Припустимо, наш новий клас називається ns3::MyMobility, є різновидом моделі мобільності. Спочатку,
клас повинен успадкувати від свого батьківського класу, ns3::MobilityModel, в my-mobility.h
файл заголовка:

простір імен ns3 {

клас MyClass : публічна MobilityModel
{

Це вимагає від нас оголосити GetTypeId () функція. Це однорядкова публічна функція
декларація:

громадськості:
/ **
* Зареєструйте цей тип.
* \return Об'єкт TypeId.
*/
статичний TypeId GetTypeId (void);

Ми вже представили, що a TypeId визначення буде виглядати як у my-mobility.cc
файл реалізації:

NS_OBJECT_ENSURE_REGISTERED (MyMobility);

TypeId
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 ())
// тощо (більше параметрів).
;
повертатися до їжі;
}

Якщо ми не хочемо створювати підклас із існуючого класу, у файлі заголовка ми просто успадковуємо
від ns3::Об'єкт, а в об’єктному файлі ми встановлюємо для батьківського класу значення ns3::Об'єкт з
.SetParent ().

Типовими помилками тут є:

· Не дзвонить NS_OBJECT_ENSURE_REGISTERED ()

· Не дзвонить SetParent () метод або виклик його з неправильним типом.

· Не дзвонить AddConstructor () метод або виклик його з неправильним типом.

· Допущення друкарської помилки в назві TypeId у його конструкторі.

· Не використовувати повне ім'я типу C++ класу C++, що охоплює, як ім'я
TypeId. Зверніть увагу на це "ns3::" не потрібно.

Жодна з цих помилок не може бути виявлена нс-3 codebase, тому користувачам радимо перевірити
ретельно кілька разів, щоб вони зрозуміли це правильно.

Нові AttributeValue тип
З точки зору користувача, який пише новий клас у системі і хоче, щоб він був
доступний як атрибут, в основному йдеться про запис конверсій до/з
рядки та значення атрибутів. Більшу частину цього можна скопіювати/вставити за допомогою макросізованого коду. Для
наприклад, розглянемо оголошення класу для Прямокутник , src/мобільність/модель каталог:

Header Файл
/ **
* \коротко 2D прямокутник
*/
клас Прямокутник
{
...

подвійний xMin;
подвійний xMax;
подвійний yMin;
подвійний yMax;
};

Для цього під оголошенням класу необхідно додати один виклик макросу і два оператори
перетворити прямокутник на значення, яке можна використовувати атрибут Система:

std::ostream &operator << (std::ostream &os, const Прямокутник &прямокутник);
std::istream &оператор >> (std::istream &is, Прямокутник &прямокутник);

ATTRIBUTE_HELPER_HEADER (Прямокутник);

Реалізація Файл
У визначенні класу (. CC файл), код виглядає так:

ATTRIBUTE_HELPER_CPP (Прямокутник);

std::ostream &
оператор << (std::ostream &os, const прямокутник &прямокутник)
{
os << прямокутник.xMin << "|" << прямокутник.xMax << "|" << прямокутник.yMin << "|"
<< прямокутник.yMax;
повернення os;
}
std::istream &
оператор >> (std::istream &is, прямокутник &прямокутник)
{
char c1, c2, c3;
є >> прямокутник.xMin >> c1 >> прямокутник.xMax >> c2 >> прямокутник.yMin >> c3
>> прямокутник.yMax;
якщо (c1 != '|' ||
c2 != '|' ||
c3 != '|')
{
is.setstate (std::ios_base::failbit);
}
повернення є;
}

Ці оператори потоку просто перетворюють з рядкового представлення прямокутника
("xMin|xMax|yMin|yMax") до основного прямокутника. Розробник моделі повинен вказати це
оператори та рядкове синтаксичне представлення екземпляра нового класу.

ConfigStore
Значення для нс-3 Атрибути можна зберігати в текстовому файлі ASCII або XML і завантажувати в a
майбутній запуск моделювання. Ця функція відома як нс-3 ConfigStore. The ConfigStore is
спеціалізована база даних для значень атрибутів і значень за замовчуванням.

Хоча це окремо підтримуваний модуль в src/config-store/ каталог, ми
задокументуйте його тут, оскільки він залежить виключно від нс-3 основний модуль і атрибути.

Ми можемо вивчити цю систему на прикладі з
src/config-store/examples/config-store-save.cc.

По-перше, всі користувачі ConfigStore має містити таку заяву:

#include "ns3/config-store-module.h"

Далі ця програма додає зразок об’єкта ConfigExample щоб показати, як система розширюється:

клас ConfigExample : публічний об'єкт
{
громадськості:
static TypeId GetTypeId (void) {
статичний TypeId tid = TypeId ("ns3::A")
.SetParent ()
.AddAttribute ("TestInt16", "текст довідки",
Ціле значення (-2),
MakeIntegerAccessor (&A::m_int16),
MakeIntegerChecker ())
;
повертатися до їжі;
}
int16_t m_int16;
};

NS_OBJECT_ENSURE_REGISTERED (ConfigExample);

Далі ми використовуємо підсистему Config для перевизначення значень за замовчуванням кількома способами:

Config::SetDefault ("ns3::ConfigExample::TestInt16", IntegerValue (-5));

Ptr a_obj = Створити об'єкт ();
NS_ABORT_MSG_UNLESS (a_obj->m_int16 == -5,
"Неможливо встановити цілочисельний атрибут ConfigExample через Config::SetDefault");

Ptr a2_obj = Створити об'єкт ();
a2_obj->SetAttribute ("TestInt16", IntegerValue (-3));
IntegerValue iv;
a2_obj->GetAttribute ("TestInt16", iv);
NS_ABORT_MSG_UNLESS (iv.Get () == -3,
"Не вдається встановити цілочисельний атрибут ConfigExample через SetAttribute");

Наступний оператор необхідний для того, щоб переконатися, що (один із) створених об’єктів має корінь
у просторі імен конфігурації як екземпляр об’єкта. Зазвичай це відбувається, коли ви
агрегувати об’єкти до a ns3::Вузол or ns3::Канал приміром, але тут, оскільки ми працюємо
на базовому рівні нам потрібно створити новий кореневий об'єкт простору імен:

Config::RegisterRootNamespaceObject (a2_obj);

писемність
Далі ми хочемо вивести сховище конфігурації. На прикладах показано, як це зробити за два
формати, XML і необроблений текст. На практиці цей крок слід виконувати безпосередньо перед дзвінком
Симулятор::Біг () щоб зберегти остаточну конфігурацію безпосередньо перед запуском моделювання.

Є три атрибути, які керують поведінкою ConfigStore: "Режим",
"Ім'я файлу" та "Формат файлу". Режим (за замовчуванням "Ні") налаштовує чи нс-3 Повинен
завантажити конфігурацію з раніше збереженого файлу (вказати "Режим=Завантаження") або збережіть у файл
(уточнити "Режим=Зберегти"). Ім'я файлу (за замовчуванням "") це місце, де 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;
outputConfig.ConfigureDefaults ();
outputConfig.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 outputConfig2;
outputConfig2.ConfigureDefaults ();
outputConfig2.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::Режим «Зберегти»
за замовчуванням ns3::ConfigStore::ім'я файлу "output-attributes.txt"
за замовчуванням ns3::ConfigStore::FileFormat "RawText"
за замовчуванням ns3::ConfigExample::TestInt16 "-5"
глобальний RngSeed "1"
глобальний RngRun "1"
global SimulatorImplementationType "ns3::DefaultSimulatorImpl"
глобальний SchedulerType "ns3::MapScheduler"
глобальна контрольна сумаEnabled "false"
значення /$ns3::ConfigExample/TestInt16 "-3"

У наведеному вище, показано всі значення за замовчуванням для атрибутів для основного модуля.
Потім усі значення для нс-3 записуються глобальні значення. Нарешті, значення
екземпляр ConfigExample відображається вкорінений простір імен конфігурації. В
реальний нс-3 програми, буде показано багато інших моделей, атрибутів і значень за замовчуванням.

Також існує версія XML вихідні атрибути.xml:




























Цей файл можна заархівувати разом із вашим сценарієм моделювання та вихідними даними.

читання
Далі ми обговорюємо налаштування моделювання через збережений вхідний конфігураційний файл. Існує
пара ключових відмінностей у порівнянні з написанням остаточної конфігурації моделювання.
По-перше, нам потрібно розмістити такі оператори на початку програми, перед
записуються оператори конфігурації моделювання (тому значення реєструються перед тим, як бути
використовується в будівництві об’єктів).

Config::SetDefault ("ns3::ConfigStore::Filename", StringValue ("input-defaults.xml"));
Config::SetDefault ("ns3::ConfigStore::Mode", StringValue ("Load"));
Config::SetDefault ("ns3::ConfigStore::FileFormat", StringValue ("Xml"));
ConfigStore inputConfig;
inputConfig.ConfigureDefaults ();

Далі зверніть увагу, що завантаження вхідних конфігураційних даних обмежено атрибутом за замовчуванням (тобто.
не екземпляри) значення, а глобальні значення. Значення екземплярів атрибутів не підтримуються
тому що на цьому етапі моделювання, до побудови будь-яких об'єктів, немає
такі екземпляри об'єктів навколо. (Зверніть увагу, що майбутні покращення сховища конфігурацій можуть змінитися
ця поведінка).

По-друге, поки вихід з ConfigStore state перерахує все в базі даних, файл
вхідний файл повинен містити лише конкретні значення, які потрібно замінити. Отже, один із способів використання
цей клас для конфігурації вхідного файлу має генерувати початкову конфігурацію за допомогою
вихід ("Зберегти") "Режим" описано вище, витягніть з цього файлу конфігурації лише файл
елементів, які ви бажаєте змінити, і перемістіть ці мінімальні елементи до нового конфігураційного файлу
які потім можна безпечно редагувати та завантажувати під час наступного запуску моделювання.

Коли ConfigStore екземпляр об'єкта, його атрибути "Ім'я файлу", "Режим" та
"Формат файлу" також потрібно встановити через командний рядок або через програмні заяви.

Читання / письмо Приклад
Як більш складний приклад, припустимо, що ми хочемо читати в конфігурації
за замовчуванням із вхідного файлу з ім input-defaults.xml, і запишіть отримане
атрибути в окремий файл під назвою вихідні атрибути.xml.:

#include "ns3/config-store-module.h"
...
int main (...)
{

Config::SetDefault ("ns3::ConfigStore::Filename", StringValue ("input-defaults.xml"));
Config::SetDefault ("ns3::ConfigStore::Mode", StringValue ("Load"));
Config::SetDefault ("ns3::ConfigStore::FileFormat", StringValue ("Xml"));
ConfigStore inputConfig;
inputConfig.ConfigureDefaults ();

//
// Дозволяє користувачеві замінити будь-які значення за замовчуванням і наведене вище Bind () at
// час виконання, аргументи через командний рядок
//
командний рядок cmd;
cmd.Parse (argc, argv);

// топологія налаштування
...

// Викликати безпосередньо перед входом в Simulator::Run ()
Config::SetDefault ("ns3::ConfigStore::Filename", StringValue ("output-attributes.xml"));
Config::SetDefault ("ns3::ConfigStore::Mode", StringValue ("Зберегти"));
ConfigStore outputConfig;
outputConfig.ConfigureAttributes ();
Симулятор::Біжи ();
}

ConfigStore графічний інтерфейс користувача
Існує інтерфейс на основі GTK для ConfigStore. Це дозволяє користувачам використовувати графічний інтерфейс для
доступ і зміна змінних. Скріншоти цієї функції доступні в |ns3|
Про платформу Презентація

Щоб скористатися цією функцією, потрібно встановити libgtk та libgtk-dev; приклад Ubuntu
Команда встановлення:

$ sudo apt-get встановити libgtk2.0-0 libgtk2.0-dev

Щоб перевірити, чи налаштовано він чи ні, перевірте вихід кроку:

$ ./waf configure --enable-examples --enable-tests

---- Короткий огляд додаткових функцій NS-3:
Прив’язки Python: увімкнено
Підтримка сканування Python API: увімкнено
NS-3 Натисніть Інтеграція: увімкнено
GtkConfigStore : не ввімкнено (бібліотека 'gtk+-2.0 >= 2.12' не знайдена)

У наведеному вище прикладі він не був увімкнений, тому його не можна використовувати, доки не буде відповідна версія
встановлено та:

$ ./waf configure --enable-examples --enable-tests
$ ./waf

повторюється.

Використання майже таке ж, як і версія без GTK, але її немає ConfigStore
залучені атрибути:

// Викликати безпосередньо перед входом в Simulator::Run ()
конфігурація GtkConfigStore;
config.ConfigureDefaults ();
config.ConfigureAttributes ();

Тепер, коли ви запускаєте скрипт, має з’явитися графічний інтерфейс, який дозволить вам відкривати меню
атрибутів на різних вузлах/об’єктах, а потім запустіть виконання моделювання, коли ви
виконано.

Future робота
Є кілька можливих покращень:

· Збережіть унікальний номер версії з датою та часом на початку файлу.

· Збережіть де-небудь початкове значення rng.

· Зробіть так, щоб кожна RandomVariable серіалізувала власне початкове значення та перечитуйте його пізніше.

Об'єкт Імена
Заповнювач главу

Запис
Команда нс-3 Засіб ведення журналу може використовуватися для моніторингу або налагодження ходу моделювання
програми. Виведення журналу можна ввімкнути за допомогою операторів програми у вашому main () програми або
шляхом використання NS_LOG змінна оточення

Оператори ведення журналу не компілюються в оптимізовані збірки нс-3. Щоб використовувати журнал, один
необхідно створити (за замовчуванням) налагоджувальну збірку нс-3.

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

Про платформу
нс-3 Оператори ведення журналу зазвичай використовуються для реєстрації різних подій виконання програми, наприклад
як виникнення подій моделювання або використання певної функції.

Наприклад, цей фрагмент коду з Ipv4L3Protocol::IsDestinationAddress():

якщо (адреса == iaddr.GetBroadcast ())
{
NS_LOG_LOGIC ("Для мене (адреса широкомовної передачі інтерфейсу)");
повернути правду;
}

Якщо ведення журналів увімкнено для Протокол Ipv4L3 компонент при тяжкості ЛОГІКА or
вище (див. нижче про серйозність журналу), заява буде роздрукована; інакше це
буде придушено.

включення Вихід
Зазвичай користувачі керують виведенням журналу двома способами. Перший – це встановлення
NS_LOG змінна середовища; наприклад:

$ NS_LOG="*" ./waf --запустіть спочатку

буде виконувати перший навчальна програма з усіма виводами журналів. (Специфіка NS_LOG
Формат буде обговорено нижче.)

Це можна зробити більш детальним, вибравши окремі компоненти:

$ NS_LOG="Ipv4L3Protocol" ./waf --запустіть спочатку

Вихід можна додатково налаштувати за допомогою параметрів префікса.

Другий спосіб увімкнути ведення журналу - це використовувати явні оператори у вашій програмі, наприклад in
перший навчальна програма:

Int
main (int argc, char *argv[])
{
LogComponentEnable ("UdpEchoClientApplication", LOG_LEVEL_INFO);
LogComponentEnable ("UdpEchoServerApplication", LOG_LEVEL_INFO);
...

(Значення LOG_LEVEL_INFO, та інші можливі значення будуть обговорені нижче.)

NS_LOG синтаксис
Команда NS_LOG Змінна середовища містить список компонентів журналу та параметрів. журнал
компоненти розділені символами `:':

$ NS_LOG=" : ..."

Параметри для кожного компонента журналу надаються як прапорці після кожного компонента журналу:

$ NS_LOG=" = | ...: ..."

Параметри контролюють серйозність і рівень для цього компонента, а також чи є необов’язковими
повинна бути включена інформація, така як час моделювання, вузол моделювання, функція
ім'я та символічну суворість.

Ввійти компоненти
Як правило, компонент журналу відноситься до одного вихідного коду . CC файл і охоплює файл
весь файл.

Деякі помічники мають спеціальні методи, які дозволяють реєструвати всі компоненти в модулі,
охоплює різні одиниці компіляції, але логічно згруповані разом, наприклад нс-3
код wifi:

WifiHelper wifiHelper;
wifiHelper.EnableLogComponents ();

Команда NS_LOG Підстановка компонента журналу "*" дозволить увімкнути всі компоненти.

Щоб побачити, які компоненти журналу визначені, спрацює будь-який з них:

$ NS_LOG="print-list" ./waf --run ...

$ NS_LOG="foo" # маркер, який не відповідає жодному компоненту журналу

У першій формі буде надруковано ім’я та активні прапори для всіх компонентів журналу
пов’язані в; спробуйте це з скретч-симулятор. Друга форма друкує весь зареєстрований журнал
компонентів, а потім вийти з помилкою.

Строгість та рівень Опції
Окремі повідомлення належать до одного «класу серйозності», встановленого макросом, який створює
повідомлення. У наведеному вище прикладі NS_LOG_LOGIC(..) створює повідомлення в LOG_LOGIC
клас тяжкості.

Наступні класи тяжкості визначаються як перерахувати константи:

┌────────────────┬──────────────────────────────── ─┐
│Клас тяжкості │ Значення │
├────────────────┼───────────────────────────────── ─┤
LOG_NONE │ За замовчуванням, без реєстрації │
├────────────────┼───────────────────────────────── ─┤
LOG_ERROR │ Лише повідомлення про серйозні помилки │
├────────────────┼───────────────────────────────── ─┤
LOG_WARN │ Попереджувальні повідомлення │
├────────────────┼───────────────────────────────── ─┤
LOG_DEBUG │ Для використання при налагодженні │
├────────────────┼───────────────────────────────── ─┤
LOG_INFO │ Інформаційна │
├────────────────┼───────────────────────────────── ─┤
LOG_FUNCTION │ Трасування функцій │
├────────────────┼───────────────────────────────── ─┤
LOG_LOGIC │ Контроль потоку в межах │
│ │ функції │
└───────────────┴───────────────────────────────── ─┘

Зазвичай потрібно бачити повідомлення певного класу серйозності та вище. Це робиться шляхом
визначення "рівнів" інклюзивного журналювання:

┌───────────────────┬───────────────────────────── ─────┐
│Рівень │ Значення │
├───────────────────┼───────────────────────────── ─────┤
LOG_LEVEL_ERROR │ Тільки LOG_ERROR клас тяжкості │
│ │ повідомлення. │
├───────────────────┼───────────────────────────── ─────┤
LOG_LEVEL_WARNLOG_WARN і вище. │
├───────────────────┼───────────────────────────── ─────┤
LOG_LEVEL_DEBUGLOG_DEBUG і вище. │
├───────────────────┼───────────────────────────── ─────┤
LOG_LEVEL_INFOLOG_INFO і вище. │
├───────────────────┼───────────────────────────── ─────┤
LOG_LEVEL_FUNCTIONLOG_FUNCTION і вище. │
├───────────────────┼───────────────────────────── ─────┤
LOG_LEVEL_LOGICLOG_LOGIC і вище. │
├───────────────────┼───────────────────────────── ─────┤
LOG_LEVEL_ALL │ Усі класи тяжкості. │
├───────────────────┼───────────────────────────── ─────┤
LOG_ALL │ Синонім до LOG_LEVEL_ALL
└───────────────────┴───────────────────────────── ─────┘

Варіанти класу і рівня серйозності можуть бути вказані в NS_LOG змінна середовища за
ці токени:

┌──────────┬─────────────────┐
│Клас │ Рівень │
├──────────┼─────────────────┤
помилкаlevel_error
├──────────┼─────────────────┤
попереджатирівень_попередження
├──────────┼─────────────────┤
відлагоджуватиlevel_debug
├──────────┼─────────────────┤
infoрівень_інформації
├──────────┼─────────────────┤
функціярівень_функції
├──────────┼─────────────────┤
логікаlevel_logic
├──────────┼─────────────────┤
│ │ рівень_всі
│ │ всі
│ │ *
└─────────┴─────────────────┘

Використання маркера класу серйозності дозволяє реєструвати повідомлення лише з таким рівнем серйозності. Наприклад,
NS_LOG="*=попередити" не виводить повідомлення з серйозністю помилка. NS_LOG="*=level_debug" волі
виводити повідомлення на рівні серйозності відлагоджувати і вище.

Класи та рівні серйозності можуть бути поєднані з `|' оператор:
NS_LOG="*=level_warn|логіка" буде виводити повідомлення на рівні серйозності помилка, попереджати та логіка.

Команда NS_LOG символ підстановки рівня серйозності "*" і всі є синонімами до рівень_всі.

Для компонентів журналу, згаданих лише в NS_LOG

$ NS_LOG=" :..."

серйозність за замовчуванням LOG_LEVEL_ALL.

префікс Опції
Декілька префіксів можуть допомогти визначити, де і коли виникло повідомлення і з чого
тяжкість.

Доступні параметри префікса (як перерахувати константи) є

┌─────────────────┬─────────────────────────────── ───┐
│Префікс Символ │ Значення │
├─────────────────┼─────────────────────────────── ───┤
LOG_PREFIX_FUNC │ Поставте префікс імені, що дзвонить │
│ │ функція. │
├─────────────────┼─────────────────────────────── ───┤
LOG_PREFIX_TIME │ Введіть префікс часу моделювання. │
├─────────────────┼─────────────────────────────── ───┤
LOG_PREFIX_NODE │ Поставте префікс ідентифікатора вузла. │
├─────────────────┼─────────────────────────────── ───┤
LOG_PREFIX_LEVEL │ Введіть префікс рівня серйозності. │
├─────────────────┼─────────────────────────────── ───┤
LOG_PREFIX_ALL │ Увімкнути всі префікси. │
└─────────────────┴─────────────────────────────── ───┘

Параметри префіксів коротко описані нижче.

Варіанти можна надати в NS_LOG змінна середовища за допомогою цих токенів:

┌──────────────┬────────────┐
│Жетон │ Альтернативний │
├─────────────┼────────────┤
prefix_funcфункц
├─────────────┼────────────┤
префікс_часчас
└──────────────┴────────────┘

префікс_вузолвузол
├─────────────┼────────────┤
рівень_префіксарівень
├─────────────┼────────────┤
префікс_всівсі
│ │ *
└──────────────┴────────────┘

Для компонентів журналу, згаданих лише в NS_LOG

$ NS_LOG=" :..."

параметри префікса за замовчуванням LOG_PREFIX_ALL.

Строгість префікс
Клас серйозності повідомлення може бути включено в параметри рівень_префікса or рівень.
Наприклад, це значення NS_LOG дозволяє вести журнал для всіх компонентів журналу (`*') і всіх
класи тяжкості (= все), і додає до повідомлення префікс класу серйозності (|рівень_префікса).

$ NS_LOG="*=all|prefix_level" ./waf --запустіть scratch-simulator
Симулятор скретч
Повідомлення про помилку [ERROR].
[WARN] попередження
[DEBUG] повідомлення про налагодження
Інформаційне повідомлення [INFO].
Повідомлення функції [FUNCT].
Логічне повідомлення [LOGIC].

Time префікс
Час моделювання може бути включено в параметри префікс_час or час. Це друкує
час моделювання в секундах.

вузол префікс
Ідентифікатор вузла моделювання може бути включено в параметри префікс_вузол or вузол.

функція префікс
Ім’я функції, що викликає, може бути включено в параметри prefix_func or функц.

NS_LOG Символи
Підстановка компонента журналу "*" дозволить увімкнути всі компоненти. Щоб увімкнути всі компоненти на a
використання конкретного рівня тяжкості *=.

Параметр рівня серйозності підстановки "*" є синонімом для всі. Це має відбутися перед будь-яким
`|' параметри розділення символів. Щоб увімкнути всі класи серйозності, використовуйте =*,
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_FINE (...); макрос всередині простору імен ns3.
Створіть унікальний ідентифікатор рядка (зазвичай на основі імені файлу та/або класу
визначено у файлі) і зареєструйте його за допомогою макровиклику, наприклад:

простір імен ns3 {

NS_LOG_COMPONENT_DEFINE («Протокол Ipv4L3»);
...

Це реєструється Протокол Ipv4L3 як компонент журналу.

(Макрос був ретельно написаний, щоб дозволити включення або всередині, або за межами
простору імен ns3, і використання буде відрізнятися в залежності від кодової бази, але початковим наміром було
зареєструвати це поза простору імен ns3 у глобальній області дії файлу.)

2. Додайте оператори ведення журналу (макровиклики) до своїх функцій і органів функцій.

Запис Макрос
Макроси журналу та відповідні рівні серйозності

┌───────────────┬─────────────────────────┐
│Клас тяжкості │ Макро │
├───────────────┼─────────────────────────┤
LOG_NONE │ (не потрібно) │
├───────────────┼─────────────────────────┤
LOG_ERRORNS_LOG_ERROR (...);
├───────────────┼─────────────────────────┤
LOG_WARNNS_LOG_WARN (...);
├───────────────┼─────────────────────────┤
LOG_DEBUGNS_LOG_DEBUG (...);
├───────────────┼─────────────────────────┤
LOG_INFONS_LOG_INFO (...);
├───────────────┼─────────────────────────┤
LOG_FUNCTIONNS_LOG_FUNCTION (...);
├───────────────┼─────────────────────────┤
LOG_LOGICNS_LOG_LOGIC (...);
└────────────────┴──────────────────────────┘

Макроси функціонують як вихідні потоки, тому що ви можете надіслати std :: cout, приєднався
by << операторів, дозволяється:

void MyClass::Check (значення int, char * елемент)
{
NS_LOG_FUNCTION (цей << arg << елемент);
якщо (arg > 10)
{
NS_LOG_ERROR ("виявлене неправильне значення " << значення <
" під час перевірки " << ім'я << "!");
}
...
}

Зверніть увагу, що 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 для отримання додаткової інформації про виконання, наприклад розміру a
структуру даних при додаванні/видаленні з неї.

· Використання NS_LOG_LOGIC щоб простежити важливі логічні гілки в межах функції.

· Перевірте, чи зміни в журналі не порушують код. Запустіть деякі приклади програм за допомогою
всі компоненти журналу ввімкнено (напр NS_LOG="***").

Простеження
Підсистема відстеження є одним із найважливіших механізмів для розуміння нс-3, в
більшість випадків, нс-3 користувачі матимуть блискучу ідею щодо нових і покращених мереж
особливість. Щоб переконатися, що ця ідея працює, дослідник внесе зміни в файл
існуючої системи, а потім запустіть експерименти, щоб побачити, як нова функція поводиться шляхом збирання
статистичні дані, які фіксують поведінку об’єкта.

Іншими словами, вся суть запуску моделювання полягає в тому, щоб генерувати вихідні дані для подальшого використання
дослідження. в нс-3, підсистемою, яка дає змогу досліднику це робити, є трасування
підсистема.

Простеження мотивація
Існує багато способів отримати інформацію з програми. Найпростіший спосіб
щоб просто надрукувати інформацію безпосередньо на стандартному виводі, як у,

#включати
...
intmain()
{
...
std::cout << "Значення x є " << x << std::endl;
...
}

Це можливо в невеликих середовищах, але в міру того, як ваші симуляції стають все більше і більше
ускладнюється, ви отримуєте все більше і більше відбитків і завдання аналізу та виконання
обчислення на виході починають ставати все складніше.

Інша річ, яку слід враховувати, це те, що кожен раз, коли потрібен новий ласий шматочок, ядро ​​програмного забезпечення
необхідно відредагувати та ввести інший друк. Немає стандартного способу контролювати все
цього випуску, тому обсяг виробництва має тенденцію безмежно зростати. Зрештою,
пропускна здатність, необхідна для простого виведення цієї інформації, починає обмежувати час роботи
моделювання. Вихідні файли збільшуються до величезних розмірів, і їх розбір стає a
проблема.

нс-3 забезпечує простий механізм ведення журналу та надання певного контролю над виводом через
Ввійти компоненти, але рівень контролю зовсім не дуже дрібний. Заготівля лісу
модуль є відносно тупим інструментом.

Бажано мати об’єкт, який дозволить лише проникнути в основну систему
отримати необхідну інформацію без необхідності змінювати та перекомпілювати основну систему. Навіть
кращою була б система, яка сповіщала б користувача про зміну об’єкта, що цікавить, або
відбулася цікава подія.

Команда нс-3 Система трасування розроблена для роботи за цими напрямками та добре інтегрована з
підстеби Attribute і Config, що дозволяють використовувати відносно прості сценарії використання.

Про платформу
Підсистема трасування багато в чому покладається на нс-3 Механізми зворотного виклику та атрибутів. ти
перед спробою прочитати та зрозуміти відповідні розділи посібника
зрозуміти систему відстеження.

Команда нс-3 Система трасування побудована на концепціях незалежних джерел трасування і
трасування мийок; разом з єдиним механізмом підключення джерел до мийок.

Джерела трасування — це об’єкти, які можуть сигналізувати про події, що відбуваються в симуляції, і надавати
доступ до цікавих базових даних. Наприклад, джерело сліду може вказувати, коли a
пакет отримує мережевий пристрій і надає доступ до вмісту пакета для
зацікавлені раковини слідів. Джерело сліду також може вказувати, коли цікавий стан
зміни відбуваються в моделі. Наприклад, вікно перевантаження моделі TCP є простим
кандидат на джерело слідів.

Джерела слідів самі по собі не корисні; вони повинні бути підключені до інших фрагментів коду
які насправді роблять щось корисне з інформацією, наданою джерелом. The
сутності, які споживають інформацію трасування, називаються приймачами трасування. Джерела слідів є
генератори подій і прийомники слідів є споживачами.

Такий явний поділ дозволяє розкидати велику кількість джерел слідів
система в тих місцях, які, на думку авторів моделі, можуть бути корисними. Якщо користувач не підключається a
відслідковувати приймач до одного з цих джерел, нічого не виводить. Таке розташування дозволяє відносно
невибагливі користувачі приєднують нові типи приймачів до існуючих джерел трасування, без
що вимагає редагування та перекомпіляції ядра або моделей симулятора.

Споживачів подій трасування, створених джерелом трасування, може бути нуль або більше. Можна
уявіть джерело трасування як різновид інформаційного зв’язку точка-багато точок.

"Транспортний протокол" для цього концептуального зв'язку "точка-багато точок" є нс-3 Callback.

Згадайте з розділу зворотного дзвінка, що функція зворотного виклику – це спосіб дозволити двом модулям
система для зв'язку за допомогою викликів функцій, в той же час від'єднуючи виклик
функцію з викликаного класу повністю. Це та сама вимога, що описана вище
для системи відстеження.

По суті, джерело слідів is зворотний виклик, до якого може бути зареєстровано кілька функцій.
Коли приймач трасування виявляє зацікавленість в отриманні подій трасування, він додає зворотний виклик до a
список зворотних викликів, утримуваних джерелом трасування. Коли відбувається цікава подія, слід
джерело викликає його Оператор () надання нуля або більше параметрів. Про це повідомляє джерело
перегляньте його список зворотних викликів, викликаючи кожен з них по черзі. Таким чином, параметр(и)
передаються в прийомники трасування, які є лише функціями.

Команда Найпростіший Приклад
Буде корисно розглянути короткий приклад, щоб підкріпити те, що ми сказали:

#include "ns3/object.h"
#include "ns3/uinteger.h"
#include "ns3/traced-value.h""
#include "ns3/trace-source-accessor.h"

#включати

використання простору імен ns3;

Перше, що потрібно зробити, це включити необхідні файли. Як зазначалося вище, система слідів
інтенсивно використовує системи об'єктів і атрибутів. Перші два включають введення
декларації для цих систем. Файл, traced-value.h вносить необхідне
оголошення для відстеження даних, які підкоряються семантиці значень.

Загалом, семантика значень просто означає, що ви можете передавати об’єкт, а не an
адреса. Щоб взагалі використовувати семантику значень, у вас повинен бути об’єкт з an
доступний пов’язаний конструктор копіювання та оператор присвоєння. Розширюємо вимоги
щоб говорити про набір операторів, які попередньо визначені для типів звичайних даних (POD).
Оператор=, оператор++, оператор--, оператор+, оператор== тощо.

Все це означає, що ви зможете відстежити зміни об’єкта, зроблені за допомогою
ці оператори.:

клас MyObject : публічний об'єкт
{
громадськості:
статичний TypeId GetTypeId (void)
{
статичний TypeId tid = TypeId ("MyObject")
.SetParent (Object::GetTypeId ())
.AddConstructor ()
.AddTraceSource ("MyInteger",
"Це ціле значення для відстеження.",
MakeTraceSourceAccessor (&MyObject::m_myInt))
;
повертатися до їжі;
}

Мій об'єкт () {}
TracedValue m_myInt;
};

Оскільки система трасування інтегрована з атрибутами, а атрибути працюють з об’єктами,
має бути нс-3 Об'єкт для джерела сліду, щоб жити в. Дві важливі лінії
код є .AddTraceSource і TracedValue декларація

Команда .AddTraceSource надає "гачки", які використовуються для підключення джерела трасування до
зовнішній світ. The TracedValue декларація забезпечує інфраструктуру, яка перевантажує
оператори, згадані вище, і керує процесом зворотного виклику.:

анулювати
IntTrace (Int oldValue, Int newValue)
{
std::cout << "Traced " << oldValue << " to " << newValue << std::endl;
}

Це визначення прийому слідів. Це безпосередньо відповідає функції зворотного виклику.
Ця функція буде викликатися щоразу, коли один з операторів TracedValue is
виконано.:

Int
main (int argc, char *argv[])
{
Ptr myObject = CreateObject ();

myObject->TraceConnectWithoutContext ("MyInteger", MakeCallback(&IntTrace));

myObject->m_myInt = 1234;
}

У цьому фрагменті перше, що потрібно зробити, це створити об’єкт, у якому
джерело сліду живе.

Наступний крок, TraceConnectWithoutContext, утворює зв'язок між слідом
джерело та поглинач слідів. Зверніть увагу на MakeCallback функція шаблону. Згадати з
Розділ зворотного виклику, що створює спеціалізований функтор, відповідальний за надання
перевантажений Оператор () використовується для "запуску" зворотного виклику. Перевантажені оператори (++, -- тощо)
буде використовувати це Оператор () щоб фактично викликати зворотний виклик. The TraceConnectWithoutContext,
приймає рядковий параметр, який надає ім’я атрибута, призначеного для трасування
джерело. Давайте поки що проігноруємо контекст, оскільки він ще не важливий.

Нарешті, рядок:

myObject->m_myInt = 1234;

слід тлумачити як заклик до оператор = на змінну-член m_myInt з
ціле число 1234 передано як параметр. Виявляється, що цей оператор визначено (за
TracedValue), щоб виконати зворотний виклик, який повертає void і приймає два цілі значення як
параметри -- старе значення та нове значення для цілого числа, про яке йдеться. Це точно
підпис функції для функції зворотного виклику, яку ми надали -- IntTrace.

Підводячи підсумок, джерело трасування — це, по суті, змінна, яка містить список зворотних викликів. А
trace sink — це функція, яка використовується як мета зворотного виклику. Тип атрибута та об’єкта
Інформаційні системи використовуються для забезпечення способу підключення джерел слідів до приймачів слідів. The
Акт "влучення" до джерела трасування - це виконання оператора над джерелом трасування, який спрацьовує
зворотні дзвінки. Це призводить до того, що зворотні виклики приймача трасування реєструють інтерес до джерела
викликається з параметрами, наданими джерелом.

використання конфиг Підсистема до Спілкування до Трасування Джерела
Команда TraceConnectWithoutContext виклик, показаний вище в простому прикладі, насправді дуже
рідко використовується в системі. Більш типово, конфиг підсистема використовується для вибору
джерело відстеження в системі за допомогою того, що називається a конфиг шлях.

Наприклад, у системі можна знайти щось, що виглядає так (взято
від examples/tcp-large-transfer.cc):

void CwndTracer (uint32_t oldval, uint32_t newval) {}

...

Config::ConnectWithoutContext (
"/NodeList/0/$ns3::TcpL4Protocol/SocketList/0/CongestionWindow",
MakeCallback (&CwndTracer));

Це має виглядати дуже знайомо. Це те саме, що й у попередньому прикладі, за винятком того
статична функція-член класу конфиг викликається замість методу on Об'єкт;
і замість an атрибут ім'я, надається шлях.

Перше, що потрібно зробити, це прочитати шлях назад. Останній відрізок шляху має бути
an атрибут з Об'єкт. Насправді, якби у вас був вказівник на Об'єкт що має
"Вікно заторів" атрибут зручно (назв theObject), ви можете написати це так само, як
попередній приклад:

void CwndTracer (uint32_t oldval, uint32_t newval) {}

...

theObject->TraceConnectWithoutContext ("CongestionWindow", MakeCallback (&CwndTracer));

Виявляється, що код для Config::ConnectWithoutContext робить саме це. Це
функція приймає шлях, який представляє ланцюжок Об'єкт вказівників і слідує за ними доти
доходить до кінця шляху та інтерпретує останній сегмент як атрибут на останньому
об'єкт. Давайте пройдемося по тому, що відбувається.

Провідний символ "/" в шляху відноситься до так званого простору імен. Один з
попередньо визначеними просторами імен у системі конфігурації є "NodeList", який є списком усіх
вузли в симуляції. Пункти списку посилаються на індекси до списку, отже
"/NodeList/0" відноситься до нульового вузла в списку вузлів, створених за допомогою моделювання.
Цей вузол насправді є a Ptr і так само є підкласом an ns3::Об'єкт.

Як описано в розділі "Об'єктна модель", нс-3 підтримує модель агрегації об'єктів. The
наступний сегмент шляху починається з символу "$", що вказує на a GetObject дзвонити має бути
зроблено пошук типу, який слід. Коли вузол ініціалізується за допомогою an
InternetStackHelper ряд інтерфейсів агреговано до вузла. Одним з таких є
Протокол четвертого рівня TCP. Тип середовища виконання цього об'єкта протоколу ns3::TcpL4Protocol''.
Коли `` GetObject виконується, повертає вказівник на об’єкт цього типу.

Команда Протокол TcpL4 клас визначає атрибут під назвою "SocketList", який є списком
розетки. Кожна розетка насправді є ns3::Об'єкт зі своїм Attributes. Предмети в
список сокетів посилається за індексом, як і в NodeList, тому "SocketList/0"
посилається на нульовий сокет у списку сокетів на нульовому вузлі в NodeList --
перший вузол, побудований під час моделювання.

Це розетка, тип якої виявляється an ns3::TcpSocketImpl визначає атрибут
називається "CongestionWindow", який є a TracedValue,
Config::ConnectWithoutContext тепер робить a,:

object->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 концептуальна модель пристрою, а також концептуальні моделі різного пристрою
помічники. Зрозуміло, що створені файли відповідають a
- - угода про найменування.

Помічники протоколу розглядають проблему визначення, через які трасування слід увімкнути
пара протокол і інтерфейс. Це випливає з нс-3 концептуальна модель стеку протоколів,
а також концептуальні моделі помічників інтернет-стека. Природно, файли трасування
слід дотримуватися а - - угода про найменування.

Тому помічники відстеження природно потрапляють у двовимірну таксономію. Існує
тонкощі, які заважають всім чотирьом класам поводитися однаково, але ми прагнемо до цього
зробити так, щоб усі вони працювали якомога подібно; і по можливості є аналоги для
всі методи в усіх класах.

┌────────────────┬───────┬───────┐
│ │ pcap │ ascii │
├────────────────┼───────┼───────┤
│Помічник пристрою │ │ │
├────────────────┼───────┼───────┤
│Помічник протоколу │ │ │
└─────────────────┴──────┴───────┘

Ми використовуємо підхід, який називається а міксин щоб додати функції трасування до наших допоміжних класів. А
міксин це клас, який надає функціональні можливості, успадковані підкласом.
Успадкування від міксина не вважається формою спеціалізації, а насправді є способом
зібрати функціональність.

Давайте швидко розглянемо всі чотири ці випадки та їх відповідні міксини.

Pcap Простеження Пристрій Помічники
Мета цих помічників — полегшити додавання послідовного засобу відстеження pcap до файлу
нс-3 пристрій. Ми хочемо, щоб усі різні варіанти трасування pcap працювали однаково
всі пристрої, тому методи цих помічників успадковуються помічниками пристроїв. Поглянь
at src/network/helper/trace-helper.h якщо ви хочете стежити за обговоренням, дивлячись на
реальний код.

Клас PCapHelperForDevice це міксин забезпечує функціональність високого рівня для використання
Трасування pcap у файлі нс-3 пристрій. Кожен пристрій має реалізувати єдиний віртуальний метод
успадковано від цього класу.:

virtual void EnablePcapInternal (префікс std::string, Ptr nd, bool безладний) = 0;

Особливість цього методу відбиває орієнтований на пристрій погляд на ситуацію
рівень. Усі відкриті методи, успадковані від класу PCapUserHelperForDevice зменшити до
викликаючи цей один залежний від пристрою метод реалізації. Наприклад, найнижчий рівень
метод pcap,:

void EnablePcap (префікс std::string, Ptr nd, bool promiscuous = false, bool explicitFilename = false);

буде називати реалізацію пристрою EnablePcapInternal безпосередньо. Всі інші загальнодоступні pcap
методи трасування базуються на цій реалізації, щоб забезпечити додатковий рівень користувача
функціональність. Для користувача це означає, що всі помічники пристроїв у системі будуть
мати доступні всі методи трасування pcap; і всі ці методи будуть працювати однаково
шлях між пристроями, якщо пристрій реалізує EnablePcapInternal правильно

Pcap Простеження Пристрій Помічник Методи
void EnablePcap (префікс std::string, Ptr nd,
bool promiscuous = false, bool explicitFilename = false);
void EnablePcap (префікс std::string, std::string ndName,
bool promiscuous = false, bool explicitFilename = false);
void EnablePcap (префікс std::string, NetDeviceContainer d,
bool promiscuous = false);
void EnablePcap (префікс std::string, NodeContainer n,
bool promiscuous = false);
void EnablePcap (префікс std::string, uint32_t nodeid, uint32_t deviceid,
bool promiscuous = false);
void EnablePcapAll (префікс std::string, bool promiscuous = false);

У кожному з методів, показаних вище, є параметр за замовчуванням безладний Що
за замовчуванням false. Цей параметр вказує, що слід не збирати
безладний режим. Якщо ви хочете, щоб ваші сліди включали весь трафік, який бачить пристрій
(і якщо пристрій підтримує безладний режим) просто додайте істинний параметр до будь-якого з параметрів
дзвінки вище. Наприклад,:

Ptr nd;
...
helper.EnablePcap ("префікс", nd, true);

увімкне безладний режим захоплення на NetDevice визначено nd.

Перші два методи також містять параметр за замовчуванням, який називається explicitFilename що буде
обговорюватимуться нижче.

Вам пропонується ознайомитися з Doxygen для класу PCapHelperForDevice щоб знайти деталі
цих методів; але підсумувати...

Ви можете ввімкнути трасування pcap на певній парі вузол/мережа-пристрій, надавши a
Ptr в EnablePcap метод. Ptr неявно, оскільки мережевий пристрій
має належати саме одному вузол. Наприклад,:

Ptr nd;
...
helper.EnablePcap ("префікс", nd);

Ви можете ввімкнути трасування pcap на певній парі вузол/мережа-пристрій, надавши a
std :: рядок представляє рядок служби імені об'єкта для an EnablePcap метод.
Ptr шукається з рядка імені. Знову ж таки, є неявним, оскільки
названий мережевий пристрій має належати точно одному вузол. Наприклад,:

Імена::Додати ("сервер" ...);
Імена::Додати ("server/eth0" ...);
...
helper.EnablePcap ("префікс", "сервер/ath0");

Ви можете ввімкнути трасування pcap для набору пар вузол/мережа-пристрій, надавши a
NetDeviceContainer. Для кожного NetDevice в контейнері перевіряється тип. Для кожного
пристрій належного типу (того самого типу, яким керує помічник пристрою), трасування є
увімкнено. Знову ж таки, неявно, оскільки знайдений мережевий пристрій має належати точно
один вузол. Наприклад,:

NetDeviceContainer d = ...;
...
helper.EnablePcap ("префікс", d);

Ви можете ввімкнути трасування pcap для набору пар вузол/мережа-пристрій, надавши a
NodeContainer. Для кожного вузол , NodeContainer його додається NetDevices повторюються.
Для кожного NetDevice приєднаний до кожного вузла в контейнері, тип цього пристрою
перевірено. Для кожного пристрою належного типу (того самого типу, яким керує пристрій
помічник), трасування ввімкнено.:

NodeContainer n;
...
helper.EnablePcap ("префікс", n);

Ви можете ввімкнути трасування pcap на основі ідентифікатора вузла та ідентифікатора пристрою, а також явно
Ptr. Кожен вузол в системі має цілочисельний ідентифікатор вузла і кожен пристрій підключено до вузла
має цілий ідентифікатор пристрою:

helper.EnablePcap ("префікс", 21, 1);

Нарешті, ви можете ввімкнути трасування pcap для всіх пристроїв у системі з тим самим типом, що й
яким керує помічник пристрою.:

helper.EnablePcapAll ("префікс");

Pcap Простеження Пристрій Помічник ім'я файлу вибір
В описах методів, наведених вище, є побудова повного імені файлу за допомогою
метод реалізації. За умовою, pcap сліди в нс-3 системи мають форму
- id>- id>.pcap

Як згадувалося раніше, кожен вузол у системі матиме присвоєний системою ідентифікатор вузла; і
кожен пристрій матиме індекс інтерфейсу (також званий ідентифікатором пристрою) відносно свого вузла.
Таким чином, за замовчуванням файл трасування pcap створюється в результаті включення трасування на першому
пристрій вузла 21 з використанням префікса "префікс" буде префікс-21-1.pcap.

Ви завжди можете використовувати нс-3 сервіс імен об’єктів, щоб зробити це більш зрозумілим. Наприклад, якщо
Ви використовуєте службу імен об'єктів, щоб призначити ім'я "сервер" вузлу 21, отриманий pcap
Ім'я файлу трасування автоматично стане, префікс-сервер-1.pcap і якщо ви також призначите
ім'я "eth0" для пристрою, ім'я вашого файлу pcap автоматично підбере це і буде
званий префікс-сервер-eth0.pcap.

Нарешті, два з описаних вище методів:

void EnablePcap (префікс std::string, Ptr nd, bool promiscuous = false, bool explicitFilename = false);
void EnablePcap (префікс std::string, std::string ndName, bool promiscuous = false, bool explicitFilename = false);

мають параметр за замовчуванням explicitFilename. Якщо встановлено значення true, цей параметр
вимикає механізм автоматичного завершення імен файлів і дозволяє створити явний
ім'я файлу. Ця опція доступна лише в методах, які дозволяють відстежувати pcap на a
один пристрій.

Наприклад, щоб організувати помічника пристрою для створення одного безладного pcap
захоплення файлу певного імені (my-pcap-file.pcap) на даному пристрої можна:

Ptr nd;
...
helper.EnablePcap ("my-pcap-file.pcap", nd, true, true);

Перший правда Параметр включає безладні трасування режиму, а другий повідомляє помічнику
інтерпретувати префікс параметр як повне ім'я файлу.

Ascii Простеження Пристрій Помічники
Поведінка помічника трасування ascii міксин істотно схожий на версію pcap.
Подивитися на src/network/helper/trace-helper.h якщо ви хочете стежити за обговоренням
при перегляді реального коду.

Клас AsciiTraceHelperForDevice додає функціональність високого рівня для використання ascii
трасування до допоміжного класу пристрою. Як і у випадку pcap, кожен пристрій має реалізувати a
єдиний віртуальний метод, успадкований від трасування ascii міксин.:

virtual void EnableAsciiInternal (Ptr stream, std::string префікс, Ptr nd) = 0;

Особливість цього методу відбиває орієнтований на пристрій погляд на ситуацію
рівень; а також той факт, що помічник може писати в спільний вихідний потік. Всі з
відкриті методи, пов’язані з трасуванням ascii, успадковані від класу AsciiTraceHelperForDevice
зводяться до виклику цього методу реалізації, залежного від одного пристрою. Наприклад,
методи трасування ascii найнижчого рівня:

void EnableAscii (префікс std::string, Ptr nd);
void EnableAscii (Ptr потік, Ptr nd);

буде називати реалізацію пристрою EnableAsciiInternal безпосередньо, надаючи або a
дійсний префікс або потік. Усі інші публічні методи трасування ASCII будуть спиратися на них
низькорівневі функції для забезпечення додаткової функціональності на рівні користувача. Що це означає для
Користувач полягає в тому, що всі помічники пристроїв у системі матимуть усі методи трасування ascii
доступний; і всі ці методи працюватимуть однаково на різних пристроях, якщо пристрої
здійснювати EnableAsciiInternal правильно

Ascii Простеження Пристрій Помічник Методи
void EnableAscii (префікс std::string, Ptr nd);
void EnableAscii (Ptr потік, Ptr nd);

void EnableAscii (префікс std::string, std::string ndName);
void EnableAscii (Ptr stream, 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, uint32_t nodeid, uint32_t deviceid);
void EnableAscii (Ptr stream, uint32_t nodeid, uint32_t deviceid);

void EnableAsciiAll (префікс std::string);
void EnableAsciiAll (Ptr потік);

Вам пропонується ознайомитися з Doxygen для класу TraceHelperForDevice щоб знайти
деталі цих методів; але підсумувати...

Для трасування 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 ("trace-file-name.tr");
...
helper.EnableAscii (потік, nd1);
helper.EnableAscii (потік, nd2);

У цьому випадку контексти трасування записуються в файл трасування ascii, оскільки вони є обов’язковими
щоб розкрити сліди від двох пристроїв. Зверніть увагу, що оскільки користувач повністю
вказуючи ім'я файлу, рядок повинен містити ".tr" для узгодженості.

Ви можете ввімкнути трасування ascii на певній парі вузол/мережа-пристрій, надавши a
std :: рядок представляє рядок служби імені об'єкта для an EnablePcap метод.
Ptr шукається з рядка імені. Знову ж таки, є неявним, оскільки
названий мережевий пристрій має належати точно одному вузол. Наприклад,:

Імена::Додати ("клієнт" ...);
Імена::Додати ("клієнт/eth0" ...);
Імена::Додати ("сервер" ...);
Імена::Додати ("server/eth0" ...);
...
helper.EnableAscii ("префікс", "клієнт/eth0");
helper.EnableAscii ("префікс", "сервер/eth0");

Це призведе до отримання двох файлів з іменем префікс-клієнт-eth0.tr та префікс-сервер-eth0.tr з
трасування для кожного пристрою у відповідному файлі трасування. Оскільки всі EnableAscii
функції перевантажені, щоб отримати обгортку потоку, ви також можете використовувати цю форму:

Імена::Додати ("клієнт" ...);
Імена::Додати ("клієнт/eth0" ...);
Імена::Додати ("сервер" ...);
Імена::Додати ("server/eth0" ...);
...
Ptr stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
...
helper.EnableAscii (потік, "клієнт/eth0");
helper.EnableAscii (потік, "server/eth0");

Це призведе до створення одного файлу трасування під назвою trace-file-name.tr що містить усі
події трасування для обох пристроїв. Події будуть неоднозначні контекстом слідів
струни.

Ви можете ввімкнути трасування ascii для набору пар вузол/мережа-пристрій, надавши a
NetDeviceContainer. Для кожного NetDevice в контейнері перевіряється тип. Для кожного
пристрій належного типу (того самого типу, яким керує помічник пристрою), трасування є
увімкнено. Знову ж таки, неявно, оскільки знайдений мережевий пристрій має належати точно
один вузол. Наприклад,:

NetDeviceContainer d = ...;
...
helper.EnableAscii ("префікс", d);

Це призведе до створення ряду файлів трасування ascii, кожен з яких наведено нижче
в - - конвенція .tr. Об’єднання всіх слідів в a
один файл виконується аналогічно наведеним вище прикладам:

NetDeviceContainer d = ...;
...
Ptr stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
...
helper.EnableAscii (потік, d);

Ви можете ввімкнути трасування ascii для набору пар вузол/мережа-пристрій, надавши a
NodeContainer. Для кожного вузол , NodeContainer його додається NetDevices повторюються.
Для кожного NetDevice приєднаний до кожного вузла в контейнері, тип цього пристрою
перевірено. Для кожного пристрою належного типу (того самого типу, яким керує пристрій
помічник), трасування ввімкнено.:

NodeContainer n;
...
helper.EnableAscii ("префікс", n);

Це призведе до створення ряду файлів трасування ascii, кожен з яких наведено нижче
в - - конвенція .tr. Об’єднання всіх слідів в a
один файл виконується аналогічно наведеним вище прикладам:

Ви можете ввімкнути трасування pcap на основі ідентифікатора вузла та ідентифікатора пристрою, а також явно
Ptr. Кожен вузол в системі має цілочисельний ідентифікатор вузла і кожен пристрій підключено до вузла
має цілий ідентифікатор пристрою:

helper.EnableAscii ("префікс", 21, 1);

Звичайно, сліди можна об’єднати в один файл, як показано вище.

Нарешті, ви можете ввімкнути трасування pcap для всіх пристроїв у системі з тим самим типом, що й
яким керує помічник пристрою.:

helper.EnableAsciiAll ("префікс");

Це призведе до створення кількох файлів трасування ascii, по одному на кожен пристрій
система типу, керована помічником. Усі ці файли будуть слідувати за
- - конвенція .tr. Об’єднання всіх слідів в один
файл виконується аналогічно наведеним вище прикладам.

Ascii Простеження Пристрій Помічник ім'я файлу вибір
Неявно в описах методів у стилі префіксів вище є побудова завершеного
імена файлів за методом реалізації. За умовою, сліди ascii в нс-3 системи є
форми - id>- id>.tr.

Як згадувалося раніше, кожен вузол у системі матиме присвоєний системою ідентифікатор вузла; і
кожен пристрій матиме індекс інтерфейсу (також званий ідентифікатором пристрою) відносно свого вузла.
Таким чином, за замовчуванням файл трасування ascii створюється в результаті включення трасування на першому
пристрій вузла 21, використовуючи префікс "префікс", буде префікс-21-1.тр.

Ви завжди можете використовувати нс-3 сервіс імен об’єктів, щоб зробити це більш зрозумілим. Наприклад, якщо
ви використовуєте службу імен об’єктів, щоб призначити ім’я «сервер» вузлу 21, в результаті чого
Ім'я файлу трасування ascii автоматично стане, префікс-сервер-1.tr і якщо ви також призначите
ім'я "eth0" для пристрою, ім'я вашого файлу трасування ascii автоматично підбере це
і називатися префікс-сервер-eth0.tr.

Pcap Простеження протокол Помічники
Мета цих міксини полягає в тому, щоб полегшити додавання послідовного засобу відстеження pcap
протоколи. Ми хочемо, щоб усі різні варіанти трасування pcap працювали однаково для всіх
протоколів, тому методи цих помічників успадковуються помічниками стека. Подивись на
src/network/helper/trace-helper.h якщо ви хочете стежити за обговоренням, дивлячись на
реальний код.

У цьому розділі ми проілюструємо методи, що застосовуються до протоколу IPv4, до
вкажіть сліди в подібних протоколах, просто замініть відповідний тип. Наприклад,
використовувати a Ptr замість а Ptr і зателефонуйте Увімкнути PcapIpv6 замість Увімкнути PcapIpv4.

Клас PCapHelperForIpv4 забезпечує функціональність високого рівня для використання трасування pcap
, IPv4 протокол. Кожен помічник протоколу, що вмикає ці методи, повинен реалізувати один
віртуальний метод, успадкований від цього класу. Буде окрема реалізація для
IPv6, наприклад, але різниця буде лише в назвах методів і підписах.
Щоб усунути неоднозначність класу, потрібні різні імена методів IPv4 від IPv6 які обидва
походить від класу Об'єкт, і методи, які мають однаковий підпис.:

virtual void EnablePcapIpv4Internal (префікс std::string, Ptr ipv4, uint4_t інтерфейс) = 32;

Сигнатура цього методу відображає протокол і інтерфейс-центричний погляд
ситуація на цьому рівні. Усі відкриті методи, успадковані від класу PCapHelperForIpv4
зводяться до виклику цього методу реалізації, залежного від одного пристрою. Наприклад,
метод pcap найнижчого рівня:

void EnablePcapIpv4 (префікс std::string, Ptr ipv4, uint4_t інтерфейс);

буде називати реалізацію пристрою EnablePcapIpv4Internal безпосередньо. Вся інша громадськість
Методи трасування pcap базуються на цій реалізації, щоб забезпечити додатковий рівень користувача
функціональність. Для користувача це означає, що всі помічники протоколів у системі будуть
мати доступні всі методи трасування pcap; і всі ці методи будуть працювати однаково
шлях між протоколами, якщо помічник реалізує EnablePcapIpv4Internal правильно

Pcap Простеження протокол Помічник Методи
Ці методи розроблені так, щоб вони відповідали один до одного вузол- І
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 для класу PCapHelperForIpv4 щоб знайти деталі
цих методів; але підсумувати...

Ви можете ввімкнути трасування pcap для певної пари протокол/інтерфейс, надавши a
Ptr та інтерфейс в EnablePcap метод. Наприклад,:

Ptr ipv4 = вузол->GetObject ();
...
helper.EnablePcapIpv4 ("префікс", ipv4, 0);

Ви можете ввімкнути трасування pcap на певній парі вузол/мережа-пристрій, надавши a
std :: рядок представляє рядок служби імені об'єкта для an EnablePcap метод.
Ptr шукається з рядка імені. Наприклад,:

Імена::Додати ("serverIPv4" ...);
...
helper.EnablePcapIpv4 ("префікс", "serverIpv4", 1);

Ви можете ввімкнути трасування pcap для набору пар протокол/інтерфейс, надавши файл
Ipv4InterfaceContainer. Для кожного IPv4 / інтерфейсної пари в контейнері типу протоколу
перевіряється. Для кожного протоколу належного типу (того самого типу, яким керує
помічник пристрою), увімкнено трасування для відповідного інтерфейсу. Наприклад,:

вузли NodeContainer;
...
Пристрої NetDeviceContainer = deviceHelper.Install (вузли);
...
Ipv4AddressHelper ipv4;
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
Інтерфейси Ipv4InterfaceContainer = ipv4.Assign (пристрої);
...
helper.EnablePcapIpv4 («префікс», інтерфейси);

Ви можете ввімкнути трасування pcap для набору пар протокол/інтерфейс, надавши a
NodeContainer. Для кожного вузол , NodeContainer знайдено відповідний протокол. Для
кожного протоколу, його інтерфейси перераховуються, а на отриманому ввімкнено трасування
пари. Наприклад,:

NodeContainer n;
...
helper.EnablePcapIpv4 ("префікс", n);

Ви також можете ввімкнути трасування pcap на основі ідентифікатора вузла та інтерфейсу. В цьому випадку,
ідентифікатор вузла перекладається на a Ptr і відповідний протокол шукається в
вузол. Отриманий протокол та інтерфейс використовуються для вказівки результуючого трасування
джерело.:

helper.EnablePcapIpv4 ("префікс", 21, 1);

Нарешті, ви можете ввімкнути трасування pcap для всіх інтерфейсів у системі з пов’язаними
протокол того ж типу, що й керований помічником пристрою.:

helper.EnablePcapIpv4All ("префікс");

Pcap Простеження протокол Помічник ім'я файлу вибір
У всіх описаних вище методах неявно є побудова повного
імена файлів за методом реалізації. За умовою, трасування pcap береться для пристроїв у
нс-3 системи мають форму - id>- id>.pcap, У випадку
протоколів, між протоколами і є відповідність один до одного Nodes, Це
тому що протокол Об'єкти агреговані до вузол Об'єкти. Так як немає глобального протоколу
id в системі, ми використовуємо відповідний ідентифікатор вузла в іменуванні файлів. Тому існує а
можливість колізій імен файлів у автоматично вибраних іменах файлів трасування. Для цього
Причина, узгодження назв файлів змінено для трасування протоколу.

Як згадувалося раніше, кожен вузол у системі матиме присвоєний системою ідентифікатор вузла.
Оскільки між екземплярами протоколу та екземплярами вузлів існує відповідність один до одного
ми використовуємо ідентифікатор вузла. Кожен інтерфейс має ідентифікатор інтерфейсу відносно свого протоколу. Ми використовуємо
конвенція" -n -я .pcap" для іменування файлів трасування в
помічники протоколу.

Тому за замовчуванням файл трасування pcap створюється в результаті включення трасування
інтерфейс 1 протоколу Ipv4 вузла 21 з використанням префікса "prefix" буде
"prefix-n21-i1.pcap".

Ви завжди можете використовувати нс-3 сервіс імен об’єктів, щоб зробити це більш зрозумілим. Наприклад, якщо
Ви використовуєте службу імен об'єктів, щоб призначити ім'я "serverIpv4" Ptr на вузлі
21, ім'я файлу трасування pcap автоматично стане,
"prefix-nserverIpv4-i1.pcap".

Ascii Простеження протокол Помічники
Поведінка помічників трасування ascii суттєво подібна до випадку pcap. Візьміть а
дивитися на src/network/helper/trace-helper.h якщо ви хочете стежити за обговоренням
дивлячись на реальний код.

У цьому розділі ми проілюструємо методи, що застосовуються до протоколу IPv4, до
вкажіть сліди в подібних протоколах, просто замініть відповідний тип. Наприклад,
використовувати a Ptr замість а Ptr і зателефонуйте Увімкнути AsciiIpv6 замість
Увімкнути AsciiIpv4.

Клас AsciiTraceHelperForIpv4 додає функціональність високого рівня для використання ascii
трасування до помічника протоколу. Кожен протокол, що дозволяє ці методи, повинен реалізувати a
єдиний віртуальний метод, успадкований від цього класу.:

virtual void 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
доступний; і всі ці методи працюватимуть однаково в різних протоколах, якщо
впроваджувати протоколи EnableAsciiIpv4Internal правильно

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 stream, 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, 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 для певного протоколу/інтерфейсу
пару, надавши a Ptr і інтерфейс в УвімкнутиAscii метод. Наприклад,:

Ptr ipv4;
...
helper.EnableAsciiIpv4 ("префікс", ipv4, 1);

У цьому випадку контексти трасування не записуються до файлу трасування ascii, оскільки вони будуть
зайвий. Система вибере ім’я файлу, яке буде створено за тими ж правилами, що й
описано в розділі pcap, за винятком того, що файл матиме суфікс ".tr" замість
".pcap".

Якщо ви хочете ввімкнути трасування ascii на більш ніж одному інтерфейсі та надіслати всі трасування до
окремого файлу, ви також можете зробити це, використовуючи об’єкт для посилання на один файл. ми
вже є щось подібне до цього в прикладі "cwnd" вище:

Ptr protocol4 = node1->GetObject ();
Ptr protocol4 = node2->GetObject ();
...
Ptr stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
...
helper.EnableAsciiIpv4 (потік, протокол1, 1);
helper.EnableAsciiIpv4 (потік, протокол2, 1);

У цьому випадку контексти трасування записуються в файл трасування ascii, оскільки вони є обов’язковими
щоб усунути неоднозначність слідів від двох інтерфейсів. Зверніть увагу, що оскільки користувач повністю
вказуючи ім'я файлу, рядок повинен містити ".tr" для узгодженості.

Ви можете ввімкнути трасування ascii для певного протоколу, надавши a std :: рядок
представляє рядок служби імені об'єкта для an EnablePcap метод. Ptr is
відірвався від рядка імені. The в отриманих іменах файлів неявно, оскільки
між екземплярами протоколу та вузлами існує відповідність один до одного, наприклад:

Імена::Додати ("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 ("trace-file-name.tr");
...
helper.EnableAsciiIpv4 (потік, "node1Ipv4", 1);
helper.EnableAsciiIpv4 (потік, "node2Ipv4", 1);

Це призведе до створення одного файлу трасування під назвою "trace-file-name.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. Об’єднання всіх слідів в a
один файл виконується аналогічно наведеним вище прикладам:

вузли NodeContainer;
...
Пристрої NetDeviceContainer = deviceHelper.Install (вузли);
...
Ipv4AddressHelper ipv4;
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
Інтерфейси Ipv4InterfaceContainer = ipv4.Assign (пристрої);
...
Ptr stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
...
helper.EnableAsciiIpv4 (потік, інтерфейси);

Ви можете ввімкнути трасування ascii для набору пар протокол/інтерфейс, надавши a
NodeContainer. Для кожного вузол , NodeContainer знайдено відповідний протокол. Для
кожного протоколу, його інтерфейси перераховуються, а на отриманому ввімкнено трасування
пари. Наприклад,:

NodeContainer n;
...
helper.EnableAsciiIpv4 ("префікс", n);

Це призведе до створення ряду файлів трасування ascii, кожен з яких наведено нижче
в - - конвенція .tr. Об’єднання всіх слідів в a
один файл виконується аналогічно наведеним вище прикладам:

Ви також можете ввімкнути відстеження pcap на основі ідентифікатора вузла та ідентифікатора пристрою. В цьому випадку,
ідентифікатор вузла перекладається на a 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".

Простеження реалізація деталі
дані COLLECTION
У цій главі описується структура збору даних ns-3 (DCF), яка забезпечує
можливості отримувати дані, згенеровані моделями в симуляторі, виконувати в режимі онлайн
скорочення та обробка даних, а також перетворення необроблених або перетворених даних у різноманітні вихідні дані
форматах.

На даний момент фреймворк підтримує автономні запуски ns-3, які не покладаються на жодних зовнішніх
контроль виконання програми. Об’єкти, надані DCF, можуть бути підключені нс-3 простежувати
джерела для обробки даних.

Вихідний код для класів знаходиться в каталозі src/статистика.

Цей розділ організовано таким чином. По-перше, це огляд архітектури
представлений. Далі представлені помічники для цих занять; це початкове лікування
має дозволяти базове використання системи збору даних для багатьох випадків використання. Користувачі, які
хочуть виробляти вихід за межами сфери дії поточних помічників або бажають створити
їхні власні об'єкти збору даних, слід прочитати залишок розділу, який іде
детально про всі основні типи об’єктів DCF і забезпечує низькорівневе кодування
приклади

Дизайн
DCF складається з трьох основних класів:

· Зонд є механізмом для інструментування та контролю виведення даних моделювання, тобто
використовується для моніторингу цікавих подій. Він виробляє вихід у вигляді одного або кількох нс-3
джерела слідів. Об’єкти зонда підключаються до однієї або кількох трас мийки (називається
Колектори), які обробляють зразки в режимі онлайн та готують їх до виведення.

· Колекціонер споживає дані, згенеровані одним або кількома об’єктами Probe. Це виконує
перетворення даних, такі як нормалізація, скорочення та обчислення
основна статистика. Об’єкти-колектори не виробляють дані, які безпосередньо виводяться
ns-3 запуск; замість цього вони виводять дані за потоком до іншого типу об'єкта, який називається
Агрегатор, який виконує цю функцію. Зазвичай колектори виводять свої дані
також форму джерел слідів, що дозволяє з’єднувати колектори послідовно.

· Агрегатор є кінцевою точкою даних, зібраних мережею зондів і збирачів.
Основна відповідальність Агрегатора полягає в упорядкуванні даних та їх відповідності
метаданих у різні вихідні формати, такі як звичайні текстові файли, файли електронних таблиць або
бази даних

Усі три з цих класів надають можливість динамічно включатися або вимикатися
протягом всієї симуляції.

Будь-яка автономна нс-3 Запуск моделювання, який використовує DCF, зазвичай створює принаймні один
екземпляр кожного з трьох вищенаведених класів.
[зображення] Огляд системи збору даних.UNINDENT

Загальний потік обробки даних зображено в дані COLLECTION Рамки огляд.
З лівого боку біг нс-3 зображено моделювання. У ході виконання
моделювання, дані надаються моделями через джерела слідів або за допомогою інших засобів.
На схемі показано, що зонди можна підключити до цих джерел слідів для отримання даних
асинхронно, або зонди можуть опитувати дані. Дані потім передаються об’єкту-колектору
що перетворює дані. Нарешті, до виходів можна підключити агрегатор
колектор для створення графіків, файлів або баз даних.
[зображення] Data Collection Framework aggregation.UNINDENT

Варіант наведеного вище малюнка представлено в дані COLLECTION Рамки агрегація.
Цей другий малюнок ілюструє, що об'єкти DCF можуть бути пов'язані один з одним
що нижні об’єкти отримують вхідні дані від кількох вищестоящих об’єктів. Фігура
концептуально показує, що кілька зондів можуть генерувати вихід, який подається в один
колектор; наприклад, колектор, який виводить співвідношення двох лічильників
зазвичай отримують дані кожного лічильника з окремих зондів. Кілька колекторів також можуть
подавати в єдиний агрегатор, який (як випливає з його назви) може збирати ряд даних
потоки для включення в єдиний графік, файл або базу даних.

дані COLLECTION Помічники
Повна гнучкість системи збору даних забезпечується взаємоз'єднанням
зондів, колекторів та агрегаторів. Виконання всіх цих взаємозв’язків призводить до
багато конфігураційних операторів в програмах користувача. Для зручності використання одні з найпоширеніших
операції можуть бути об'єднані та інкапсульовані в допоміжні функції. Крім того, деякі
заяви за участю нс-3 джерела трасування не мають прив’язок Python через обмеження в
палітурки.

дані COLLECTION Помічники Про платформу
У цьому розділі ми надаємо огляд деяких допоміжних класів, які були створені для
полегшити конфігурацію системи збору даних для деяких поширених випадків використання. The
помічники дозволяють користувачам формувати звичайні операції лише з кількома операторами в C++ або
Програми на Python. Але така простота використання обходиться значно меншою ціною
гнучкість, ніж може забезпечити низькорівнева конфігурація, і необхідність явного кодування
підтримка нових типів Probe у помічниках (щоб обійти проблему, описану нижче).

Акцент на поточних помічників полягає в маршуванні даних з нс-3 простежити джерела в
графіки або текстові файли gnuplot без високого ступеня налаштування виводу чи статистичних даних
обробка (спочатку). Крім того, використання обмежено доступними типами зондів
нс-3. У наступних розділах цієї документації детальніше про створення нового
Типи зондів, а також відомості про з’єднання зондів, колекторів та агрегаторів
в нестандартних аранжуваннях.

На сьогоднішній день реалізовано два помічника зі збору даних:

· GnuplotHelper

· FileHelper

GnuplotHelper
GnuplotHelper — це допоміжний клас для створення вихідних файлів, які використовуються для створення gnuplot. The
загальна мета — надати користувачам можливість швидко створювати графіки з експортованих даних
in нс-3 джерела слідів. За замовчуванням виконується мінімальний обсяг перетворення даних;
Мета полягає в тому, щоб генерувати графіки з мінімальною кількістю конфігураційних операторів (за замовчуванням).
можливо.

GnuplotHelper Про платформу
GnuplotHelper створить 3 різні файли в кінці моделювання:

· Файл даних gnuplot, розділений пробілом

· Керуючий файл gnuplot

· Сценарій оболонки для створення gnuplot

Для створення графіків необхідні два оператори конфігурації. Перший
оператор конфігурує графік (назва файлу, назва, легенди та тип виводу, де вихід
Тип за замовчуванням - PNG, якщо не вказано):

void ConfigurePlot (const std::string &outputFileNameWithoutExtension,
const std::string &title,
const std::string &xLegend,
const std::string &yLegend,
const std::string &terminalType = ".png");

Другий оператор підключає джерело трасування, що цікавить:

void PlotProbe (const std::string &typeId,
const std::string &path,
const std::string &probeTraceSource,
const std::string &title);

Аргументи такі:

· typeId: The нс-3 Ідентифікатор типу зонда

· шлях: Шлях у нс-3 простір імен конфігурації до одного або кількох джерел трасування

· probeTraceSource: який вихід зонда (саме є джерелом трасування) слід побудувати

· title: назва, яка пов'язується з набором(ами) даних (в легенді gnuplot)

Варіант PlotProbe вище — це вказати п’ятий необов’язковий аргумент, який контролює
де в сюжеті розміщено ключ (легенда).

Повністю відпрацьований приклад (з сьомий.cc) показано нижче:

// Створити помічник gnuplot.
GnuplotHelper plotHelper;

// Налаштувати графік.
// Налаштувати графік. Першим аргументом є префікс імені файлу
// для згенерованих вихідних файлів. Другий, третій і четвертий
// аргументами є, відповідно, назва графіка, вісь x та мітки осі Y
plotHelper.ConfigurePlot ("seventh-packet-byte-count",
"Кількість пакетних байтів проти часу",
«Час (секунди)»,
"Кількість пакетних байтів",
"png");

// Вказуємо тип проби, шлях до джерела трасування (у просторі імен конфігурації) та
// досліджуємо вихідне джерело трасування ("OutputBytes") для побудови графіка. Аргумент четвертий
// вказує назву мітки ряду даних на графіку. Останній
// аргумент форматує графік, вказуючи, де повинен бути розміщений ключ.
plotHelper.PlotProbe (probeType,
tracePath,
"Вихідні байти",
"Кількість пакетних байтів",
GnuplotAggregator::KEY_BELOW);

У цьому прикладі файл ProbeType та tracePath наведені нижче (для IPv4):

probeType = "ns3::Ipv4PacketProbe";
tracePath = "/NodeList/*/$ns3::Ipv4L3Protocol/Tx";

ProbeType є ключовим параметром для роботи цього помічника. Цей TypeId має бути зареєстрований
в системі, а підпис на приймачі трасування зонда має відповідати підпису трасування
джерело, до якого він підключений. Типи зондів попередньо визначені для ряду типів даних
відповідний нс-3 відстежуваних значень, а також для кількох інших сигнатур джерел трасування, таких як
джерело трасування 'Tx' ns3::Протокол Ipv4L3 клас.

Зауважте, що вказаний шлях джерела трасування може містити символи підстановки. У цьому випадку множинні
набори даних нанесені на один графік; по одному для кожного відповідного шляху.

Основним результатом буде три файли:

сьомий-пакет-байт-count.dat
seventh-packet-byte-count.plt
сьомий-пакет-байт-count.sh

На цьому етапі користувачі можуть вручну редагувати файл .plt для подальших налаштувань, або
просто запустіть його через gnuplot. Біг sh сьомий-пакет-байт-count.sh просто керує сюжетом
через gnuplot, як показано нижче.
[зображення] 2-D Gnuplot Створено seventh.cc Приклад..UNINDENT

Можна помітити, що ключові елементи (легенда, назва, розміщення легенди, xlabel, ylabel,
і шлях для даних) розміщуються на графіку. Оскільки було два матчі до
наданий шлях конфігурації, показано два ряди даних:

· Кількість байтів пакетів-0 відповідає /NodeList/0/$ns3::Ipv4L3Protocol/Tx

· Кількість байтів пакетів-1 відповідає /NodeList/1/$ns3::Ipv4L3Protocol/Tx

GnuplotHelper ConfigurePlot
GnuplotHelper ConfigurePlot() функцію можна використовувати для налаштування графіків.

Він має наступний прототип:

void ConfigurePlot (const std::string &outputFileNameWithoutExtension,
const std::string &title,
const std::string &xLegend,
const std::string &yLegend,
const std::string &terminalType = ".png");

Він має такі аргументи:

┌────────────────────────────────┬──────────────── ───────────────────┐
│Аргумент │ Опис │
├────────────────────────────────┼──────────────── ──────────────────┤
│outputFileNameWithoutExtension │ Ім'я файлів, пов'язаних з gnuplot до │
│ │ писати без розширення. │
├────────────────────────────────┼──────────────── ──────────────────┤
│заголовок │ Наведіть рядок заголовка для використання для │
│ │ цей сюжет. │
├────────────────────────────────┼──────────────── ──────────────────┤
│xLegend │ Легенда для x горизонтального │
│ │ вісь. │
├────────────────────────────────┼──────────────── ──────────────────┤
│yЛегенда │ Легенда для y вертикалі │
│ │ вісь. │
└────────────────────────────────┴──────────────── ───────────────────┘

│terminalType │ Рядок налаштування типу терміналу для │
│ │ вихід. Термінал за замовчуванням │
│ │ тип «png». │
└────────────────────────────────┴──────────────── ───────────────────┘

GnuplotHelper ConfigurePlot() функція налаштовує для цього параметри, пов’язані з графіком
Помічник gnuplot, щоб він створив файл даних gnuplot, розділений пробілом, з ім
outputFileNameWithoutExtension + ".dat", керуючий файл gnuplot з ім'ям
outputFileNameWithoutExtension + ".plt" і сценарій оболонки для створення gnuplot з ім'ям
outputFileNameWithoutExtension + ".sh".

Приклад використання цієї функції можна побачити в сьомий.cc код, описаний вище
де він використовувався наступним чином:

plotHelper.ConfigurePlot ("seventh-packet-byte-count",
"Кількість пакетних байтів проти часу",
«Час (секунди)»,
"Кількість пакетних байтів",
"png");

GnuplotHelper PlotProbe
GnuplotHelper PlotProbe() функцію можна використовувати для побудови графіка значень, згенерованих зондами.

Він має наступний прототип:

void PlotProbe (const std::string &typeId,
const std::string &path,
const std::string &probeTraceSource,
const std::string &title,
enum GnuplotAggregator::KeyLocation keyLocation = GnuplotAggregator::KEY_INSIDE);

Він має такі аргументи:

┌─────────────────┬─────────────────────────────── ───┐
│Аргумент │ Опис │
├─────────────────┼─────────────────────────────── ───┤
│typeId │ Ідентифікатор типу для зонда │
│ │ створений цим помічником. │
├─────────────────┼─────────────────────────────── ───┤
│шлях │ Конфігураційний шлях для доступу до трасування │
│ │ джерело. │
├─────────────────┼─────────────────────────────── ───┤
│probeTraceSource │ Джерело трасування зонда до │
│ │ доступ. │
├─────────────────┼─────────────────────────────── ───┤
│title │ Назва, яка буде пов'язана з │
│ │ цей набір даних │
├─────────────────┼─────────────────────────────── ───┤
│keyLocation │ Розташування ключа в │
│ │ ділянка. Розташування за замовчуванням — │
│ │ всередині. │
└─────────────────┴─────────────────────────────── ───┘

GnuplotHelper PlotProbe() функція відображає набір даних, згенерований шляхом підключення нс-3
відстеження джерела за допомогою зонда, створеного допоміжником, а потім побудови графіка значень з
probeTraceSource. Набір даних матиме вказану назву та складатиметься з
'newValue' для кожної позначки часу.

Якщо шлях конфігурації має більше одного збігу в системі, тому що є символ підстановки, тоді
буде нанесено один набір даних для кожного збігу. Назви наборів даних будуть доповнюватися суфіксами
відповідні символи для кожного з підстановочних знаків у шляху конфігурації, розділені пробілами. Для
наприклад, якщо запропонована назва набору даних — це рядок «байти» і є два символи підстановки
на шляху, тоді заголовки наборів даних, як-от "bytes-0 0" або "bytes-12 9", будуть можливі як
мітки для наборів даних, які зображуються.

Приклад використання цієї функції можна побачити в сьомий.cc код, описаний вище
де він використовувався (із заміною змінної) таким чином:

plotHelper.PlotProbe ("ns3::Ipv4PacketProbe",
"/NodeList/*/$ns3::Ipv4L3Protocol/Tx",
"Вихідні байти",
"Кількість пакетних байтів",
GnuplotAggregator::KEY_BELOW);

Інше прикладів
Гнуплот Помічник Приклад
Трохи простіший приклад, ніж сьомий.cc приклад можна знайти в
src/stats/examples/gnuplot-helper-example.cc. Наступний 2-D gnuplot було створено за допомогою
приклад.
[зображення] 2-D Gnuplot Створено gnuplot-helper-example.cc Приклад..UNINDENT

У цьому прикладі є об’єкт Emitter, який збільшує свій лічильник відповідно до a
Пуассона, а потім видає значення лічильника як джерело трасування.

Ptr випромінювач = CreateObject ();
Names::Add ("/Names/Emitter", емітер);

Зауважте, що оскільки в шляху, використаному нижче, немає символів підстановки, був лише 1 потік даних
намальований у сюжеті. Цей єдиний потік даних на графіку просто позначений «Кількість випромінювачів»,
без додаткових суфіксів, як можна було б побачити, якби на шляху були символи підстановки.

// Створити помічник gnuplot.
GnuplotHelper plotHelper;

// Налаштувати графік.
plotHelper.ConfigurePlot ("gnuplot-helper-example",
"Кількість випромінювачів проти часу",
«Час (секунди)»,
"Кількість випромінювачів",
"png");

// Побудова значень, згенерованих зондом. Шлях, який ми пропонуємо
// допомагає розкрити джерело сліду.
plotHelper.PlotProbe ("ns3::Uinteger32Probe",
"/Names/Emitter/Counter",
«Вихід»,
"Кількість випромінювачів",
GnuplotAggregator::KEY_INSIDE);

FileHelper
FileHelper — це допоміжний клас, який використовується для розміщення значень даних у файлі. Загальна мета є
щоб надати користувачам можливість швидко створювати форматовані текстові файли з експортованих даних
in нс-3 джерела слідів. За замовчуванням виконується мінімальний обсяг перетворення даних;
Метою є створення файлів із мінімальною кількістю конфігураційних операторів (за замовчуванням).
можливо.

FileHelper Про платформу
FileHelper створить 1 або більше текстових файлів наприкінці моделювання.

FileHelper може створювати 4 різні типи текстових файлів:

· Відформатований

· розділений пробілом (за замовчуванням)

· Через кому

· Розділені табуляції

Відформатовані файли використовують рядки формату в стилі C і функцію sprintf() для їх друку
значення у файлі, який записується.

Наведений нижче текстовий файл із 2 стовпцями відформатованих значень
seventh-packet-byte-count-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 стовпців форматованих значень
seventh-packet-byte-count-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 окремі текстові файли
були створені. Перший текстовий файл, який називається "seventh-packet-byte-count-0.txt",
відповідає збігу підстановкового знака із «*» заміненим на «0». Другий текстовий файл,
який називається "seventh-packet-byte-count-1.txt", відповідає підстановочному знаку з
"*" замінено на "1". Також зверніть увагу, що виклик функції до WriteProbe() дасть ан
повідомлення про помилку, якщо немає збігів для шляху, який містить символи підстановки.

// Створити допоміжний файл.
FileHelper fileHelper;

// Налаштувати файл для запису.
fileHelper.ConfigureFile ("seventh-packet-byte-count",
FileAggregator::FORMATTED);

// Встановлюємо мітки для цього форматованого вихідного файлу.
fileHelper.Set2dFormat ("Час (секунди) = %.3e\tКількість байтів пакетів = %.0f");

// Запис значень, згенерованих зондом.
fileHelper.WriteProbe ("ns3::Ipv4PacketProbe",
"/NodeList/*/$ns3::Ipv4L3Protocol/Tx",
«OutputBytes»);

FileHelper ConfigureFile
FileHelper ConfigureFile() Функцію можна використовувати для налаштування текстових файлів.

Він має наступний прототип:

void ConfigureFile (const std::string &outputFileNameWithoutExtension,
enum FileAggregator::FileType fileType = FileAggregator::SPACE_SEPARATED);

Він має такі аргументи:

┌────────────────────────────────┬──────────────── ───────────────────┐
│Аргумент │ Опис │
├────────────────────────────────┼──────────────── ──────────────────┤
│outputFileNameWithoutExtension │ Назва вихідного файлу для запису │
│ │ без розширення. │
├────────────────────────────────┼──────────────── ──────────────────┤
│fileType │ Тип файлу для запису. │
│ │ Типом файлу за замовчуванням є пробіл │
│ │ відокремлено. │
└────────────────────────────────┴──────────────── ───────────────────┘

FileHelper ConfigureFile() функція налаштовує параметри, пов’язані з текстовим файлом для
допоміжний файл, щоб він створив файл з іменем outputFileNameWithoutExtension plus
можлива додаткова інформація зі збігів із підстановочними знаками плюс ".txt" зі значеннями, надрукованими як
визначений типом файлу. Тип файлу за замовчуванням розділений пробілом.

Приклад використання цієї функції можна побачити в сьомий.cc код, описаний вище
де він використовувався наступним чином:

fileHelper.ConfigureFile ("seventh-packet-byte-count",
FileAggregator::FORMATTED);

FileHelper WriteProbe
FileHelper WriteProbe() Функцію можна використовувати для запису значень, згенерованих зондами
текстові файли.

Він має наступний прототип:

void WriteProbe (const std::string &typeId,
const std::string &path,
const std::string &probeTraceSource);

Він має такі аргументи:

┌─────────────────┬─────────────────────────────── ───┐
│Аргумент │ Опис │
├─────────────────┼─────────────────────────────── ───┤
│typeId │ Ідентифікатор типу для зонда, який має бути │
│ │ створено. │
├─────────────────┼─────────────────────────────── ───┤
│шлях │ Конфігураційний шлях для доступу до трасування │
│ │ джерело. │
├─────────────────┼─────────────────────────────── ───┤
│probeTraceSource │ Джерело трасування зонда до │
│ │ доступ. │
└─────────────────┴─────────────────────────────── ───┘

FileHelper WriteProbe() функція створює вихідні текстові файли, згенеровані шляхом підключення
ns-3 джерело трасування за допомогою зонда, створеного допоміжником, а потім запису значень із файлу
probeTraceSource. Назви вихідних файлів будуть мати текст, збережений у змінній-члені
m_outputFileNameWithoutExtension плюс ".txt", і складатиметься з "newValue" у кожному
мітка часу.

Якщо шлях конфігурації має більше одного збігу в системі, тому що є символ підстановки, тоді
буде створено один вихідний файл для кожного збігу. Імена вихідних файлів будуть містити
текст у m_outputFileNameWithoutExtension плюс відповідні символи для кожного з
символи підстановки в шляху конфігурації, розділені тире, плюс ".txt". Наприклад, якщо значення
у m_outputFileNameWithoutExtension є рядок "packet-byte-count", і є два
символи підстановки в шляху, а потім виведіть імена файлів, наприклад "packet-byte-count-0-0.txt" або
"packet-byte-count-12-9.txt" буде можливим як імена для файлів, які будуть створені.

Приклад використання цієї функції можна побачити в сьомий.cc код, описаний вище
де він використовувався наступним чином:

fileHelper.WriteProbe ("ns3::Ipv4PacketProbe",
"/NodeList/*/$ns3::Ipv4L3Protocol/Tx",
«OutputBytes»);

Інше прикладів
Файл Помічник Приклад
Трохи простіший приклад, ніж сьомий.cc приклад можна знайти в
src/stats/examples/file-helper-example.cc. У цьому прикладі використовується лише FileHelper.

Наведений нижче текстовий файл із 2 стовпцями відформатованих значень file-helper-example.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, який збільшує свій лічильник відповідно до a
Пуассона, а потім видає значення лічильника як джерело трасування.

Ptr випромінювач = CreateObject ();
Names::Add ("/Names/Emitter", емітер);

Зауважте, що оскільки в шляху, використаному нижче, немає символів підстановки, був лише 1 текстовий файл
створений. Цей єдиний текстовий файл називається просто "file-helper-example.txt", без додаткових
суфікси, як ви б побачили, якби на шляху були символи підстановки.

// Створити допоміжний файл.
FileHelper fileHelper;

// Налаштувати файл для запису.
fileHelper.ConfigureFile ("файл-помічник-приклад",
FileAggregator::FORMATTED);

// Встановлюємо мітки для цього форматованого вихідного файлу.
fileHelper.Set2dFormat ("Час (секунди) = %.3e\tCount = %.0f");

// Запис значень, згенерованих зондом. Шлях, який ми
// provide допомагає розкрити джерело сліду.
fileHelper.WriteProbe ("ns3::Uinteger32Probe",
"/Names/Emitter/Counter",
«Вихід»);

Сфера та Недоліки
Наразі лише ці зонди реалізовані та підключені до GnuplotHelper і
до FileHelper:

· BooleanProbe

· DoubleProbe

· Uinteger8Probe

· Uinteger16Probe

· Uinteger32Probe

· TimeProbe

· PacketProbe

· ApplicationPacketProbe

· Ipv4PacketProbe

Таким чином, ці пробники є єдиними типами ідентифікаторів, які можна використовувати PlotProbe() та
WriteProbe().

У наступних кількох розділах ми розглянемо кожен із основних типів об’єктів (зонд, колектор,
та Aggregator) більш детально та показати, як їх можна з’єднати разом за допомогою
API нижнього рівня.

Зонди
У цьому розділі детально описані функції, надані класом Probe для an нс-3
моделювання та наводить приклади того, як їх кодувати в програмі. Цей розділ призначений для
користувачів, зацікавлених у розробці моделювання за допомогою нс-3 інструменти та використання Даних
Collection Framework, частиною якого є клас Probe, для створення вихідних даних
результати їхнього моделювання.

Зонд Про платформу
Передбачається, що об’єкт Probe підключений до змінної із симуляції, значення якої
протягом усього експерименту мають відношення до користувача. Зонд зафіксує, що було
значення, які приймає змінна протягом усього моделювання, і передають такі дані іншій
член платформи збору даних. Хоча це виходить за рамки цього розділу
обговорити, що відбувається після того, як Зонд видає свої результати, достатньо сказати, що до
Після закінчення моделювання користувач отримає детальну інформацію про те, які значення були
зберігається всередині змінної, що досліджується під час моделювання.

Як правило, зонд підключається до нс-3 джерело сліду. Таким чином, будь-коли
джерело трасування експортує нове значення, Probe споживає це значення (і експортує його вниз по ходу
до іншого об’єкта через власне джерело трасування).

Зонд можна розглядати як свого роду фільтр джерел слідів. Основні причини для
можливе підключення до зонда, а не безпосередньо до джерела слідування:

· Зонди можуть динамічно вмикатися та вимикатися під час моделювання із викликами до Увімкнути()
та Вимкнути(). Наприклад, виведення даних може бути вимкнено під час
фаза розігріву моделювання.

· Зонди можуть виконувати операції з даними для вилучення значень із більш складних
конструкцій; наприклад, виведення значення розміру пакета з отриманого пакета ns3::Packet.

· Зонди реєструють ім'я в просторі імен ns3::Config (за допомогою Назви::Додати ()) так що інше
об'єкти можуть посилатися на них.

· Зонди забезпечують статичний метод, який дозволяє маніпулювати зондом за іменем, наприклад
що робиться в ns2measure [Cic06]

Stat::put ("my_metric", ID, зразок);

Еквівалентом ns-3 вищезгаданого коду ns2measure є, наприклад

DoubleProbe::SetValueByPath ("/шлях/до/зонд", зразок);

Створення
Зауважте, що об’єкт базового класу Probe не можна створити, оскільки він є абстрактною базою
клас, тобто він має чисті віртуальні функції, які не були реалізовані. Об'єкт з
Тип DoubleProbe, який є підкласом класу Probe, буде створено тут для відображення
що потрібно зробити.

Один оголошує DoubleProbe у динамічній пам’яті за допомогою класу розумного покажчика (Ptr ). До
створити DoubleProbe у динамічній пам’яті з розумними покажчиками, потрібно лише викликати
нс-3 метод CreateObject():

Ptr myprobe = Створити об'єкт ();

Оголошення вище створює DoubleProbes, використовуючи значення за замовчуванням для його атрибутів.
У класі DoubleProbe є чотири атрибути; два в об'єкті базового класу
DataCollectionObject і два в базовому класі Probe:

· «Назва» (DataCollectionObject), StringValue

· «Увімкнено» (DataCollectionObject), логічне значення

· «Start» (Probe), a TimeValue

· "Stop" (Probe), a TimeValue

Такі атрибути можна встановити при створенні об’єкта, використовуючи такий метод:

Ptr myprobe = CreateObjectWithAttributes (
"Ім'я", StringValue ("myprobe"),
"Enabled", BooleanValue (false),
"Початок", TimeValue (Секунди (100.0)),
«Зупинити», TimeValue (Секунди (1000.0)));

Пуск і Зупинка — це змінні часу, які визначають інтервал дії датчика. The
Зонд виводить дані, лише якщо поточний час моделювання знаходиться всередині цього
інтервал. Спеціальне значення часу 0 секунд для зупинки вимкне цей атрибут (тобто
тримайте Probe увімкненим протягом усієї симуляції). Увімкнено – це прапорець, який вмикає зонд або
вимкнено, і має бути встановлене значення true, щоб зонд експортував дані. Ім'я - це ім'я об'єкта
в рамках DCF.

Імпортуючий та експорту дані
нс-3 Джерела слідів сильно типізовані, тому механізми підключення зондів до трасування
джерело та для експорту даних належать до його підкласів. Наприклад, за замовчуванням
розповсюдження нс-3 надає клас DoubleProbe, який призначений для підключення до трасування
джерело експортує подвійне значення. Далі ми детально розповімо про роботу DoubleProbe і
потім обговоріть, як інші класи Probe можуть бути визначені користувачем.

DoubleProbe Про платформу
DoubleProbe підключається до подвійного значення нс-3 джерело сліду, а сам експортує a
різні подвійні нс-3 джерело сліду.

Наступний код, взятий з src/stats/examples/double-probe-example.cc, показує основні
операції переведення DoubleProbe в симуляцію, де він досліджує лічильник
експортується об’єктом-випромінювачем (клас Emitter).

Ptr випромінювач = CreateObject ();
Names::Add ("/Names/Emitter", емітер);
...

Ptr probe1 = Створити об'єкт ();

// Підключаємо зонд до лічильника випромінювача
bool connected = probe1->ConnectByObject («Лічильник», емітер);

Наступний код перевіряє той самий лічильник, експортований тим самим об’єктом випромінювача. Це
DoubleProbe, однак, використовує шлях у просторі імен конфігурації для створення
підключення. Зауважте, що емітер зареєструвався в просторі імен конфігурації після
він був створений; інакше ConnectByPath не працюватиме.

Ptr probe2 = Створити об'єкт ();

// Примітка, тут не перевіряється значення, що повертається
probe2->ConnectByPath ("/Names/Emitter/Counter");

Наступний показаний нижче DoubleProbe буде мати значення за допомогою свого шляху
простір імен конфігурації. Зауважте, що цього разу DoubleProbe зареєструвався в
простір імен конфігурації після його створення.

Ptr probe3 = Створити об'єкт ();
probe3->SetName ("StaticallyAccessedProbe");

// Ми повинні додати його до бази даних конфігурації
Names::Add ("/Names/Probes", probe3->GetName (), probe3);

Функція Count() випромінювача тепер може встановити значення для цього DoubleProbe як
наступним чином:

анулювати
Випромінювач::Count (недійсний)
{
...
m_counter += 1.0;
DoubleProbe::SetValueByPath ("/Names/StatticalAccessedProbe", 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 експортує подвійні значення в своє джерело трасування "Output"; об'єкт нижче за течією
можна підключити приймач трасування (NotifyViaProbe) до цього наступним чином:

connect = probe1->TraceConnect ("Output", probe1->GetName (), MakeCallback (&NotifyViaProbe));

Інше зонди
Крім DoubleProbe, також доступні такі датчики:

· Uinteger8Probe підключається до an нс-3 джерело трасування, що експортує uint8_t.

· Uinteger16Probe підключається до an нс-3 джерело трасування, що експортує uint16_t.

· Uinteger32Probe підключається до an нс-3 джерело трасування, що експортує uint32_t.

· PacketProbe підключається до нс-3 джерело трасування, що експортує пакет.

· ApplicationPacketProbe підключається до нс-3 джерело трасування, що експортує пакет і сокет
адреса

· Ipv4PacketProbe підключається до нс-3 джерело трасування, що експортує пакет, об’єкт IPv4 та
інтерфейс.

створення new Зонд Типи
Щоб створити новий тип зонда, потрібно виконати такі дії:

· Переконайтеся, що ваш новий клас Probe є похідним від базового класу Probe.

· Переконайтеся, що чисті віртуальні функції, які ваш новий клас Probe успадковує від
Реалізовано базовий клас зонда.

· Знайдіть існуючий клас Probe, який використовує джерело трасування, найближче за типом до
тип джерела трасування, який буде використовувати ваш зонд.

· Скопіюйте існуючий файл заголовка класу Probe (.h) і файл реалізації (.cc) до двох
нові файли з іменами, що відповідають вашому новому зонду.

· Замініть типи, аргументи та змінні у скопійованих файлах відповідними
тип для вашого зонда.

· Зробіть необхідні зміни, щоб компілювати код і щоб він поводився так, як ви б
люблю.

прикладів
Тут буде детально розглянуто два приклади:

· Приклад подвійного датчика

· Приклад діаграми пакетів IPv4

подвійний Зонд Приклад
Приклад подвійного зонда обговорювався раніше. Приклад програми можна знайти
in src/stats/examples/double-probe-example.cc. Щоб підсумувати те, що відбувається в цій програмі,
є випромінювач, який експортує лічильник, який збільшується відповідно до процесу Пуассона.
Зокрема, показано два способи випромінювання даних:

1. через простежувану змінну, підключену до одного зонда:

TracedValue m_counter; // зазвичай це буде цілочисельний тип

2. через лічильник, значення якого надсилається в другий зонд, на який посилається його ім'я в
система конфігурації:

анулювати
Випромінювач::Count (недійсний)
{
NS_LOG_FUNCTION (це);
NS_LOG_DEBUG ("Розрахунок на " << Simulator::Now ().GetSeconds ());
m_counter += 1.0;
DoubleProbe::SetValueByPath ("/Names/StatticalAccessedProbe", m_counter);
Simulator::Schedule (Секунди (m_var->GetValue ()), &Emitter::Count, це);
}

Розглянемо зонд уважніше. Зонди можуть отримувати свої значення множинно
способи:

1. шляхом прямого доступу зонда до джерела слідів і підключення до нього прийому слідів

2. шляхом доступу зонда до джерела трасування через простір імен config та підключення a
слід до нього

3. кодом виклику, який явно викликає зонд SetValue() метод

4. за кодом виклику явно викликає SetValueByPath
("/шлях/через/Конфігурація/простір імен", ...)

Очікується, що перші дві методики будуть найпоширенішими. Також у прикладі
показано підключення звичайної функції зворотного виклику, як це зазвичай робиться в нс-3, це
функція зворотного виклику не пов'язана з об'єктом Probe. Нижче ми назвемо цей випадок 0).

// Це функція для перевірки підключення необробленої функції до джерела трасування
анулювати
NotifyViaTraceSource (std::string context, подвійний oldVal, подвійний newVal)
{
NS_LOG_DEBUG ("контекст: " << контекст << " old " << oldVal << " new " << newVal);
}

Спочатку необхідно налаштувати випромінювач:

Ptr випромінювач = CreateObject ();
Names::Add ("/Names/Emitter", емітер);

// Об'єкт Emitter не пов'язаний з вузлом ns-3, отже
// він не почнеться автоматично, тому нам потрібно зробити це самостійно
Симулятор::Розклад (Секунди (0.0), &Emitter::Start, emitter);

Різні DoubleProbes взаємодіють з випромінювачем у прикладі, як показано нижче.

Випадок 0):

// Нижче показано типову функціональність без зонда
// (підключити функцію-приймач до джерела трасування)
//
connect = emitter->TraceConnect ("Лічильник", "зразок контексту", MakeCallback (&NotifyViaTraceSource));
NS_ASSERT_MSG (підключено, "Джерело трасування не підключено");

випадок 1):

//
// Probe1 буде підключено безпосередньо до об'єкта джерела трасування Emitter
//

// probe1 буде підключено до джерела трасування Emitter
Ptr probe1 = Створити об'єкт ();
// назва пробника може служити його контекстом у трасуванні
probe1->SetName ("ObjectProbe");

// Підключаємо зонд до лічильника випромінювача
connect = probe1->ConnectByObject («Лічильник», випромінювач);
NS_ASSERT_MSG (підключено, "Джерело трасування не підключено до зонда 1");

випадок 2):

//
// Probe2 буде підключено до об'єкта джерела трасування Emitter за допомогою
// доступ до нього за іменем шляху в базі даних Config
//

// Створити інший подібний зонд; це буде підключено через шлях конфігурації
Ptr probe2 = Створити об'єкт ();
probe2->SetName ("PathProbe");

// Примітка, тут не перевіряється значення, що повертається
probe2->ConnectByPath ("/Names/Emitter/Counter");

випадок 4) (випадок 3 не показаний у цьому прикладі):

//
// Probe3 буде викликано випромінювачем безпосередньо через
// статичний метод SetValueByPath().
//
Ptr probe3 = Створити об'єкт ();
probe3->SetName ("StaticallyAccessedProbe");
// Ми повинні додати його до бази даних конфігурації
Names::Add ("/Names/Probes", probe3->GetName (), probe3);

І, нарешті, приклад показує, як можна підключити зонди для генерування результату:

// Сам зонд повинен генерувати вихід. Контекст, який ми надаємо
// до цього пробника (у цьому випадку ім'я пробника) допоможе розібратися
// джерело сліду
підключений = probe3->TraceConnect ("Вихід",
"/Names/Probes/StaticallyAccessedProbe/Output",
MakeCallback (&NotifyViaProbe));
NS_ASSERT_MSG (підключено, "Джерело трасування не .. підключено до виходу пробника3");

Наступний зворотний виклик підключено до Probe в цьому прикладі для ілюстрації;
зазвичай, зонд підключається до об’єкта Collector.

// Це функція для перевірки підключення її до виходу пробника
анулювати
NotifyViaProbe (std::string context, подвійний oldVal, подвійний newVal)
{
NS_LOG_DEBUG ("контекст: " << контекст << " old " << oldVal << " new " << newVal);
}

IPv4 Пакет Сюжет Приклад
Приклад діаграми пакету IPv4 заснований на прикладі fifth.cc з нс-3 Підручник. Це
можна знайти в src/stats/examples/ipv4-packet-plot-example.cc.

вузол 0 вузол 1
+----------------+ +----------------+
| ns-3 TCP | | ns-3 TCP |
+----------------+ +----------------+
| 10.1.1.1 | | 10.1.1.2 |
+----------------+ +----------------+
| точка-точка | | точка-точка |
+----------------+ +----------------+
| |
+--------------------+

Ми просто подивимося на Probe, оскільки він ілюструє, що Probes також може розпаковувати значення
структури (у даному випадку пакети) і повідомляють ці значення як вихідні дані джерела трасування
ніж просто передача даних одного типу.

Є й інші аспекти цього прикладу, які будуть пояснені пізніше в документації.
Експортуються два типи даних – це сам пакет (Вихід) і кількість
кількість байтів у пакеті (Вихідні байти).

TypeId
Ipv4PacketProbe::GetTypeId ()
{
статичний TypeId tid = TypeId ("ns3::Ipv4PacketProbe")
.SetParent ()
.AddConstructor ()
.AddTraceSource ( "Вихід",
"Пакет плюс його об'єкт IPv4 та інтерфейс, які служать виходом для цього зонда",
MakeTraceSourceAccessor (&Ipv4PacketProbe::m_output))
.AddTraceSource ( "OutputBytes",
«Кількість байтів у пакеті»,
MakeTraceSourceAccessor (&Ipv4PacketProbe::m_outputBytes))
;
повертатися до їжі;
}

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

анулювати
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, packetSizeNew);
m_packetSizeOld = packetSizeNew;
}
}

посилання
[Cic06]
Клаудіо Чикконетті, Енцо Мінгоцці, Джованні Стеа, «Інтегрована структура для
Забезпечення ефективного збору даних та статистичного аналізу за допомогою ns2, Workshop on
ns-2 (WNS2), Піза, Італія, жовтень 2006 р.

Колектори
Цей розділ є заповнювачем для детального опису функцій, наданих Collector
клас до an нс-3 моделювання та наводить приклади того, як їх кодувати в програмі.

Примітка: Станом на ns-3.18, Collector все ще розробляються і ще не надаються як частина
рамки.

Агрегатори
У цьому розділі детально описано функціональні можливості, надані класом Aggregator для an нс-3
моделювання. Цей розділ призначений для користувачів, зацікавлених у розробці моделювання за допомогою
нс-3 інструменти та використання Data Collection Framework, класом Aggregator якого є a
частина, щоб генерувати вихідні дані з результатами їх моделювання.

Агрегатор Про платформу
Передбачається, що для цього об’єкт агрегатора має бути підключений до одного або кількох джерел трасування
отримати вхідні дані. Агрегатори є кінцевою точкою даних, зібраних мережею
Зонди та колектори під час моделювання. Завдання агрегатора – взяти їх
значення та трансформуйте їх у кінцевий вихідний формат, наприклад звичайні текстові файли,
файли електронних таблиць, графіки або бази даних.

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

Зверніть увагу на наступне про агрегатори:

· Агрегатори можуть динамічно вмикатися та вимикатися під час моделювання із викликами до
Увімкнути() та Вимкнути(). Наприклад, під час агрегування даних може бути вимкнено
фаза розігріву моделювання, що означає, що ці значення не будуть включені до фіналу
вихідне середовище.

· Агрегатори отримують дані від колекторів за допомогою зворотних викликів. Коли пов’язано колектор
до агрегатора здійснюється виклик TraceConnect для встановлення трасування агрегатора
метод sink як зворотний виклик.

На сьогоднішній день реалізовано два агрегатори:

· GnuplotAggregator

· Агрегатор файлів

GnuplotAggregator
GnuplotAggregator створює вихідні файли, які використовуються для створення gnuplot.

GnuplotAggregator створить 3 різні файли в кінці моделювання:

· Файл даних gnuplot, розділений пробілом

· Керуючий файл gnuplot

· Сценарій оболонки для створення gnuplot

Створення
Тут буде створено об’єкт типу GnuplotAggregator, щоб показати, що потрібно зробити.

Один оголошує GnuplotAggregator у динамічній пам’яті за допомогою класу розумного покажчика
(Птр ). Щоб створити GnuplotAggregator у динамічній пам’яті з розумними вказівниками, достатньо одного
потрібно подзвонити нс-3 метод CreateObject(). Наступний код від
src/stats/examples/gnuplot-aggregator-example.cc показує, як це зробити:

string fileNameWithoutExtension = "gnuplot-aggregator";

// Створити агрегатор.
Ptr агрегатор =
CreateObject (ім'я файлу без розширення);

Першим аргументом конструктора, fileNameWithoutExtension, є ім’я файлу
gnuplot файли для запису без розширення. Цей GnuplotAggregator створить a
файл даних gnuplot, розділений пробілом, під назвою "gnuplot-aggregator.dat", керуючий файл gnuplot
під назвою "gnuplot-aggregator.plt", і сценарій оболонки для створення gnuplot з ім'ям +
"gnuplot-aggregator.sh".

Створений gnuplot може мати ключ у 4 різних місцях:

· Немає ключа

· Ключ всередині сюжету (за замовчуванням)

· Ключ над сюжетом

· Ключ під сюжетом

Наведені нижче значення перерахування розташування ключа gnuplot можуть вказувати позицію ключа:

enum KeyLocation {
NO_KEY,
KEY_INSIDE,
KEY_ADOVE,
KEY_BEOW
};

Якщо потрібно було мати ключ нижче, а не положення за замовчуванням всередині, тоді
ви можете зробити наступне.

агрегатор->SetKeyLocation(GnuplotAggregator::KEY_BELOW);

прикладів
Один приклад буде детально розглянуто тут:

· Приклад агрегатора Gnuplot

Гнуплот Агрегатор Приклад
Приклад, який використовує GnuplotAggregator, можна знайти в
src/stats/examples/gnuplot-aggregator-example.cc.

Наступний 2-D gnuplot було створено за прикладом.
[зображення] 2-D Gnuplot Створено gnuplot-aggregator-example.cc Приклад..UNINDENT

Цей код із прикладу показує, як побудувати GnuplotAggregator, як обговорювалося
вище.

void Create2dPlot ()
{
using namespace std;

string fileNameWithoutExtension = "gnuplot-aggregator";
string plotTitle = "Діаграма агрегатора Gnuplot";
string plotXAxisHeading = "Час (секунди)";
string plotYAxisHeading = "Подвійні значення";
string plotDatasetLabel = "Значення даних";
string datasetContext = "Набір даних/контекст/рядок";

// Створити агрегатор.
Ptr агрегатор =
CreateObject (ім'я файлу без розширення);

Встановлюються різні атрибути GnuplotAggregator, включаючи 2-D набір даних, який буде
накреслено.

// Встановлюємо властивості агрегатора.
агрегатор->SetTerminal ("png");
агрегатор->SetTitle (plotTitle);
агрегатор->SetLegend (plotXAxisHeading, plotYAxisHeading);

// Додати набір даних до агрегатора.
агрегатор->Add2dDataset (datasetContext, plotDatasetLabel);

// агрегатор повинен бути включений
агрегатор->Увімкнути ();

Далі обчислюються 2-D значення, і кожне з них окремо записується в
GnuplotAggregator за допомогою Write2d() функції.

подвійний час;
подвійне значення;

// Створення двовимірного набору даних.
для (час = -5.0; час <= +5.0; час += 1.0)
{
// Розрахувати двовимірну криву
//
/ / 2
// значення = час .
//
значення = час * час;

// Додати цю точку до сюжету.
агрегатор->Write2d (datasetContext, time, value);
}

// Вимкнути журналювання даних для агрегатора.
агрегатор->Вимкнути ();
}

Файловий агрегатор
FileAggregator надсилає отримані значення у файл.

FileAggregator може створювати 4 різні типи файлів:

· Відформатований

· розділений пробілом (за замовчуванням)

· Через кому

· Розділені табуляції

Відформатовані файли використовують рядки формату в стилі C і функцію sprintf() для їх друку
значення у файлі, який записується.

Створення
Тут буде створено об’єкт типу FileAggregator, щоб показати, що потрібно зробити.

Один оголошує FileAggregator у динамічній пам’яті за допомогою класу розумного покажчика (Ptr ).
Щоб створити FileAggregator в динамічній пам’яті з розумними покажчиками, потрібно просто викликати
нс-3 метод CreateObject. Наступний код від
src/stats/examples/file-aggregator-example.cc показує, як це зробити:

string fileName = "file-aggregator-formatted-values.txt";

// Створити агрегатор, який матиме відформатовані значення.
Ptr агрегатор =
CreateObject (ім'я файлу, FileAggregator::FORMATTED);

Першим аргументом конструктора, ім'я файлу, є ім'я файлу для запису; в
Другий аргумент, fileType, є типом файлу для запису. Цей FileAggregator створить a
файл з назвою "file-aggregator-formatted-values.txt" з його значеннями, надрукованими, як зазначено в
fileType, тобто відформатований у цьому випадку.

Дозволені такі значення перерахування типів файлів:

enum FileType {
ФОРМАТОВАНО,
SPACE_SEPARATED,
ЧЕРЕЗ КОМУ,
TAB_SEPARATED
};

прикладів
Один приклад буде детально розглянуто тут:

· Приклад агрегатора файлів

Файл Агрегатор Приклад
Приклад, який використовує FileAggregator, можна знайти в
src/stats/examples/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, як обговорювалося
вище.

void CreateCommaSeparatedFile ()
{
using namespace std;

string fileName = "file-aggregator-comma-separated.txt";
string datasetContext = "Набір даних/контекст/рядок";

// Створити агрегатор.
Ptr агрегатор =
CreateObject (ім'я файлу, агрегатор файлів::COMMA_SEPARATED);

Встановлено атрибути FileAggregator.

// агрегатор повинен бути включений
агрегатор->Увімкнути ();

Далі обчислюються 2-D значення, і кожне з них окремо записується в
FileAggregator за допомогою Write2d() функції.

подвійний час;
подвійне значення;

// Створення двовимірного набору даних.
для (час = -5.0; час <= +5.0; час += 1.0)
{
// Розрахувати двовимірну криву
//
/ / 2
// значення = час .
//
значення = час * час;

// Додати цю точку до сюжету.
агрегатор->Write2d (datasetContext, time, value);
}

// Вимкнути журналювання даних для агрегатора.
агрегатор->Вимкнути ();
}

Наступний текстовий файл із 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, як обговорювалося
вище.

void CreateFormattedFile ()
{
using namespace std;

string fileName = "file-aggregator-formatted-values.txt";
string datasetContext = "Набір даних/контекст/рядок";

// Створити агрегатор, який матиме відформатовані значення.
Ptr агрегатор =
CreateObject (ім'я файлу, FileAggregator::FORMATTED);

Встановлюються атрибути FileAggregator, включаючи рядок формату в стилі C, який потрібно використовувати.

// Встановлюємо формат значень.
агрегатор->Set2dFormat ("Час = %.3e\tValue = %.0f");

// агрегатор повинен бути включений
агрегатор->Увімкнути ();

Далі обчислюються 2-D значення, і кожне з них окремо записується в
FileAggregator за допомогою Write2d() функції.

подвійний час;
подвійне значення;

// Створення двовимірного набору даних.
для (час = -5.0; час <= +5.0; час += 1.0)
{
// Розрахувати двовимірну криву
//
/ / 2
// значення = час .
//
значення = час * час;

// Додати цю точку до сюжету.
агрегатор->Write2d (datasetContext, time, value);
}

// Вимкнути журналювання даних для агрегатора.
агрегатор->Вимкнути ();
}

Адаптери
У цьому розділі детально описані функціональні можливості класу Adapter для an нс-3
моделювання. Цей розділ призначений для користувачів, зацікавлених у розробці моделювання за допомогою
нс-3 інструменти та використання Data Collection Framework, частиною якого є клас Adapter,
генерувати вихідні дані з результатами їх моделювання.

Примітка: термін «адаптер» також може бути написаний як «адаптер»; ми вибрали орфограму вирівняно
зі стандартом C++.

адаптер Про платформу
Адаптер використовується для встановлення з’єднань між різними типами об’єктів DCF.

На сьогоднішній день реалізовано один адаптер:

· Адаптер часових рядів

Time Серія адаптер
TimeSeriesAdaptor дозволяє Probes підключатися безпосередньо до агрегаторів без необхідності
Колектор між ними.

Обидва реалізовані помічника DCF використовують адаптори TimeSeriesAdaptors, щоб приймати зонд
значення різних типів і вивести поточний час плюс значення з обома перетвореними
до подвійного.

Роль класу TimeSeriesAdaptor - це адаптер, який приймає необроблені значення
досліджує дані різних типів і виводить кортеж із двох подвійних значень. Перший - це а
мітка часу, яка може бути встановлена ​​на різні роздільні здатності (наприклад, секунди, мілісекунди тощо).
майбутнє, але в даний час жорстко закодований у секундах. Другий — це перетворення a
неподвійне значення до подвійного значення (можливо з втратою точності).

Сфера застосування/Обмеження
У цьому розділі обговорюються рамки та обмеження системи збору даних.

Наразі в DCF реалізовано лише ці пробники:

· BooleanProbe

· DoubleProbe

· Uinteger8Probe

· Uinteger16Probe

· Uinteger32Probe

· TimeProbe

· PacketProbe

· ApplicationPacketProbe

· Ipv4PacketProbe

Наразі в DCF немає колекторів, хоча BasicStatsCollector знаходиться під
розвитку.

Наразі в DCF реалізовано лише такі агрегатори:

· GnuplotAggregator

· Агрегатор файлів

Наразі в DCF реалізовано лише цей адаптер:

Адаптер часового ряду.

Future Робота
У цьому розділі обговорюється майбутня робота над платформою збору даних.

Ось деякі речі, які ще потрібно зробити:

· Підключіть більше джерел слідів нс-3 код, щоб отримати більше значень із симулятора.

· Впровадити більше типів зондів, ніж є зараз.

· Реалізуйте більше, ніж просто єдиний поточний 2-D Collector, BasicStatsCollector.

· Впровадити більше агрегаторів.

· Впроваджуйте більше, ніж просто адаптери.

Статистичний Рамки
У цьому розділі описано роботу зі збору даних моделювання та статистичну основу для
нс-3.

Вихідний код для статистичної основи живе в каталозі src/статистика.

Цілі
Основні цілі цієї роботи такі:

· Надання функціональних можливостей для запису, обчислення та представлення даних і статистики для аналізу
мережевого моделювання.

· Підвищення продуктивності моделювання за рахунок зменшення потреби у створенні великих журналів трасування
порядок збору даних.

· Увімкніть керування моделюванням за допомогою онлайн-статистики, наприклад, припинення моделювання або
повторні випробування.

Похідні підцілі та інші цільові функції включають наступне:

· Інтеграція з існуючою системою трасування ns-3 як основною інструментальною структурою
внутрішнього механізму моделювання, наприклад мережевих стеків, мережевих пристроїв і каналів.

· Дозволяє користувачам використовувати структуру статистики без необхідності використання трасування
системи.

· Допомога користувачам у створенні, агрегуванні та аналізі даних за кілька випробувань.

· Підтримка інструментів, створених користувачем, наприклад подій, що стосуються конкретної програми
заходи.

· Низька пам'ять і навантаження на ЦП, коли пакет не використовується.

· Максимальне використання існуючих інструментів аналізу та виводу. Рамка може
надати деякі базові статистичні дані, але основна увага зосереджена на зборі даних і їх створенні
доступні для маніпулювання у встановлених інструментах.

· Можлива підтримка розповсюдження незалежних копій важлива, але не включена
у першому раунді функцій.

Про платформу
Структура статистики містить такі функції:

· Основна структура та два основних збирача даних: лічильник і мінімальний/максимальний/середній/загальний показник
спостерігач.

· Розширення для легкої роботи з часом і пакетами.

· Вивід відкритого тексту, відформатований для OMNet++.

· Використання виведення бази даних SQLite, автономний, легкий, високопродуктивний механізм SQL.

· Обов’язкові та відкриті метадані для опису та роботи з циклами.

· Приклад, заснований на умовному експерименті дослідження властивостей NS-3
продуктивність ad hoc Wi-Fi за замовчуванням. Він включає наступне:

· Будує двовузлову спеціальну мережу WiFi з параметризованою відстанню між вузлами
окремо

· Програми джерела та приймача трафіку UDP з дещо іншою поведінкою та
вимірювальні гачки, ніж стандартні класи.

· Збір даних з ядра NS-3 через існуючі сигнали трасування, зокрема дані про
кадри, передані та отримані об’єктами WiFi MAC.

· Інструментування спеціальних програм шляхом підключення нових сигналів трасування до статистики
рамки, а також через прямі оновлення. Записується інформація про загальну кількість пакетів
надіслані та отримані, передані байти та наскрізна затримка.

· Приклад використання тегів пакетів для відстеження наскрізної затримки.

· Простий контрольний сценарій, який запускає низку проб експерименту по-різному
відстань і запитує отриману базу даних для створення графіка за допомогою GNUPlot.

Зробити
Серед пріоритетних елементів:

· Включення коду онлайнової статистики, наприклад, для ефективних довірчих інтервалів пам'яті.

· Положення в збирачах даних для припинення прогонів, тобто коли порогове значення або
впевненість задоволена.

· Збірники даних для реєстрації зразків у часі та виведення в різні формати.

· Продемонструвати написання простих циклічних подій для регулярного опитування певного значення.

Кожне з них повинно виявитися простим для включення в поточну структуру.

Підхід
Структура базується на таких основних принципах:

· Одне експериментальне випробування проводиться одним екземпляром програми моделювання, будь то в
паралельно або послідовно.

· Сценарій керування виконує екземпляри моделювання, змінюючи параметри за необхідності.

· Дані збираються та зберігаються для побудови та аналізу за допомогою зовнішніх сценаріїв і
існуючі інструменти.

· Заходи в межах ядра ns-3 вживаються шляхом підключення stat framework до існуючого
трасування сигналів.

· Сигнали трасування або прямі маніпуляції з фреймворком можуть використовуватися для інструментування настроювання
код симуляції.

Ці основні компоненти фреймворку та їх взаємодія зображені на
наступний малюнок. [зображення]

Приклад
У цьому розділі розглядається процес побудови експерименту в рамках і
створювати з нього дані для аналізу (графіки), демонструючи структуру та API
шлях.

Питання
''Яка (змодельована) продуктивність WiFi NetDevices ns-3 (з використанням стандартних
налаштування)? Наскільки далеко один від одного можуть бути бездротові вузли в симуляції, перш ніж вони не зможуть
надійно спілкуватися?''

· Гіпотеза: ґрунтуючись на знаннях продуктивності реального життя, вузли повинні спілкуватися
на відстані не менше 100 м один від одного. Зв'язку далі 200м бути не повинно
здійсненне.

Хоча це не дуже поширене запитання в контексті симуляції, це важлива властивість
про які розробники моделювання повинні мати базове розуміння. Це також поширене явище
дослідження виконано на живому обладнанні.

Моделювання програма
Перше, що потрібно зробити при реалізації цього експерименту, це розробка моделювання
програма. Код для цього прикладу можна знайти в examples/stats/wifi-example-sim.cc.
Він виконує наступні основні кроки.

· Оголошення параметрів і розбір командного рядка за допомогою ns3::Командний рядок.

подвійна відстань = 50.0;
формат рядка ("OMNet++");
рядковий експеримент ("wifi-distance-test");
рядкова стратегія ("wifi-default");
рядок runID;

командний рядок cmd;
cmd.AddValue("distance", "Відстань один від одного для розміщення вузлів (у метрах).", distance);
cmd.AddValue("формат", "Формат для виведення даних.", формат);
cmd.AddValue("експеримент", "Ідентифікатор для експерименту.", експеримент);
cmd.AddValue("стратегія", "Ідентифікатор стратегії", стратегія);
cmd.AddValue("run", "Ідентифікатор для запуску.", runID);
cmd.Parse (argc, argv);

· Створення вузлів і мережевих стеків за допомогою ns3::NodeContainer, ns3::WiFiHelper та
ns3::InternetStackHelper.

вузли NodeContainer;
вузли.Створити(2);

WifiHelper wifi;
wifi.SetMac("ns3::AdhocWifiMac");
wifi.SetPhy("ns3::WifiPhy");
NetDeviceContainer nodeDevices = wifi.Install(ноди);

InternetStackHelper інтернет;
internet.Install(nodes);
Ipv4AddressHelper ipAddrs;
ipAddrs.SetBase("192.168.0.0", "255.255.255.0");
ipAddrs.Assign(nodeDevices);

· Позиціонування вузлів за допомогою ns3::MobilityHelper. За замовчуванням вузли мають статику
рухливість і не рухатиметься, але має розташовуватися на заданій відстані один від одного. Є
кілька способів для цього; це робиться тут за допомогою ns3::ListPositionAllocator, який малює
позицій із заданого списку.

мобільність MobilityHelper;
Ptr positionAlloc =
CreateObject ();
positionAlloc->Add(Vector(0.0, 0.0, 0.0));
positionAlloc->Add(Vector(0.0, distance, 0.0));
mobility.SetPositionAllocator(positionAlloc);
мобільність.Install(nodes);

· Встановлення генератора трафіку та трафіку. Запас додатків може бути
використовувався, але приклад містить спеціальні об’єкти src/test/test02-apps.(cc|h). Ці
мають просту поведінку, генеруючи задану кількість пакетів, розташованих через заданий інтервал.
Оскільки існує лише один із кожного, вони встановлюються вручну; для більшого набору
ns3::ApplicationHelper можна використовувати клас. Прокоментований Config::Set зміни лінії
адресат пакетів, у цьому прикладі налаштований на трансляцію за замовчуванням. Зауважте, що
загалом WiFi може мати різну продуктивність для широкомовних і одноадресних кадрів через
різні політики контролю швидкості та MAC-адреси.

Ptr appSource = NodeList::GetNode(0);
Ptr відправник = CreateObject ();
appSource->AddApplication(відправник);
відправник->Почати(секунд(1));

Ptr appSink = NodeList::GetNode(1);
Ptr приймач = CreateObject ();
appSink->AddApplication(одержувач);
приймач->Пуск(секунд(0));

// Config::Set("/NodeList/*/ApplicationList/*/$Sender/Destination",
// Ipv4AddressValue("192.168.0.2"));

· Налаштування даних і статистики, які збираються. Основна парадигма полягає в тому, що ан
ns3::DataCollector об’єкт створюється для зберігання інформації про цей конкретний запуск, щоб
які спостерігачі та калькулятори прикріплені для фактичного створення даних. важливо,
інформація про виконання включає мітки для «експерименту», «стратегії», «входу» та
''бігти''. Вони використовуються для подальшої ідентифікації та легкого групування даних із кількох випробувань.

· Експеримент - це дослідження, членом якого є дане випробування. Ось він на WiFi
продуктивність і відстань.

· Стратегія - це код або параметри, які перевіряються в цьому випробуванні. У цьому прикладі
це виправлено, але очевидним розширенням було б дослідити інший біт WiFi
ставки, кожна з яких буде окремою стратегією.

· Вхідними даними є конкретна проблема, поставлена ​​для цього випробування. Ось це просто своє
відстань між двома вузлами.

· RunID — це унікальний ідентифікатор цього випробування, яким позначено його інформацію
для ідентифікації в подальшому аналізі. Якщо ідентифікатор запуску не надано, приклад програми створює
(слабкий) ідентифікатор запуску з використанням поточного часу.

Ці чотири фрагменти метаданих є обов’язковими, але може знадобитися більше. Їх можна додавати
до запису за допомогою ns3::DataCollector::AddMetadata() метод.

дані DataCollector;
data.DescribeRun(експеримент, стратегія, введення, runID);
data.AddMetadata("автор", "tjkopena");

Фактичне спостереження та обчислення виконує ns3::DataCalculator об'єктів, з яких
існує кілька різних типів. Вони створені програмою моделювання, що додається до
код звітності або вибірки, а потім зареєстрований у ns3::DataCollector тому вони будуть
запитувати їх пізніше. Одним із простих механізмів спостереження є використання існуючих
джерела трасування, наприклад, щоб інструментувати об’єкти в ядрі ns-3, не змінюючи їх
код. Тут лічильник приєднується безпосередньо до сигналу трасування на рівні WiFi MAC
цільовий вузол.

Ptr totalRx = CreateObject ();
totalRx->SetKey("wifi-rx-frames");
Config::Connect("/NodeList/1/DeviceList/*/$ns3::WifiNetDevice/Rx",
MakeCallback(&PacketCounterCalculator::FrameUpdate, totalRx));
data.AddDataCalculator(totalRx);

Калькуляторами також можна маніпулювати безпосередньо. У цьому прикладі створюється лічильник і
передається додатку приймача трафіку для оновлення при отриманні пакетів.

Ptr > appRx = CreateObject >();
appRx->SetKey("пакети приймача прийому");
приймач->Установити лічильник(appRx);
data.AddDataCalculator(appRx);

Щоб збільшити кількість, код обробки пакетів приймача викликає один із
способи оновлення калькулятора.

m_calc->Оновити();

Програма також містить кілька інших прикладів, використовуючи обидва примітиви
калькулятори, такі як ns3::CounterCalculator і ті, що пристосовані для спостереження за пакетами та
разів. в src/test/test02-apps.(cc|h) він також створює простий спеціальний тег, який використовує
для відстеження наскрізної затримки для згенерованих пакетів, звітування про результати до a
ns3::TimeMinMaxAvgTotalCalculator калькулятор даних.

· Запуск моделювання, яке є дуже простим після створення.

Simulator::Run();

· Створення будь-якого OMNet++ or SQLite вихід, залежно від аргументів командного рядка. до
зробити це а ns3::DataOutputInterface об'єкт створений і налаштований. Конкретний тип
це визначатиме вихідний формат. Потім цей об’єкт отримує
ns3::DataCollector об'єкт, який він запитує, щоб отримати вихід.

Ptr вихід;
якщо (формат == "OMNet++") {
NS_LOG_INFO("Створення вихідних даних у форматі OMNet++.");
вихід = CreateObject ();
} Ще {
# ifdef STAT_USE_DB
NS_LOG_INFO("Створення вихідних даних у форматі SQLite.");
вихід = CreateObject ();
# endif
}

вихід->Вивід(дані);

· Звільнення будь-якої пам'яті, яка використовується симуляцією. Це повинно бути в кінці основного
для прикладу.

Simulator::Destroy();

Запис
Щоб детально побачити, що приклад програми, програми та структура статистики роблять, установіть
NS_LOG змінна належним чином. Нижченаведене забезпечить багатий результат від усіх
три.

$ експорт NS_LOG=WiFiDistanceExperiment:WiFiDistanceApps

Зауважте, що це надзвичайно сповільнює симуляцію.

Зразок Вихід
Компіляція та просто запуск тестової програми буде додано OMNet++ форматований вихід, наприклад
наступне до data.sca.

запустити run-1212239121

експеримент attr "wifi-distance-test"
стратегія attr "wifi-default"
attr input "50"
опис атрибута ""

attr "автор" "tjkopena"

кількість скалярних кадрів wifi-tx 30
кількість скалярних кадрів wifi-rx 30
скалярна кількість пакетів sender-tx 30
кількість скалярних приймачів-rx-пакетів 30
scalar tx-pkt-size count 30
скаляр tx-pkt-size total 1920
скалярний tx-pkt-size середнє 64
скаляр tx-pkt-size max 64
скаляр tx-pkt-size min 64
скалярна затримка 30
загальна скалярна затримка 5884980 нс
скалярна затримка в середньому 196166ns
скалярна затримка max 196166ns
скалярна затримка min 196166ns

Контроль Script
Щоб автоматизувати збір даних на різних входах (відстанях), простий Bash
сценарій використовується для виконання серії симуляцій. Його можна знайти на
examples/stats/wifi-example-db.sh. Сценарій призначений для запуску з приклади/статистика/
каталог.

Сценарій виконує набір відстаней, збираючи результати в SQLite
бази даних. На кожній дистанції проводиться п'ять випробувань, щоб отримати кращу картину очікуваного
продуктивність. Весь експеримент займає лише кілька десятків секунд, щоб запуститися на низькому рівні
машині, оскільки під час симуляції немає вихідних даних і генерується невеликий трафік.

#!/ Бен / ш

DISTANCES="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

if [ -e data.db ]
потім
echo Видалити data.db?
читати ANS
if [ "$ANS" = "yes" -o "$ANS" = "y" ]
потім
echo Видалення бази даних
rm data.db
fi
fi

для випробування через $TRIALS
do
для відстані в $DISTANCES
do
echo Trial $trial, distance $distance
./bin/test02 --format=db --distance=$distance --run=run-$distance-$trial
зроблений
зроблений

Аналіз та Висновок
Після проведення всіх випробувань сценарій виконує простий SQL-запит над
бази даних за допомогою SQLite програма командного рядка. Запит обчислює середню втрату пакетів у
кожен набір випробувань, пов'язаний з кожною дистанцією. Не враховує різн
стратегії, але інформація присутня в базі даних, щоб зробити деякі прості розширення
і зроби так. Потім зібрані дані передаються в GNUplot для побудови графіків.

CMD="виберіть exp.input,avg(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='sender-tx-packets' \
групувати за exp.input \
порядок за abs(exp.input) ASC;"

sqlite3 -noheader data.db "$CMD" > wifi-default.data
sed -i "s/|/ /" wifi-default.data
gnuplot wifi-example.gnuplot

Сценарій GNUplot знайдено за адресою examples/stats/wifi-example.gnuplot просто визначає результат
формат і деяке базове форматування для графіка.

встановити термінальний postscript портрет покращений lw 2 "Helvetica" 14

розмір набору 1.0, 0.66

#------------------------------------------------ ------
встановити "wifi-default.eps"
#set title "Втрата пакетів на відстані"
set xlabel "Відстань (м) --- середнє 5 спроб на точку"
встановити діапазон x [0:200]
встановити ylabel "% втрати пакетів"
встановити yrange [0:110]

графік "wifi-default.data" із заголовком рядків "WiFi Defaults"

кінець Результат
Отриманий графік не надає доказів того, що модель Wi-Fi за замовчуванням є такою
обов'язково нерозумним і надає певної впевненості принаймні символічній вірності
реальність. Що ще важливіше, це просте розслідування було проведено до кінця
використовуючи статистичну систему. Успіх! [зображення]

Реальний час
нс-3 був розроблений для інтеграції в середовища випробувань і віртуальних машин. до
інтегруватися з реальними мережевими стеками та випускати/споживати пакети, це планувальник у реальному часі
необхідно спробувати заблокувати симуляційний годинник за допомогою апаратного годинника. Ми описуємо тут a
компонент цього: планувальник RealTime.

Мета планувальника реального часу полягає в тому, щоб викликати прогресування годинника симуляції
відбуватися синхронно відносно деякої зовнішньої бази часу. Без присутності
зовнішня база часу (настінний годинник), час симуляції миттєво змінюється від імітованого
час до наступного.

Поведінка
У разі використання планувальника не в реальному часі (за замовчуванням у нс-3), симулятор просуває
час моделювання до наступної запланованої події. Під час виконання події час моделювання становить
заморожені. З планувальником реального часу поведінка подібна з точки зору
імітаційних моделей (тобто час моделювання заморожено під час виконання події), але між
події, симулятор намагатиметься підтримувати симуляційний годинник у відповідності з машиною
годинник.

Коли подія завершується, і планувальник переходить до наступної події,
планувальник порівнює час виконання наступної події з годинником машини. Якщо наступний
подія запланована на майбутній час, симулятор переходить у режим сну, доки цей реальний час не буде досягнуто
а потім виконує наступну подію.

Може статися так, що через обробку, притаманну виконанню подій моделювання,
що симулятор не встигає за реальним часом. У такому випадку це залежить від користувача
конфігурація що робити. Є два нс-3 атрибути, які керують поведінкою. The
перший є ns3::RealTimeSimulatorImpl::SynchronizationMode. Можливі два записи для
цей атрибут є BestEffort (за замовчуванням) або HardLimit. У режимі «BestEffort»
Симулятор просто намагатиметься наздогнати реальний час, виконуючи події, доки не досягне a
точка, де наступна подія в майбутньому (в реальному часі), інакше симуляція завершується. в
Таким чином, у режимі BestEffort симуляція може займати більше часу, ніж режим
час настінного годинника. Інший параметр "HardLimit" призведе до переривання симуляції, якщо
перевищено поріг допуску. Цей атрибут є ns3::RealTimeSimulatorImpl::HardLimit
і за замовчуванням 0.1 секунди.

Іншим режимом роботи є той, у якому імітується час НЕ заморожені під час події
виконання. Цей режим симуляції в реальному часі було реалізовано, але видалено з нс-3 дерево
через питання, чи буде це корисно. Якщо користувачів цікавить реальний час
симулятор, для якого час моделювання не зависає під час виконання події (тобто кожен
зателефонувати до Simulator::Now() повертає поточний час настінного годинника, а не час, коли
подія почала виконуватися), зверніться до списку розсилки ns-developers.

Використання
Використання симулятора реального часу є простим з точки зору сценаріїв.
Користувачам просто потрібно встановити атрибут SimulatorImplementationType до реального часу
симулятор, наприклад:

GlobalValue::Bind ("SimulatorImplementationType",
StringValue ("ns3::RealtimeSimulatorImpl"));

Є сценарій examples/realtime/realtime-udp-echo.cc який має приклад того, як
налаштувати поведінку в реальному часі. Спробуйте:

$ ./waf --run realtime-udp-echo

Визначається, чи буде симулятор працювати якнайкраще, чи жорстко обмежено
за атрибутами, поясненими в попередньому розділі.

Реалізація
Реалізація міститься в таких файлах:

· src/core/model/realtime-simulator-impl.{cc,h}

· src/core/model/wall-clock-synchronizer.{cc,h}

Для того, щоб створити планувальник реального часу, у першому наближенні потрібно просто викликати
симуляція часу стрибає, щоб споживати реальний час. Ми пропонуємо зробити це за допомогою комбінації
сон- і зайнятий- чекає. Очікування сну призводять до того, що викликаючий процес (потік) віддає
процесор протягом деякого часу. Незважаючи на те, що цей зазначений проміжок часу можна пройти
до наносекундної роздільної здатності, він фактично перетворюється на деталізацію, специфічну для ОС. в
Linux, деталізація називається Jiffy. Зазвичай цієї роздільної здатності недостатньо для
наші потреби (порядку десяти мілісекунд), тому ми округляємо в меншу сторону і спимо деякий час
менша кількість Jiffies. Потім процес пробуджується після вказаної кількості
Jiffies минуло. Наразі у нас є час, який залишився чекати. Цей час є
зазвичай менше, ніж мінімальний час сну, тому ми зайняті – чекаємо решту
час. Це означає, що потік просто знаходиться в циклі for, споживаючи цикли, доки не буде
настає бажаний час. Після поєднання режиму сну та очікування зайнятості минув реальний час
(настінний) годинник має узгоджуватися з часом моделювання наступної події та симуляції
надходження.

Помічники
Наведені вище розділи познайомили вас з різними нс-3 концепції програмування, такі як smart
покажчики для керування пам’яттю з підрахунком посилань, атрибути, простори імен, зворотні виклики тощо.
Користувачі, які працюють на цьому низькорівневому 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

Щоб запустити цей приклад, виконайте такі дії:

$ ./waf оболонка
$ cd build/debug/src/stats/examples
$ ./gnuplot-приклад

Це повинно створити наступні керуючі файли gnuplot у каталозі, де знаходиться приклад
знаходиться:

ділянка-2д.пл
plot-2d-with-error-bars.plt
ділянка-3д.пл

Щоб обробити ці керуючі файли gnuplot, виконайте наступне:

$ gnuplot plot-2d.plt
$ gnuplot plot-2d-with-error-bars.plt
$ gnuplot plot-3d.plt

Це має створити наступні графічні файли в каталозі, де знаходиться приклад
розташований:

plot-2d.png
plot-2d-with-error-bars.png
plot-3d.png

Ви можете переглядати ці графічні файли у своєму улюбленому засобі перегляду графіки. Якщо у вас є gimp
встановлено на вашій машині, наприклад, ви можете зробити це:

$ gimp plot-2d.png
$ gimp plot-2d-with-error-bars.png
$ gimp plot-3d.png

An Приклад 2-вимірний Сюжет
Наступний двовимірний графік
[картина]

було створено за допомогою наступного коду з gnuplot-example.cc:

using namespace std;

string fileNameWithNoExtension = "plot-2d";
string graphicsFileName = fileNameWithNoExtension + ".png";
рядок plotFileName = fileNameWithNoExtension + ".plt";
string plotTitle = "2-D графік";
string dataTitle = "2-D дані";

// Створення екземпляра сюжету та встановлення його заголовка.
Графік Gnuplot (graphicsFileName);
plot.SetTitle (plotTitle);

// Створення графічного файлу, який створить файл графіки
// використовується з Gnuplot, бути файлом PNG.
plot.SetTerminal ("png");

// Встановити мітки для кожної осі.
plot.SetLegend ("Значення X", "Значення Y");

// Встановити діапазон для осі x.
plot.AppendExtra ("встановити діапазон x [-6:+6]");

// Створення екземпляра набору даних, встановлення його заголовка та створення точок
// нанесено разом із сполучними лініями.
набір даних Gnuplot2dDataset;
dataset.SetTitle (dataTitle);
dataset.SetStyle (Gnuplot2dDataset::LINES_POINTS);

подвійний х;
подвійне у;

// Створення двовимірного набору даних.
для (x = -5.0; x <= +5.0; x += 1.0)
{
// Розрахувати двовимірну криву
//
/ / 2
// y = x .
//
y = x * x;

// Додати цю точку.
набір даних.Add (x, y);
}

// Додати набір даних до графіка.
plot.AddDataset (набір даних);

// Відкрити файл графіка.
ofstream plotFile (plotFileName.c_str());

// Записати файл графіка.
plot.GenerateOutput (plotFile);

// Закрити файл графіка.
plotFile.close ();

An Приклад 2-вимірний Сюжет з помилка бруси
Наступний двовимірний графік зі смугами похибок у напрямках x і y
[картина]

було створено за допомогою наступного коду з gnuplot-example.cc:

using namespace std;

string fileNameWithNoExtension = "plot-2d-with-error-bars";
string graphicsFileName = fileNameWithNoExtension + ".png";
рядок plotFileName = fileNameWithNoExtension + ".plt";
string plotTitle = "2-D графік зі смугами помилок";
string dataTitle = "2-D дані зі смугами помилок";

// Створення екземпляра сюжету та встановлення його заголовка.
Графік Gnuplot (graphicsFileName);
plot.SetTitle (plotTitle);

// Створення графічного файлу, який створить файл графіки
// використовується з Gnuplot, бути файлом PNG.
plot.SetTerminal ("png");

// Встановити мітки для кожної осі.
plot.SetLegend ("Значення X", "Значення Y");

// Встановити діапазон для осі x.
plot.AppendExtra ("встановити діапазон x [-6:+6]");

// Створення екземпляра набору даних, встановлення його заголовка та створення точок
// нанесено без сполучних ліній.
набір даних Gnuplot2dDataset;
dataset.SetTitle (dataTitle);
dataset.SetStyle (Gnuplot2dDataset::POINTS);

// Зробіть так, щоб набір даних мав смуги похибок у напрямках x і y.
dataset.SetErrorBars (Gnuplot2dDataset::XY);

подвійний х;
подвійна xErrorDelta;
подвійне у;
подвійна yErrorDelta;

// Створення двовимірного набору даних.
для (x = -5.0; x <= +5.0; x += 1.0)
{
// Розрахувати двовимірну криву
//
/ / 2
// y = x .
//
y = x * x;

// Робимо невизначеність у напрямку x постійною і make
// невизначеність у напрямку y є постійною часткою
// значення y.
xErrorDelta = 0.25;
yErrorDelta = 0.1 * y;

// Додайте цю точку з невизначеністю як в x, так і в y
// напрямок.
набір даних.Add (x, y, xErrorDelta, yErrorDelta);
}

// Додати набір даних до графіка.
plot.AddDataset (набір даних);

// Відкрити файл графіка.
ofstream plotFile (plotFileName.c_str());

// Записати файл графіка.
plot.GenerateOutput (plotFile);

// Закрити файл графіка.
plotFile.close ();

An Приклад 3-вимірний Сюжет
Наступний двовимірний графік
[картина]

було створено за допомогою наступного коду з gnuplot-example.cc:

using namespace std;

string fileNameWithNoExtension = "plot-3d";
string graphicsFileName = fileNameWithNoExtension + ".png";
рядок plotFileName = fileNameWithNoExtension + ".plt";
string plotTitle = "3-D графік";
string dataTitle = "3-D дані";

// Створення екземпляра сюжету та встановлення його заголовка.
Графік Gnuplot (graphicsFileName);
plot.SetTitle (plotTitle);

// Створення графічного файлу, який створить файл графіки
// використовується з Gnuplot, бути файлом PNG.
plot.SetTerminal ("png");

// Поверніть графік на 30 градусів навколо осі x, а потім поверніть
// побудувати 120 градусів навколо нової осі z.
plot.AppendExtra ("встановити вигляд 30, 120, 1.0, 1.0");

// Зробіть так, щоб нуль для осі z знаходився в площині осі x і осі y.
plot.AppendExtra ("встановити ticslevel 0");

// Встановити мітки для кожної осі.
plot.AppendExtra ("встановити xlabel 'X Values'");
plot.AppendExtra ("встановити ylabel 'Y Values'");
plot.AppendExtra ("встановити zlabel 'Z Values'");

// Встановити діапазони для осей x і y.
plot.AppendExtra ("встановити діапазон x [-5:+5]");
plot.AppendExtra ("встановити yrange [-5:+5]");

// Створення екземпляра набору даних, встановлення його заголовка та створення точок
// з'єднані лініями.
набір даних Gnuplot3dDataset;
dataset.SetTitle (dataTitle);
dataset.SetStyle ("з лініями");

подвійний х;
подвійне у;
подвійний z;

// Створення двовимірного набору даних.
для (x = -5.0; x <= +5.0; x += 1.0)
{
для (y = -5.0; y <= +5.0; y += 1.0)
{
// Розрахувати 3-D поверхню
//
// 2 2
// z = x * y .
//
z = x * x * y * y;

// Додати цю точку.
набір даних.Додати (x, y, z);
}

// Необхідний порожній рядок у кінці кожного значення x
// точки для роботи тривимірної сітки поверхні.
набір даних.AddEmptyLine ();
}

// Додати набір даних до графіка.
plot.AddDataset (набір даних);

// Відкрити файл графіка.
ofstream plotFile (plotFileName.c_str());

// Записати файл графіка.
plot.GenerateOutput (plotFile);

// Закрити файл графіка.
plotFile.close ();

використання Python до прогін нс-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 Приклад Python Script Що Runs нс-3
Ось приклад коду, написаного на Python і який виконується нс-3, яка написана
на C++. Цей приклад Python можна знайти в examples/tutorial/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("2ms"))

пристрої = pointToPoint.Install(ноди)

стек = ns.internet.InternetStackHelper()
stack.Install(nodes)

адреса = ns.internet.Ipv4AddressHelper()
address.SetBase(ns.network.Ipv4Address("10.1.1.0"), ns.network.Ipv4Mask("255.255.255.0"))

інтерфейси = адреса. Призначити (пристрої);

echoServer = 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("MaxPackets", 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()

Робота Python Сценарії
waf містить деякі параметри, які автоматично оновлюють шлях python для пошуку ns3
модуль. Щоб запустити приклади програм, є два способи використання waf, щоб подбати про це. Один
це запустити оболонку waf; наприклад:

$ ./waf --shell
$ python examples/wireless/mixed-wireless.py

а інший — використовувати опцію --pyrun для waf:

$ ./waf --pyrun examples/wireless/mixed-wireless.py

Щоб запустити сценарій python у налагоджувачі C:

$ ./waf --shell
$ gdb --args python examples/wireless/mixed-wireless.py

Щоб запустити власний сценарій Python, який викликає нс-3 і це має цей шлях,
/path/to/your/example/my-script.pyВиконайте наступні дії:

$ ./waf --shell
$ python /path/to/your/example/my-script.py

Застереження
Прив'язки Python для нс-3 знаходяться в стадії розробки, і деякі обмеження відомі
розробників. Деякі з цих обмежень (не всі) перераховані тут.

Неповна Покриття
Перш за все, майте на увазі, що Python підтримує не 100% API. Деякі з
причини:

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 (backboneDevices);

У Python на даний момент вам потрібно зробити:

ipAddrs = ns3.Ipv4AddressHelper()
ipAddrs.SetBase(ns3.Ipv4Address("192.168.0.0"), ns3.Ipv4Mask("255.255.255.0"))
ipAddrs.Assign(backboneDevices)

Командний рядок
Командний рядок::AddValue() працює інакше в Python, ніж у нс-3. У Python файл
Перший параметр — це рядок, який представляє назву параметра командного рядка. Коли варіант
встановлено, атрибут із такою самою назвою, як і назва опції, встановлено на Командний рядок()
об'єкт. Приклад:

NUM_NODES_SIDE_DEFAULT = 3

cmd = ns3.CommandLine()

cmd.NumNodesSide = Жодного
cmd.AddValue("NumNodesSide", "Кількість вузлів на стороні сітки (загальна кількість вузлів буде квадратом цього числа)")

cmd.Parse(argv)

[...]

якщо 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.Simulator.Run()
ns3.Simulator.Destroy()
ascii.close() # закрити файл

Є одне застереження: ви не повинні дозволяти, щоб файловий об’єкт збирався як сміття нс-3
все ще використовує його. Це означає, що наведена вище змінна 'ascii' не повинна залишатися
поза межами області, інакше програма вийде з ладу.

Cygwin обмеження
Прив’язки Python не працюють на Cygwin. Це пов’язано з помилкою gccxml.

Ви можете уникнути цього, повторно просканувавши визначення API з cygwin
середовище (./waf --python-scan). Однак найбільш вірогідним рішенням, мабуть, доведеться
ми вимикаємо прив’язки python у CygWin.

Якщо ви справді дбаєте про прив’язки Python у Windows, спробуйте створити за допомогою mingw і native
замість цього python. Або, щоб створити без прив’язок python, вимкніть прив’язки python у
етап налаштування:

$ ./waf configure --disable-python

Робочий з Python палітурки
Зараз існує два типи прив’язок Python нс-3:

1. Монолітні прив’язки містять визначення API для всіх модулів і їх можна знайти в
єдиний каталог, прив'язки/python.

2. Модульні прив’язки містять визначення API для окремого модуля, і їх можна знайти в кожному
модулі прив'язки каталог.

Python палітурки Workflow
Процес, за допомогою якого обробляються прив’язки Python, такий:

1. Періодично розробник використовує GCC-XML (http://www.gccxml.org) сканування на основі API
сценарій, який зберігає скановане визначення API як bindings/python/ns3_module_*.py файли
або як файли Python у кожному модулі прив'язки каталог. Ці файли зберігаються в секреті
контроль версій в основному нс-3 сховище;

2. Інші розробники клонують репозиторій і використовують уже відскановані визначення API;

3. При налаштуванні нс-3, pybindgen буде завантажено автоматично, якщо ще не завантажено
встановлено. Звільнений нс-3 архівні файли надсилатимуть копію pybindgen.

Якщо під час компіляції прив’язок Python щось піде не так, і ви просто хочете їх проігнорувати
і рухайтеся далі з C++, ви можете вимкнути Python за допомогою:

$ ./waf --disable-python

інструкції та цінності Обробка Нові Файли or Змінено API
Отже, ви змінювали існуюче нс-3 API і прив’язки Python більше не компілюються? робити
не впадайте у відчай, ви можете повторно сканувати прив’язки, щоб створити нові прив’язки, які відображатимуть зміни
до нс-3 API.

Залежно від того, використовуєте ви монолітні чи модульні прив’язки, див. обговорення нижче
дізнайтеся, як повторно сканувати прив’язки Python.

Монолітний Python палітурки
Сканування Монолітний Python палітурки
Щоб сканувати монолітні прив’язки Python, виконайте такі дії:

$ ./waf --python-scan

Organization of Монолітний Python палітурки
Монолітні визначення API Python організовані таким чином. Для кожного нс-3 Модулі
, файл bindings/python/ns3_module_ .py описує свій API. Кожен з них
файли мають 3 функції верхнього рівня:

1. захист типи_реєстрів(модуль)(): ця функція піклується про реєстрацію нових типів (наприклад,
класи C++, переліки), які визначені в модулі;

2. захист register_methods(модуль)(): ця функція викликає для кожного класу , інший
функція register_methods_Ns3 (модуль). Ці останні функції додають метод
визначення для кожного класу;

3. захист реєстр_функцій(модуль)(): ця функція реєструє нс-3 функції, які належать
цей модуль.

Модульний Python палітурки
Про платформу
Починаючи з версії ns 3.11, паралельно до старої монолітної версії додаються модульні зв’язки.
прив'язки.

Нові прив’язки python генеруються в просторі імен «ns» замість «ns3» для старого
палітурки. приклад:

з вузла імпорту ns.network
n1 = Node()

З модульними прив’язками Python:

1. Для кожного існує один окремий модуль розширення Python нс-3 модуль;

2. Сканування визначень API (apidefs) виконується на основі кожного ns-модуля;

3. Файли apidefs кожного модуля зберігаються в підкаталозі «bindings» модуля
каталог;

Сканування Модульний Python палітурки
Наприклад, щоб сканувати модульні прив’язки Python для основного модуля, виконайте такі дії:

$ ./waf --apiscan=core

Щоб сканувати модульні прив’язки Python для всіх модулів, виконайте такі дії:

$ ./waf --apiscan=all

створення a Нові Модулі
Якщо ви додаєте новий модуль, прив’язки Python продовжуватимуть компілюватися, але не будуть
накрийте новий модуль.

Щоб покрити новий модуль, ви повинні створити a bindings/python/ns3_module_ .py файл,
подібно до того, що описано в попередніх розділах, і зареєструйте його в змінній
LOCAL_MODULES() in bindings/python/ns3modulegen.py

Додавання Модульний палітурки До A існуючий Модулі
Щоб додати підтримку модульних прив’язок до існуючого нс-3 просто додайте наступне
до його функції wscript build():

bld.ns3_python_bindings()

Organization of Модульний Python палітурки
Команда src/ /прив'язки каталог може містити наступні файли, деякі з них
необов'язково:

· callbacks_list.py: це відсканований файл, НЕ ТОРКАЙТЕСЯ. Містить список
Зворотний виклик<...> екземпляри шаблону, знайдені в сканованих заголовках;

· modulegen__gcc_LP64.py: це відсканований файл, НЕ ТОРКАЙТЕСЯ. Відскановані визначення API
для GCC, архітектура LP64 (64-розрядна)

· modulegen__gcc_ILP32.py: це відсканований файл, НЕ ТОРКАЙТЕСЯ. Відскановані визначення API
для GCC, архітектура ILP32 (32-розрядна)

· modulegen_customizations.py: ви можете додатково додати цей файл, щоб налаштувати
генерація коду pybindgen

· scan-header.h: ви можете додатково додати цей файл, щоб налаштувати, який файл заголовка сканується
для модуля. В основному цей файл сканується замість ns3/ -module.h.
Як правило, перший оператор #include "ns3/ -module.h", а також деякі інші
матеріал для примусової інстанції шаблону;

· module_helpers.cc: ви можете додати додаткові файли, як-от цей, для зв’язування з python
модуль розширення, але вони повинні бути зареєстровані в wscript. Подивись на
src/core/wscript для прикладу того, як це зробити;

· .py: якщо цей файл існує, він стає «інтерфейсним» модулем python для ns3
модуль, а модуль розширення (файл .so) стає _ .так замість .так.
The Файл .py має імпортувати всі символи з модуля _ (це більше
складно, ніж це звучить, перегляньте src/core/bindings/core.py для прикладу), а потім можете додати
деякі додаткові визначення чистого Python.

більше Інформація та цінності Розробники
Якщо ви розробник і вам потрібна додаткова інформація про нс-3Прив'язки Python див
Python палітурки вики сторінка.

Випробування
Про платформу
Цей документ стосується тестування та перевірки нс-3 програмне забезпечення.

Цей документ передбачає

· відомості про термінологію та тестування програмного забезпечення (розділ 2);

· опис інфраструктури тестування ns-3 (Розділ 3);

· посібник для розробників моделей або учасників нових моделей щодо написання тестів (розд
4);

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

фон
Цей довідник - главу може be пропустив by читачі знайомий з основи of програмне забезпечення тестування.

Написання бездефектного програмного забезпечення є складною пропозицією. Існує багато вимірів
проблема, і існує велика плутанина щодо того, що означають різні терміни в
різні контексти. Ми виявили, що варто витратити трохи часу на перегляд
предмет і визначення деяких термінів.

Тестування програмного забезпечення можна умовно визначити як процес виконання програми за допомогою
намір знайти помилки. Коли хтось починає дискусію щодо тестування програмного забезпечення, це
швидко стає очевидним, що існує багато різних установок розуму, з якими можна
підійти до теми.

Наприклад, можна розбити процес на широкі функціональні категорії, такі як
«тестування правильності», «тестування продуктивності», «тестування надійності» та «безпеки»
Інший спосіб поглянути на проблему за життєвим циклом: «тестування вимог»,
«тестування конструкції», «тестування приймання» та «тестування на технічне обслуговування». Ще один погляд
залежить від обсягу перевіреної системи. У цьому випадку можна говорити про «модульне тестування»,
«тестування компонентів», «тестування інтеграції» та «тестування системи». Ці терміни є
також жодним чином не стандартизовано, тому «тестування обслуговування» та «регресія».
testing'' можна почути взаємозамінно. Крім того, ці терміни часто зловживають.

Існує також ряд різних філософських підходів до тестування програмного забезпечення. для
наприклад, деякі організації виступають за написання тестових програм перед фактичним впровадженням
бажане програмне забезпечення, що дає «розробку, керовану тестуванням». Деякі організації підтримують
тестування з точки зору клієнта якнайшвидше, дотримуючись паралелі з
гнучкий процес розробки: «тестуйте рано і тестуйте часто». Іноді це називається
''гнучке тестування''. Здається, що для кожного існує принаймні один підхід до тестування
методика розробки.

Команда нс-3 проект не займається адвокацією жодного з цих процесів, але
проект в цілому має вимоги, які допомагають інформувати процес тестування.

Як і всі основні програмні продукти, нс-3 має ряд якостей, які повинні бути присутніми для
продукт на успіх. З точки зору тестування, деякі з цих якостей повинні бути
адресовані такі нс-3 має бути «правильним», «надійним», «продуктивним» і
В ідеалі має бути метрика для кожного з цих вимірів
перевірено за допомогою тестів, щоб визначити, коли продукт не відповідає очікуванням /
вимоги.

Правильність
Основна мета тестування — визначити, чи поводиться частина програмного забезпечення
''правильно.'' Для нс-3 це означає, що якщо ми моделюємо щось, моделювання повинно бути
достовірно представляти певну фізичну сутність або процес із визначеною точністю та
точність.

Виявляється, є дві точки зору, з яких можна дивитися на правильність.
Перевірка того, що конкретна модель реалізована відповідно до її специфікації
узагальнено наз перевірка. Процес визначення правильності моделі
його використання за призначенням називається узагальнено перевірка достовірності.

Перевірка та перевірка
Комп’ютерна модель — це математичне або логічне представлення чогось. Це може
представляють транспортний засіб, слона (див Девід Харель говорити про моделювання an слон at
SIMUTols 2009або мережеву карту. Моделі також можуть представляти такі процеси, як глобальні
потепління, транспортний потік на автостраді або специфікація мережевого протоколу. Моделі можуть бути
повністю точні представлення специфікації логічного процесу, але вони
ніколи не може повністю імітувати фізичний об'єкт або процес. У більшості випадків а
в модель внесено ряд спрощень, щоб зробити моделювання за допомогою обчислень
податливий.

Кожна модель має a мета система що він намагається імітувати. Перший крок в
створення імітаційної моделі полягає в ідентифікації цієї цільової системи та рівня її деталізації
точність, яку хочеться відтворити моделюванням. У випадку логічного процесу,
цільову систему можна ідентифікувати як «TCP, як визначено RFC 793». У цьому випадку це
ймовірно, буде бажано створити модель, яка повністю і вірно відтворює RFC
793. У випадку фізичного процесу це буде неможливо. Якщо, наприклад, ви
бажаєте імітувати карту бездротової мережі, ви можете визначити, що вам потрібно, ''an
точна реалізація специфікації 802.11 на рівні MAC і [...] не дуже повільна
Модель PHY-рівня специфікації 802.11a.

Як тільки це буде зроблено, можна розробити абстрактну модель цільової системи. Це
зазвичай це вправа в управлінні компромісами між складністю та вимогами до ресурсів
і точність. Процес розробки абстрактної моделі наз модель
кваліфікація в літературі. У випадку протоколу TCP цей процес призводить до a
дизайн колекції об’єктів, взаємодій і поведінки, які будуть повністю реалізовані
RFC 793 в нс-3. У випадку бездротової карти цей процес призводить до кількох
компроміси, щоб дозволити симулювати фізичний рівень і дизайн мережевого пристрою
і канал для ns-3 разом із бажаними об’єктами, взаємодіями та поведінкою.

Потім ця абстрактна модель перетворюється на нс-3 модель, що реалізує абстрактне
модель як комп'ютерна програма. Процес узгодження реалізації з
абстрактна модель наз модель перевірка в літературі.

Процес поки що відкритий. Залишилося визначити, що заданий ns-3
модель має певний зв’язок з певною реальністю, тобто її точне відображення
реальна система, будь то логічний процес чи фізична сутність.

Якщо хтось збирається використовувати імітаційну модель, щоб спробувати передбачити, як працює якась реальна система
щоб поводитись, має бути якась причина вірити у ваші результати, тобто чи можна цьому довіряти
висновок, зроблений на основі моделі, перетворюється на правильний прогноз для реальної системи.
Процес узгодження поведінки моделі ns-3 з бажаною цільовою системою
поведінка, визначена процесом кваліфікації моделі, називається модель перевірка достовірності ,
література. У випадку реалізації TCP ви можете порівняти поведінку
вашу модель TCP ns-3 до певної еталонної реалізації, щоб перевірити вашу модель. в
у випадку симуляції бездротового фізичного рівня, ви можете порівняти поведінку
вашу модель реального апаратного забезпечення в контрольованих умовах,

Команда нс-3 Середовище тестування надає інструменти для перевірки моделі та
тестування та заохочує публікацію результатів перевірки.

Надійність
Міцність – це здатність протистояти навантаженням або змінам середовища,
вхідні дані або обчислення тощо. Система або проект є «надійними», якщо вони можуть працювати з цим
зміни з мінімальною втратою функціональності.

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

Система також може бути піддана навантаженню, якщо генерувати електроенергію, яка працює близько до потужності або перевищує її
або імітація виснаження ресурсів різного роду. Такий жанр тестування називається
''стрес-тестування''.

Система та її компоненти можуть бути піддані так званим «чистим тестам», які демонструють
позитивний результат – тобто система працює правильно у відповідь на велику
варіація очікуваних конфігурацій.

Система та її компоненти також можуть бути піддані «брудним тестам», які надають вхідні дані
поза очікуваним діапазоном. Наприклад, якщо модуль очікує рядок із закінченням нулем
подання цілого числа, брудний тест може надати незавершений рядок випадкового
символів, щоб переконатися, що система не аварійно завершує роботу в результаті цього неочікуваного введення.
На жаль, виявлення такого «брудного» введення та вжиття превентивних заходів для забезпечення
система не виходить з катастрофічного збою може вимагати величезних витрат на розробку.
Щоб скоротити час розробки, на початку проекту було прийнято рішення
мінімізувати кількість перевірки параметрів і обробки помилок у нс-3 кодова база. для
з цієї причини ми не витрачаємо багато часу на брудне тестування - це просто виявить
результати дизайнерського рішення, яке ми знаємо.

Ми хочемо це продемонструвати нс-3 програмне забезпечення працює за певних умов. ми
запозичте пару визначень, щоб трохи звузити це. The домен of застосовності is
набір встановлених умов, для яких модель була перевірена, порівняно з ними
реальності, наскільки це можливо, і визнано придатним для використання. The діапазон of точність є
узгодження між комп’ютеризованою моделлю та реальністю в межах області застосування.

Команда нс-3 Середовище тестування надає інструменти для налаштування та запуску тесту
середовищ у кількох системах (buildbot) і надає класи для заохочення чистого
тести для перевірки роботи системи в очікуваній «області застосовності»
і «діапазон точності».

Виступ
Гаразд, «виконавець» — це не справжнє англійське слово. Однак це дуже стислий неологізм
який досить часто використовується для опису того, чого ми хочемо нс-3 бути: потужним і досить швидким, щоб
виконати роботу.

Це справді стосується широкого предмета тестування продуктивності програмного забезпечення. Один із ключових
те, що робиться, це порівняти дві системи, щоб знайти, яка працює краще (див
контрольні показники). Це використовується, щоб продемонструвати, що, наприклад, нс-3 може виконувати основний вид
моделювання принаймні так само швидко, як конкуруючий інструмент, або його можна використовувати для ідентифікації частин
система, яка працює погано.

Перейдіть на вкладку нс-3 тестова основа, ми надаємо підтримку для визначення часу різних видів тестів.

Підтримка
Програмний продукт повинен бути зручним для обслуговування. Знову ж таки, це дуже широке твердження, але а
структура тестування може допомогти із завданням. Після того, як модель розроблена, перевірена та
перевірено, ми можемо неодноразово виконувати набір тестів для всієї системи, щоб переконатися
що він залишається дійсним і перевіреним протягом усього терміну служби.

Коли функція перестає функціонувати належним чином після певних змін у системі
інтегрований, він називається узагальнено a регресія. Спочатку термін регресія
стосується зміни, яка спричинила повторну появу раніше виправленої помилки, але цей термін є
розроблено для опису будь-яких змін, які порушують існуючу функціональність. Тут багато
види регресій, які можуть виникнути на практиці.

A місцевий регресія зміна безпосередньо впливає на змінений компонент. для
наприклад, якщо компонент змінено для виділення та звільнення пам’яті, але застарілі покажчики є
використовується, сам компонент виходить з ладу.

A віддалений регресія це той, у якому зміна одного компонента порушує функціональність
інший компонент. Це відображає порушення неявного, але, можливо, нерозпізнаного
договір між компонентами.

An викритий регресія це той, який створює ситуацію, коли раніше існувала помилка
що не вплинуло, раптово виявляється в системі. Це може бути так само просто, як фізичні вправи
шлях коду вперше.

A продуктивністі регресія це той, який викликає вимоги до продуктивності системи
бути порушеним. Наприклад, виконання певної роботи в функції низького рівня, яка може повторюватися
велика кількість разів може раптово зробити систему непридатною для використання з певних точок зору.

Команда нс-3 платформа тестування надає інструменти для автоматизації процесу перевірки та
перевірте код у нічних наборах тестів, щоб допомогти швидко визначити можливі регресії.

Тестування рамки
ns-3 складається з ядра симуляції, набору моделей, прикладів програм і тестів.
З часом нові учасники додають моделі, тести та приклади. Тестова програма Python
test.py виконує функції керівника виконання тесту; test.py можна запускати тестовий код і приклади
шукає регресії, може виводити результати в декілька форм і може керувати кодом
засоби аналізу покриття. Поверх цього ми шаруємо Buildbots які створюються автоматично
роботи, які виконують тестування надійності, запускаючи тестову структуру на різних системах
і з різними параметрами конфігурації.

BuildBots
На найвищому рівні тестування ns-3 знаходяться buildbots (сборкові роботи). Якщо ви
незнайомі з цією системою http://djmitche.github.com/buildbot/docs/0.7.11/.
Це автоматизована система з відкритим кодом, яка дозволяє нс-3 кожен повинен бути перебудований і перевірений
час щось змінилося. Запустивши buildbots на кількох різних системах, ми
може це гарантувати нс-3 збирається та виконується належним чином на всіх підтримуваних системах.

Користувачі (і розробники) зазвичай не взаємодіють із системою buildbot інакше, як
читайте його повідомлення щодо результатів тестування. Якщо виявлено збій в одному з
автоматизованих завдань збірки та тестування, buildbot надішле електронний лист на адресу ns-розробники
список адресатів. Цей електронний лист виглядатиме приблизно так

У повній URL-адресі, наведеній в електронному листі, можна шукати ключове слово не вдалося та
виберіть stdio посилання для відповідного кроку, щоб побачити причину помилки.

Будівельний робот тихо виконає свою роботу, якщо немає помилок, і система піддасться
створюйте та тестуйте цикли щодня, щоб переконатися, що все добре.

Test.py
Роботи buildbots використовують програму Python, test.py, який відповідає за роботу всіх
тести та збирання отриманих звітів у формі, зрозумілій людині. Ця програма є
також доступний для використання користувачами та розробниками.

test.py є дуже гнучким, дозволяючи користувачеві вказати кількість і тип тестів
бігати; а також кількість і вид продукції, яку потрібно створити.

Перед бігом test.py, переконайтеся, що приклади та тести ns3 створено на практиці
Наступні

$ ./waf configure --enable-examples --enable-tests
$ ./waf

За замовчуванням test.py проведе всі доступні тести та повідомить про статус у дуже стислій формі
форму. Виконання команди

$ ./test.py

призведе до ряду PASS, 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'
"складання" успішно завершено (0.939 с)
ПОМИЛКА: Models TestSuite ns3-wifi-propagation-loss-models
PASS: служба імен об’єктів TestSuite
ПРОЙДЕН: TestSuite pcap-файл-об’єкт
ПРОЙДЕНО: TestSuite ns3-tcp-cwnd
...
ПРОЙДЕНО: сумісність TestSuite ns3-tcp
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, --pyexample=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. Роботи buildbot виберуть 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

призводить до запуску цього єдиного набору тестів.

ПОМИЛКА: Models TestSuite ns3-wifi-propagation-loss-models

Щоб знайти детальну інформацію про збій, необхідно вказати тип виведення
бажаний. Наприклад, більшість людей, ймовірно, зацікавиться текстовим файлом:

$ ./test.py --suite=ns3-wifi-propagation-loss-models --text=results.txt

Це призведе до того, що один набір тестів буде запущено із записом статусу тесту в
файл ''results.txt''.

Ви повинні знайти щось подібне до наступного в цьому файлі

ПОМИЛКА: Набір тестів ''ns3-wifi-propagation-loss-models'' (реальний 0.02 користувач 0.01 система 0.00)
ПРОЙДЕНО: Тестовий приклад "Перевірити ... Friis ... модель ..." (реальний 0.01 користувач 0.00 система 0.00)
ПОМИЛКА: Тестовий приклад "Перевірити ... Відстань журналу ... модель" (реальний 0.01 користувач 0.01 система 0.00)
Подробиці:
Повідомлення: Отримано неочікуване значення SNR
Умова: [довгий опис того, що насправді не вдалося]
Фактично: 176.395
Обмеження: 176.407 +- 0.0005
Файл: ../src/test/ns3wifi/propagation-loss-models-test-suite.cc
Лінія: 360

Зауважте, що набір тестів складається з двох тестів. Перший тест перевірив
Модель втрат при розповсюдженні Фріса прийнято. У другому тестовому випадку не вдалося перевірити журнал
Модель поширення на відстані. У цьому випадку було знайдено SNR 176.395, і тест
очікуване значення 176.407 з точністю до трьох знаків після коми. Файл, який реалізовано
вказано невдалий тест, а також рядок коду, який викликав збій.

Якщо бажаєте, ви могли б так само легко написати файл HTML за допомогою --html варіант
як описано вище.

Зазвичай користувач виконує всі тести принаймні один раз після завантаження нс-3 щоб забезпечити це
його або її середовище було побудовано правильно та генерує правильні результати
відповідно до наборів тестів. Зазвичай розробники запускають набори тестів до і
після внесення змін, щоб переконатися, що вони не ввели регресію зі своїми
зміни. У цьому випадку розробники можуть не захотіти запускати всі тести, а лише частину. для
Наприклад, розробник може лише періодично запускати модульні тести під час створення
зміни до сховища. В цьому випадку, test.py можна сказати, щоб обмежити типи
тести, що виконуються для певного класу тестів. Наступна команда призведе лише до
виконуються модульні тести:

$ ./test.py --constrain=unit

Подібним чином наступна команда призведе до запуску лише прикладів димових тестів:

$ ./test.py --constrain=unit

Щоб переглянути короткий список юридичних типів обмежень, ви можете попросити, щоб вони були перелічені.
Наступна команда

$ ./test.py --kinds

призведе до відображення наступного списку:

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 с) Waf: вхід в каталог `/home/craigdo/repos/ns-3-allinone-test/ns-3-dev/build'
bvt: Тести перевірки складання (щоб перевірити, чи успішно завершено складання)
ядро: запустіть усі тести на основі TestSuite (за винятком прикладів)
приклад: Приклади (щоб побачити, чи успішно запускаються приклади програм)
продуктивність: Тести продуктивності (перевірте, чи система така швидка, як очікувалося)
система: системні тести (охоплює модулі для перевірки інтеграції модулів)
unit: модульні тести (в межах модулів для перевірки базової функціональності)

Будь-який із цих видів тесту можна надати як обмеження за допомогою --обмеження варіант.

Щоб переглянути короткий список усіх доступних наборів тестів, ви можете попросити їх відкрити
перераховані. Наступна команда,

$ ./test.py --list

призведе до відображення списку набору тестів, подібно до

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 с)
гістограма
ns3-wifi-перешкоди
ns3-tcp-cwnd
сумісність ns3-tcp
зразок
прилади-сітка-полум'я
devices-mesh-dot11s
прилади-сіт
...
служба імен об'єктів
Як передзвонити
Атрибути
конфиг
глобальне значення
командного рядка
основне-випадкове-число
об'єкт

Будь-який із цих наборів у списку можна вибрати для самостійного запуску за допомогою --люкс варіант як
показано вище.

Подібно до наборів тестів, можна запустити один приклад програми C++ за допомогою --приклад
варіант. Зауважте, що відносний шлях для прикладу включати не потрібно
виконувані файли, створені для прикладів C++, не мають розширень. Вхід

$ ./test.py --example=udp-echo

призводить до виконання цього єдиного прикладу.

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

призводить до виконання цього єдиного прикладу.

PASS: приклади examples/tutorial/first.py

Оскільки приклади Python не створюються, вам не потрібно вказувати каталог, де ns-3
було створено, щоб керувати ними.

Зазвичай, коли виконуються приклади програм, вони записують велику кількість даних файлу трасування.
Зазвичай це зберігається в базовому каталозі дистрибутива (наприклад,
/home/user/ns-3-dev). Коли test.py запускає приклад, це дійсно абсолютно байдуже
з файлами трасування. Він просто хоче визначити, чи можна створити та запустити приклад
без помилок. Оскільки це так, файли трасування записуються в a
/tmp/unchecked-traces каталог. Якщо ви запустите наведений вище приклад, ви зможете знайти
асоційовані udp-echo.tr та udp-echo-n-1.pcap файли там.

Список доступних прикладів визначається вмістом каталогу ''examples'' у
розподіл. Якщо вибрати приклад для виконання за допомогою --приклад варіант
test.py не буде робити жодних спроб вирішити, чи налаштовано приклад чи ні, це
просто спробує запустити його та повідомить про результат спроби.

Коли test.py запускається, за замовчуванням він спочатку переконається, що система була повністю завершена
побудований. Це можна подолати, вибравши --nowaf варіант.

$ ./test.py --list --nowaf

призведе до відображення списку наразі створених наборів тестів, подібно до:

ns3-wifi-propagation-loss-models
ns3-tcp-cwnd
сумісність ns3-tcp
pcap-файл-об'єкт
служба імен об'єктів
генератори випадкових чисел

Зверніть увагу на відсутність Ваф будувати повідомлення.

test.py також підтримує запуск наборів тестів і прикладів у valgrind. Valgrind - це a
гнучка програма для налагодження та профілювання виконуваних файлів Linux. За замовчуванням запускається valgrind
інструмент під назвою memcheck, який виконує низку функцій перевірки пам’яті, зокрема
виявлення доступу до неініціалізованої пам'яті, неправильне використання виділеної пам'яті (подвійне звільнення,
доступ після звільнення тощо) і виявлення витоків пам’яті. Це можна вибрати за допомогою
--подрібнити варіант.

$ ./test.py --grind

Коли він біжить, test.py і програми, які він виконує опосередковано, створюють велику кількість
тимчасові файли. Зазвичай вміст цих файлів нецікавий, однак у деяких
випадках може бути корисним (з метою налагодження) переглянути ці файли. test.py забезпечує
--зберігати параметр, який призведе до збереження цих тимчасових файлів після запуску
завершено. Файли зберігаються в каталозі під назвою testpy-вивід у підкаталозі
названо відповідно до поточного всесвітнього координованого часу (також відомого як Гринвіче).
час).

$ ./test.py --retain

Нарешті, test.py забезпечує -багатослівний варіант, який дозволить друкувати великі обсяги інформації
про його прогрес. Не очікується, що це буде дуже корисно, якщо немає
помилка. У цьому випадку ви можете отримати доступ до стандартного виведення та стандартної помилки
повідомляється за допомогою запущених наборів тестів і прикладів. Виберіть докладний у такий спосіб:

$ ./test.py --verbose

Усі ці варіанти можна змішувати та поєднувати. Наприклад, щоб запустити все ядро ​​ns-3
набори тестів під valgrind, у докладному режимі, під час генерації вихідного файлу HTML, один
зробив би:

$ ./test.py --verbose --grind --constrain=core --html=results.html

TestTaxonomy
Як згадувалося вище, тести згруповані в ряд широко визначених класифікацій
дозволяють користувачам вибірково запускати тести для вирішення різних видів тестування, які потрібні
має бути зроблено.

· Тести перевірки побудови

· Модульні тести

· Системні тести

· Приклади

· Тести продуктивності

BuildVerificationTests
Це відносно прості тести, які будуються разом із дистрибутивом і використовуються
щоб переконатися, що збірка майже працює. Наші поточні модульні тести живуть у
вихідні файли коду, який вони тестують і вбудовані в модулі ns-3; і так підходить
опис БВЦ. BVT живуть у тому самому вихідному коді, який вбудовано в код ns-3.
Наші поточні тести є прикладами такого роду тестів.

Блок Випробування
Модульні тести — це більш захоплюючі тести, які вдаються до деталей, щоб переконатися, що фрагмент коду
працює як рекламується в ізоляції. Насправді немає жодних причин для такого тесту
вбудований в модуль ns-3. Виявляється, наприклад, модульні тести для об'єкта
служба імен приблизно такого ж розміру, як і сам код служби імен об’єктів. Модульні тести
це тести, які перевіряють один біт функціональності, яка не вбудована в код ns-3,
але знаходиться в тому ж каталозі, що і код, який він тестує. Цілком можливо, що ці тести
також перевірте інтеграцію кількох файлів реалізації в модуль. Файл
src/core/test/names-test-suite.cc є прикладом такого тесту. Файл
src/network/test/pcap-file-test-suite.cc є ще одним прикладом використання відомого справного pcap
як тестовий векторний файл. Цей файл зберігається локально в каталозі src/network.

SYSTEM Випробування
Системні тести – це ті, які включають більше одного модуля в системі. У нас їх багато
цей тип тестів виконується в нашій поточній системі регресії, але вони зазвичай є
перевантажені приклади. Ми надаємо нове місце для цього виду тесту в каталозі
src/тест. Файл src/test/ns3tcp/ns3-interop-test-suite.cc є прикладом такого роду
тесту. Він використовує NSC TCP для тестування реалізації TCP ns-3. Часто буде тест
вектори, необхідні для такого тесту, і вони зберігаються в каталозі, де знаходиться
тест життя. Наприклад, ns3tcp-interop-response-vectors.pcap — це файл, що складається з
кількість заголовків TCP, які використовуються як очікувані відповіді тестованого TCP ns-3
до стимулу, створеного NSC TCP, який використовується як «відомо хороша» реалізація.

прикладів
Приклади перевіряються фреймворком, щоб переконатися, що вони створені та працюватимуть. Нічого немає
позначено, і наразі файли pcap просто списані в / Tmp бути викинутим. Якщо
приклади запускаються (без збоїв) вони проходять цей димовий тест.

продуктивність Випробування
Тести продуктивності – це ті, які перевіряють певну частину системи та визначають
якщо випробування виконано до кінця в прийнятний час.

Робота Випробування
Тести зазвичай виконуються на високому рівні test.py програма. Щоб отримати список
доступні параметри командного рядка, запустіть test.py --допомога

Тестова програма test.py виконуватиме як тести, так і ті приклади, які були додані
список для перевірки. Різниця між тестами і прикладами полягає в наступному. Тести
загалом перевіряють відповідність конкретних результатів моделювання або подій очікуваній поведінці.
Навпаки, вихід прикладів не перевіряється, а тестова програма лише перевіряє
статус виходу програми-прикладу, щоб переконатися, що вона працює без помилок.

Коротко кажучи, щоб запустити всі тести, спочатку потрібно налаштувати тести на етапі налаштування, і
також (необов'язково) приклади, якщо приклади потрібно перевірити:

$ ./waf --configure --enable-examples --enable-tests

Потім побудуйте ns-3, а після його створення просто запустіть test.py. test.py -h покаже число
параметрів конфігурації, які змінюють поведінку test.py.

Програма test.py викликає для C++ тестів і прикладів програму C++ нижчого рівня під назвою
бігун-випробувач щоб фактично запустити тести. Як обговорюється нижче, це бігун-випробувач може бути а
корисний спосіб налагодження тестів.

Налагодження Випробування
Налагодження тестових програм найкраще виконувати за допомогою низькорівневої тестової програми
програма. Тест-рунер є мостом від загального коду Python до нс-3 код. Це є
написаний на C++ і використовує процес автоматичного виявлення тестів у нс-3 код для пошуку і
дозволяють виконувати всі різноманітні тести.

Основна причина, чому test.py не підходить для налагодження, це те, що це не дозволено для
ведення журналу буде ввімкнено за допомогою NS_LOG змінна середовища під час запуску test.py. Це
обмеження не застосовуються до виконуваного файлу тестового засобу. Отже, якщо ви хочете побачити журналювання
вихід із ваших тестів, ви повинні запускати їх безпосередньо за допомогою засобу запуску тестів.

Для того, щоб виконати тест-запуск, ви запускаєте його, як і будь-який інший виконуваний файл 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'
"складання" успішно завершено (0.353 с)
--assert: вказує тестам segfault (як assert), якщо виявлено помилку
--basedir=dir: встановити базовий каталог (де знайти src) на ''dir''
--tempdir=dir: встановити для тимчасового каталогу (де знайти файли даних) значення ''dir''
--constrain=test-type: обмежити перевірки наборами тестів типу ''test-type''
--help: надрукувати це повідомлення
--kinds: список усіх доступних видів тестів
--list: список усіх наборів тестів (необов’язково обмежений типом тесту)
--out=ім'я-файлу: встановити вихідний файл тестового статусу на ''ім'я-файлу''
--suite=назва-набору: запустити набір тестів під назвою ''назва-набору''
--verbose: увімкнути повідомлення в наборах тестів запуску

Вам доступна низка речей, які будуть вам знайомі, якщо ви знаєте
подивився на test.py. Цього слід було очікувати, оскільки програма виконання тестів — це лише інтерфейс
між test.py та нс-3. Ви можете помітити, що тут відсутні команди, пов’язані з прикладами.
Це тому, що прикладів насправді немає нс-3 тести test.py керує ними так, ніби вони є
представити уніфіковане середовище тестування, але насправді вони абсолютно різні, а ні
тут можна знайти.

Перший новий параметр, який з’являється тут, але не в test.py, це --стверджувати варіант. Це
Параметр корисний під час налагодження тестового випадку під час роботи під налагоджувачем, подібним до gdb. Коли
вибрано, цей параметр повідомляє базовому тесту, що він повинен викликати порушення сегментації, якщо
виявлено помилку. Це має приємний побічний ефект, спричиняючи зупинку виконання програми
(зламатися в налагоджувачі), коли виявлено помилку. Якщо ви використовуєте gdb, ви можете використовувати
цей варіант щось на зразок,

$ ./waf оболонка
$ cd build/debug/utils
$ gdb тестовий запуск
$ run --suite=global-value --assert

Якщо потім буде виявлено помилку в наборі тестів глобального значення, буде згенеровано помилку сегмента
і налагоджувач (на рівні джерела) зупиниться на NS_TEST_ASSERT_MSG що виявив
помилка

Ще одна нова опція, яка з’являється тут, це --basedir варіант. Виявляється, деякі
тести можуть потребувати посилання на вихідний каталог нс-3 розповсюдження, щоб знайти місцевий
даних, тому для виконання тесту завжди потрібен базовий каталог.

Якщо ви запускаєте тест із test.py, програма Python надасть параметр basedir для
ви. Щоб запустити один із тестів безпосередньо з програми виконання тестів за допомогою WAF, вам потрібно буде
вкажіть набір тестів для запуску разом із базовим каталогом. Отже, ви можете використовувати оболонку
і робіть:

$ ./waf --run "test-runner --basedir=`pwd` --suite=pcap-file-object"

Зверніть увагу на «зворотні» лапки на pwd команда

Якщо ви запускаєте набір тестів із налагоджувача, це може бути дуже боляче згадувати
і постійно вводьте абсолютний шлях базового каталогу розповсюдження. Тому що
це, якщо ви опустите basedir, тестувальник спробує визначити один для вас. Це
починається в поточному робочому каталозі та проходить деревом каталогів у пошуках a
файл каталогу з назвами файлів Версія та ЛІЦЕНЗІЯ. Якщо він знайде такий, він припускає, що
повинен бути базовим каталогом і надавати його для вас.

Перевірити вихід
Багато наборів тестів потребують запису тимчасових файлів (наприклад, файлів pcap) у процесі
виконання тестів. Тоді тестам потрібен тимчасовий каталог для запису. Python
утиліта тестування (test.py) надасть тимчасовий файл автоматично, але якщо працювати окремо
необхідно надати цей тимчасовий каталог. Так само, як і у випадку basedir, це може бути
дратує постійно надавати a -Темпдір, тож учасник тестування зрозуміє один
для вас, якщо ви не надасте його. Спочатку він шукає змінні середовища з назвою TMP
та TEMP і використовує їх. Якщо ні TMP ні TEMP визначені, які він вибирає / Tmp. Код
потім додає ідентифікатор, що вказує, що створило каталог (ns-3), а потім час
(hh.mm.ss), за яким йде велике випадкове число. Виконавець тесту створює для цього каталог
ім'я, яке буде використовуватися як тимчасовий каталог. Потім тимчасові файли переходять до каталогу, який
буде називатися приблизно так

/tmp/ns-3.10.25.37.61537845

Час надається як підказка, щоб ви могли відносно легко реконструювати що
каталог використовувався, якщо вам потрібно повернутися назад і переглянути файли, які були в ньому розміщені
каталог.

Іншим класом вихідних даних є тестові вихідні дані, такі як трасування pcap, які генеруються для порівняння
еталонний вихід. Програма тестування зазвичай видаляє їх після завершення тестування
бігти. Щоб вимкнути видалення тестового виводу, запустіть test.py з опцією «зберегти»:

$ ./test.py -r

а результат тесту можна знайти в testpy-вихід/ каталог.

Звітність of тест збої
Коли ви запускаєте набір тестів за допомогою засобу виконання тестів, він за умовчанням запускатиме тест тихо.
Єдина ознака того, що ви отримаєте, що тест пройдено, це відсутність повідомлення
від 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, це має бути досить зрозумілим. Це також не a
повний XML-файл, оскільки набори тестів розроблено таким чином, щоб їхні результати додавалися до основного
Файл стану XML, як описано в test.py .

Налагодження тест набір збої
Щоб налагодити тестові збої, наприклад

ЗБІЙ: TestSuite ns3-wifi-interference

Ви можете отримати доступ до базової програми запуску тестів через gdb наступним чином, а потім передати
Аргумент "--basedir=`pwd`" для запуску (ви також можете передати інші аргументи за потреби, але
basedir є необхідним мінімумом):

$ ./waf --command-template="gdb %s" --run "test-runner"
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'
"складання" успішно завершено (0.380 с)
GNU gdb 6.8-debian
Авторське право (C) 2008 Free Software Foundation, Inc.
Ліцензія 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 devices-mesh-dot11s-regression

$ ./waf --command-template="valgrind %s --basedir=`pwd` --suite=devices-mesh-dot11s-regression" --запустити програму тестування

Клас TestRunner
Виконувані файли, які запускають спеціальні тестові програми, використовують клас TestRunner. Цей клас
забезпечує автоматичну реєстрацію тестів і список, а також спосіб виконання
індивідуальні тести. Окремі набори тестів використовують глобальні конструктори C++ для додавання
набір наборів тестів, якими керує виконавець тестів. Тестовий бігун використовується для перерахування
усі доступні тести та вибрати тест для виконання. Це досить простий клас
який надає три статичні методи для надання або додавання та отримання наборів тестів до a
збірник тестів. Перегляньте doxygen для класу ns3::TestRunner for details.

Перевірити Suite
ВСІ нс-3 тести поділяються на набори тестів і тести. Набір тестів - це a
набір тестів, які повністю реалізують певний вид функціональності. як
описані вище, набори тестів можна класифікувати як,

· Тести перевірки побудови

· Модульні тести

· Системні тести

· Приклади

· Тести продуктивності

Ця класифікація експортується з класу TestSuite. Цей клас досить простий,
існує лише як місце для експорту цього типу та накопичення тестових випадків. Від користувача
З точки зору, щоб створити новий TestSuite у системі, потрібно лише визначити новий
клас, який успадковує клас TestSuite і виконувати ці два обов’язки.

Наступний код визначить новий клас, який можна запускати test.py як ''одиничний'' тест
з відображуваним іменем, ім'я мого тестового набору.

клас MySuite : публічний TestSuite
{
громадськості:
MyTestSuite ();
};

MyTestSuite::MyTestSuite ()
: TestSuite ("назва мого тестового пакету", UNIT)
{
AddTestCase (новий MyTestCase);
}

MyTestSuite myTestSuite;

Базовий клас виконує всю реєстрацію та звітність, необхідні для того, щоб бути товаром
громадянина в рамках тесту.

Перевірити випадок
Індивідуальні тести створюються за допомогою класу TestCase. Загальні моделі використання тесту
case включає «один тестовий приклад на функцію» та «один тестовий приклад на метод». Суміші з
ці моделі можна використовувати.

Щоб створити новий тестовий приклад у системі, все, що потрібно зробити, це успадкувати від
Тестовий випадок базовий клас, перевизначте конструктор, щоб дати тестовому прикладу ім’я та перевизначити
DoRun спосіб виконання тесту.

клас MyTestCase : загальнодоступний TestCase
{
MyTestCase ();
віртуальний void DoRun (порожній);
};

MyTestCase::MyTestCase ()
: TestCase ("Перевірте деякі функції")
{
}

анулювати
MyTestCase::DoRun (порожній)
{
NS_TEST_ASSERT_MSG_EQ (true, true, "Деяке повідомлення про помилку");
}

Комунальні послуги
Існує ряд різноманітних утиліт, які також є частиною тестування
рамка. Приклади включають узагальнений файл pcap, корисний для зберігання тестових векторів; a
загальний контейнер, корисний для тимчасового зберігання тестових векторів під час виконання тесту; і
інструменти для створення презентацій на основі результатів валідаційного та верифікаційного тестування.

Ці утиліти тут не задокументовані, але, наприклад, подивіться, як перевіряє TCP
знайдено в src/test/ns3tcp/ використовувати файли pcap і вихідні дані.

Як до запис Тести
Основна мета проекту ns-3 — допомогти користувачам покращити валідність і
достовірність їх результатів. Є багато елементів для отримання дійсних моделей і
моделювання, а тестування є основним компонентом. Якщо ви надаєте моделі чи приклади
ns-3, вас можуть попросити надати тестовий код. Будуть використані моделі, які ви надаєте
протягом багатьох років іншими людьми, які, мабуть, не мають уявлення на перший погляд, чи є
модель правильна. Тестовий код, який ви пишете для своєї моделі, допоможе уникнути майбутнього
регресії у вихідних даних і допоможе майбутнім користувачам зрозуміти перевірку та
межі застосовності ваших моделей.

Існує багато способів перевірити правильність реалізації моделі. У цьому
розділі, ми сподіваємося охопити деякі поширені випадки, які можна використовувати як посібник для написання нового
тести

Зразок TestSuite скелет
Якщо почати з нуля (тобто не додавати TestCase до існуючого TestSuite), ці
речі потрібно вирішити заздалегідь:

· Як буде називатися набір тестів

· Який це буде тип тесту (тест перевірки збірки, модульний тест, системний тест або
Тест продуктивності)

· Де знаходитиметься тестовий код (в існуючому модулі ns-3 або окремо в
каталог src/test/). Вам потрібно буде відредагувати файл wscript у цьому каталозі
скомпілюйте ваш новий код, якщо це новий файл.

Програма під назвою src/create-module.py є хорошою відправною точкою. Ця програма може бути
викликаний такий як create-module.py маршрутизатор для гіпотетичного нового модуля під назвою маршрутизатор. Одного разу
ви зробите це, ви побачите a маршрутизатор довідник і a test/router-test-suite.cc тестовий набір.
Цей файл може бути відправною точкою для вашого початкового тесту. Це робочий набір тестів,
хоча фактично проведені тести є тривіальними. Скопіюйте його до тесту свого модуля
і виконайте глобальну заміну "Маршрутизатор" у цьому файлі на щось, що стосується
до моделі, яку ви хочете перевірити. Ви також можете редагувати речі, наприклад більш описові
назва тестового випадку.

Вам також потрібно додати блок у свій wscript, щоб компілювати цей тест:

module_test.source = [
'test/router-test-suite.cc',
]

Перш ніж ви почнете робити корисні речі, спробуйте запустити
скелет. Переконайтеся, що для ns-3 налаштовано опцію «--enable-tests».
Припустімо, що ваш новий набір тестів називається «маршрутизатор», як тут:

RouterTestSuite::RouterTestSuite ()
: TestSuite ("маршрутизатор", UNIT)

Спробуйте цю команду:

$ ./test.py -s маршрутизатор

Повинен бути отриманий такий результат, як показано нижче:

PASS: маршрутизатор TestSuite
1 із 1 тестів пройдено (1 пройдено, 0 пропущено, 0 невдало, 0 збоїв, 0 помилок valgrind)

Дивіться src/lte/test/test-lte-antenna.cc для робочого прикладу.

Перевірити макроси
Існує кілька макросів, доступних для перевірки результатів тестової програми з очікуваними
вихід. Ці макроси визначено в src/core/model/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 приклад більшість квитків вже розпродано! до тест набір
Можна "перевірити", щоб приклади компілювалися та успішно завершувалися (без
витік пам'яті) за допомогою examples-to-run.py сценарій, розташований у тестовому каталозі вашого модуля.
Коротше кажучи, включивши екземпляр цього файлу у свій тестовий каталог, ви можете викликати
запуск тестів для виконання наведених прикладів. Зазвичай краще переконатися, що ви
виберіть приклади, які мають досить короткий час виконання, щоб не завадити тестам. Побачити
приклад в src/lte/тест/ каталог.

Тестування та цінності boolean Результати
Тестування Результати коли випадковість is залучений
Тестування вихід дані проти a відомий розподіл
Забезпечення нетривіальний вхід вектори of дані
Зберігання та посилання нетривіальний вихід дані
Представлення ваш вихід тест дані
Підтримка
створення a new нс-3 модель
У цьому розділі описано процес проектування нс-3 модель. У багатьох дослідницьких випадках,
користувачі не будуть задоволені простою адаптацією існуючих моделей, але можуть захотіти розширити
ядро симулятора новим способом. Ми використаємо приклад додавання ErrorModel до a
простий нс-3 посилання як мотивуючий приклад того, як можна підійти до цієї проблеми
продовжити проектування та впровадження.

ПРИМІТКА:
документація

Тут ми зосереджуємося на процесі створення нових моделей і нових модулів, а також на деяких з них
вибір дизайну. Задля ясності ми відкладаємо обговорення механіка
документування моделей і вихідного коду до документація глави.

Дизайн Підхід
Подумайте, як ви хочете, щоб це працювало; що воно повинно робити. Подумайте про такі речі:

· функціональність: Яку функціональність він повинен мати? Які атрибути чи конфігурація
піддається користувачеві?

· повторне використання: Наскільки інші повинні мати можливість повторно використовувати мій дизайн? Чи можу я повторно використати код із
нс-2 щоб почати? Як користувач інтегрує модель з рештою іншого
моделювання?

· залежності: Як я можу зменшити введення зовнішніх залежностей у своєму новому коді
якомога більше (щоб зробити його більш модульним)? Наприклад, чи варто уникати будь-яких
залежність від IPv4, якщо я хочу, щоб він також використовувався IPv6? Чи варто уникати будь-якої залежності
на IP взагалі?

Не соромтеся звертатися до ns-3-користувачі or ns-розробники список, якщо у вас є запитання.
Зокрема, важливо подумати про загальнодоступний API вашої нової моделі та попросити
зворотній зв'язок. Це також допомагає повідомити інших про вашу роботу, якщо вона вам цікава
співробітники.

приклад: ErrorModel
Модель помилки існує в нс-2. Це дозволяє передавати пакети до об’єкта зі збереженням стану, який
визначає, на основі випадкової змінної, чи пошкоджений пакет. Абонент може
потім вирішити, що робити з пакетом (кинути його тощо).

Основним API моделі помилок є функція для передачі пакета та значення, яке повертається
ця функція є логічним значенням, яке повідомляє абоненту, чи відбулося будь-яке пошкодження. Примітка
що залежно від моделі помилки буфер пакетних даних може бути або не пошкоджений.
Давайте назвемо цю функцію «IsCorrupt()».

Наразі в нашому дизайні ми маємо:

клас ErrorModel
{
громадськості:
/ **
* \повертає true, якщо пакет слід вважати помилковим/пошкодженим
* \param pkt Пакет для застосування моделі помилок
*/
bool IsCorrupt (Ptr pkt);
};

Зверніть увагу, що ми не передаємо вказівник const, таким чином дозволяючи функції змінювати
пакет, якщо IsCorrupt() повертає true. Не всі моделі помилок фактично змінюють пакет;
слід задокументувати, чи пошкоджений буфер пакетних даних.

Нам також можуть знадобитися спеціалізовані версії цього, наприклад, у нс-2, тож хоча це не те
єдиний вибір дизайну для поліморфізму, ми припускаємо, що ми створимо підклас базового класу
ErrorModel для спеціалізованих класів, таких як RateErrorModel, ListErrorModel тощо, таких як
виконується в нс-2.

У цей момент ви можете подумати: «Чому б не зробити IsCorrupt() віртуальним методом?». Тобто
один підхід; інший — зробити публічну невіртуальну функцію непрямою через a
приватна віртуальна функція (це в C++ відоме як ідіома не віртуального інтерфейсу і є
прийнято в нс-3 клас ErrorModel).

Далі, чи повинен цей пристрій залежати від IP чи інших протоколів? Ми не хочемо
створити залежності від протоколів Інтернету (модель помилок має бути застосовна до
протоколи, не пов’язані з Інтернетом), тому ми матимемо це на увазі пізніше.

Ще одна міркування полягає в тому, як об’єкти включатимуть цю модель помилок. Ми передбачаємо введення
явний сетер у певних реалізаціях NetDevice, наприклад:

/ **
* Додайте ErrorModel отримання до PointToPointNetDevice.
*
* PointToPointNetDevice може додатково включати ErrorModel
* ланцюг отримання пакетів.
*
* @see ErrorModel
* @param em Ptr до ErrorModel.
*/
void PointToPointNetDevice::SetReceiveErrorModel(Ptr em);

Знову ж таки, це не єдиний вибір, який у нас є (моделі помилок можна об’єднати в безліч
інші об’єкти), але він задовольняє наш основний варіант використання, який полягає в тому, щоб дозволити користувачеві примусово
помилки під час успішної передачі пакетів на рівні NetDevice.

Після деяких роздумів і перегляду існуючого нс-2 коду, ось зразок API бази
клас і перший підклас, які можна опублікувати для початкового перегляду:

клас ErrorModel
{
громадськості:
ErrorModel ();
віртуальна ~ErrorModel ();
bool IsCorrupt (Ptr pkt);
void Reset (порожній);
void Enable (недійсний);
void Вимкнути (void);
bool IsEnabled (void) const;
private:
віртуальний bool DoCorrupt (Ptr pkt) = 0;
віртуальна порожнеча DoReset (void) = 0;
};

перелік ErrorUnit
{
EU_BIT,
EU_BYTE,
EU_PKT
};

// Визначаємо, які пакети мають помилку, що відповідає базовому
// розподіл випадкової величини, частота помилок і одиниця для частоти.
клас RateErrorModel : загальнодоступна ErrorModel
{
громадськості:
RateErrorModel ();
віртуальна ~RateErrorModel ();
enum ErrorUnit GetUnit (void) const;
void SetUnit (enum ErrorUnit error_unit);
подвійний GetRate (void) const;
void SetRate (подвійна ставка);
void SetRandomVariable (const RandomVariable &ranvar);
private:
віртуальний bool DoCorrupt (Ptr pkt);
віртуальна порожнеча DoReset (пустота);
};

Ліси
Припустимо, ви готові приступити до впровадження; у вас є досить чітка картина
те, що ви хочете побудувати, і, можливо, ви запросили деякий початковий огляд або пропозиції від
список. Один із способів підійти до наступного кроку (впровадження) — це створити риштування та
заповнюйте деталі в міру розвитку дизайну.

У цьому розділі описано багато кроків, які слід розглянути, щоб визначити риштування або
нефункціональний скелет того, що зрештою буде реалізовано вашою моделлю. Зазвичай це добре
попрактикуйтесь не чекати, щоб ці деталі були інтегровані наприкінці, а натомість переходити a
скелет вашої моделі в систему на ранній стадії, а потім додайте функції пізніше після API та
інтеграція здається правильною.

Зауважте, що ви захочете змінити кілька речей у наведеній нижче презентації для вашої моделі
оскільки якщо ви дослівно дотримуєтеся моделі помилок, створений вами код буде суперечити
існуюча модель помилок. Нижче наведено лише схему того, як ErrorModel була побудована вами
можна адаптувати до інших моделей.

Розгляд нс-3 Кодування стиль Документ
На цьому етапі ви можете зупинитися та прочитати нс-3 документ стилю кодування, особливо
якщо ви плануєте повернути свій код до проекту. Стиль кодування
Посилання на документ розміщено на головній сторінці проекту: нс-3 кодування стиль.

Вирішувати де in Source Дерево Модель Повинен Проживати
Всі нс-3 вихідний код моделі знаходиться в каталозі src /. Вам потрібно буде вибрати який
підкаталог, у якому він знаходиться. Якщо це якийсь код нової моделі, має сенс розмістити його
в src / десь у каталозі, зокрема для зручності інтеграції зі збіркою
системи.

У випадку моделі помилок це дуже пов’язано з класом пакета, тому це має сенс
реалізувати це в src/мережа/ модуль де нс-3 пакетів реалізовано.

WAF та wscript
нс-3 використовує Ваф будувати систему. Ви захочете інтегрувати свій новий нс-3 використовує Waf
будувати систему. Ви захочете інтегрувати ваші нові вихідні файли в цю систему. Це
вимагає, щоб ви додали свої файли до wscript файл, знайдений у кожному каталозі.

Давайте почнемо з порожніх файлів error-model.h і error-model.cc і додамо це
src/мережа/wscript. Справді, це лише питання додавання файлу .cc до решти
вихідні файли та файл .h до списку файлів заголовків.

Тепер перейдіть до каталогу верхнього рівня та введіть "./test.py". Ти не повинен був зламати
будь-що за цією операцією.

Include Охоронці
Далі додамо трохи включати гвардія у нашому файлі заголовка.:

#ifndef ПОМИЛКА_МОДЕЛЬ_H
#define ERROR_MODEL_H
...
#endif

простору імен ns3
нс-3 використовує нс-3 простору імен щоб ізолювати його символи від інших просторів імен. Як правило, a
наступним чином користувач поставить an нс-3 блок простору імен у файлі cc і h.:

простір імен ns3 {
...
}

На даний момент у нас є кілька скелетних файлів, у яких ми можемо почати визначати наші нові класи.
Заголовний файл виглядає так:

#ifndef ПОМИЛКА_МОДЕЛЬ_H
#define ERROR_MODEL_H

простір імен ns3 {

} // простір імен ns3
#endif

в той час як error-model.cc файл виглядає просто так:

#include "error-model.h"

простір імен ns3 {

} // простір імен ns3

Ці файли мають скомпілюватися, оскільки вони насправді не мають жодного вмісту. Тепер ми готові
почати додавати класи.

Початковий Реалізація
На даний момент ми все ще працюємо над деякими риштуваннями, але ми можемо почати визначати наші
класи з функціями, які будуть додані пізніше.

Спадщина від Об'єкт Клас?
Це важливий етап проектування; чи використовувати клас Об'єкт як базовий клас для вашого нового
класи.

Як описано в розділі про нс-3 Об'єктна модель, класи, які успадковують клас
Об'єкт отримати особливі властивості:

· нс-3 тип і система атрибутів (див. Атрибути)

· система агрегації об'єктів

· система підрахунку посилань розумного вказівника (клас Ptr)

Класи, що походять від класу ObjectBase} отримати перші дві властивості вище, але ні
отримати розумні вказівники. Класи, що походять від класу RefCountBase отримати лише розумний покажчик
система підрахунку посилань.

На практиці клас Об'єкт є варіантом трьох вищезазначених нс-3 розробник буде
найчастіше зустрічаються.

У нашому випадку ми хочемо використовувати систему атрибутів, і ми будемо передавати екземпляри
цього об'єкта поперек нс-3 публічний API, тому клас Об'єкт підходить для нас.

Початковий Класи
Один із способів продовжити — почати з визначення мінімуму функцій і подивитися, чи вони будуть
компілювати. Давайте розглянемо, що все потрібно реалізувати, коли ми походить від класу Object.:

#ifndef ПОМИЛКА_МОДЕЛЬ_H
#define ERROR_MODEL_H

#include "ns3/object.h"

простір імен ns3 {

class ErrorModel : публічний об’єкт
{
громадськості:
статичний TypeId GetTypeId (void);

ErrorModel ();
віртуальна ~ErrorModel ();
};

клас RateErrorModel : загальнодоступна ErrorModel
{
громадськості:
статичний TypeId GetTypeId (void);

RateErrorModel ();
віртуальна ~RateErrorModel ();
};
#endif

Тут слід зауважити кілька речей. Треба включити об'єкт.ч. З’їзд в нс-3 це що, якщо
файл заголовка розташований у тому самому каталозі, його можна включити без будь-якого шляху
префікс. Тому, якби ми реалізовували ErrorModel у src/ядро/модель каталог, ми
міг просто сказати "#включати "об'єкт.h"". Але ми прийшли src/мережа/модель, тому ми повинні
включити це як "#включати "ns3/object.h"". Зауважте також, що це виходить за межі простору імен
декларація

По-друге, кожен клас повинен реалізовувати статичну публічну функцію-член, яка називається GetTypeId (недійсна).

По-третє, гарною ідеєю є впровадження конструкторів і деструкторів, а не дозволяти
компілятор генерує їх і робить деструктор віртуальним. У C++ також зверніть увагу на цю копію
Оператор присвоєння та конструктори копіювання генеруються автоматично, якщо вони не визначені, отже
якщо ви не хочете їх, ви повинні реалізувати їх як приватні члени. Цей аспект
C++ обговорюється в книзі Скотта Мейєрса «Ефективний C++». пункт 45.

Давайте тепер розглянемо відповідний код скелетної реалізації у файлі .cc:

#include "error-model.h"

простір імен ns3 {

NS_OBJECT_ENSURE_REGISTERED (ErrorModel);

TypeId ErrorModel::GetTypeId (недійсний)
{
static TypeId tid = TypeId ("ns3::ErrorModel")
.SetParent ()
;
повертатися до їжі;
}

ErrorModel::ErrorModel ()
{
}

ErrorModel::~ErrorModel ()
{
}

NS_OBJECT_ENSURE_REGISTERED (RateErrorModel);

TypeId RateErrorModel::GetTypeId (недійсний)
{
static TypeId tid = TypeId ("ns3::RateErrorModel")
.SetParent ()
.AddConstructor ()
;
повертатися до їжі;
}

RateErrorModel::RateErrorModel ()
{
}

RateErrorModel::~RateErrorModel ()
{
}

Що таке GetTypeId (недійсна) функція? Ця функція робить декілька речей. Він реєструє a
унікальний рядок у систему TypeId. Він встановлює ієрархію об'єктів у
система атрибутів (через SetParent). Він також оголошує, що певні об'єкти можуть бути створені через
структура створення об'єкта (AddConstructor).

Макрос NS_OBJECT_ENSURE_REGISTERED (назва класу) потрібен також один раз для кожного класу, який
визначає новий метод GetTypeId і виконує фактичну реєстрацію класу в
система. Розділ «Об’єктна модель» обговорює це більш детально.

У тому числі Зовнішній Файли
Запис Підтримка
Тут, запис a біт про додати |ns3| каротаж макроси. Примітка: Що LOG_COMPONENT_FINE is
зроблений поза простору імен ns3

конструктор, порожній функція прототипи
ключ Змінні (За замовчуванням Цінності, Атрибути)
Перевірити програма 1
Об'єкт Рамки
Додавання a Зразок Script
На цьому етапі можна спробувати взяти базові каркаси, визначені вище, і додати їх
в систему. Виконання цього кроку тепер дозволяє використовувати простішу модель під час сантехніки
у систему, а також може виявити, чи потрібно вносити зміни в дизайн або API
зробив. Коли це буде зроблено, ми повернемося до розробки функціональності
Самі ErrorModels.

додавати Базовий Підтримка in Клас
/* point-to-point-net-device.h */
клас ErrorModel;

/ **
* Модель помилок для подій отримання пакетів
*/
Ptr m_receiveErrorModel;

додавати Аксесуар
анулювати
PointToPointNetDevice::SetReceiveErrorModel (Ptr em)
{
NS_LOG_FUNCTION (це << em);
m_receiveErrorModel = em;
}

.AddAttribute ("ReceiveErrorModel",
«Модель помилки приймача, яка використовується для імітації втрати пакетів»,
PointerValue (),
MakePointerAccessor (&PointToPointNetDevice::m_receiveErrorModel),
MakePointerChecker ())

схил В SYSTEM
void PointToPointNetDevice::Receive (Ptr пакет)
{
NS_LOG_FUNCTION (цей << пакет);
uint16_t протокол = 0;

if (m_receiveErrorModel && m_receiveErrorModel->IsCorrupt (пакет) )
{
//
// Якщо у нас є модель помилки, і вона вказує, що настав час втратити a
// пошкоджений пакет, не пересилайте цей пакет, відпустіть його.
//
m_dropTrace (пакет);
}
ще
{
//
// Використовуйте гачок трасування прийому, видаляйте заголовок протоколу точка-точка
// і переслати цей пакет вверх по стеку протоколів.
//
m_rxTrace (пакет);
ProcessHeader(пакет, протокол);
m_rxCallback (цей, пакет, протокол, GetRemote ());
якщо (!m_promiscCallback.IsNull ())
{ m_promiscCallback (цей, пакет, протокол, GetRemote (),
GetAddress (), NetDevice::PACKET_HOST);
}
}
}

Створити Null Функціональний Script
/* simple-error-model.cc */

// Модель помилок
// Ми хочемо додати модель помилки до NetDevice вузла 3
// Ми можемо отримати дескриптор NetDevice через канал і вузол
// покажчики
Ptr nd3 = PointToPointTopology::GetNetDevice
(n3, канал2);
Ptr em = Створити ();
nd3->SetReceiveErrorModel (em);

бул
ErrorModel::DoCorrupt (Packet& p)
{
NS_LOG_FUNCTION;
NS_LOG_UNCOND("Пошкоджено!");
повернення помилковим;
}

На цьому етапі ми можемо запустити програму з нашою тривіальною ErrorModel, підключеною до приймача
шлях до PointToPointNetDevice. Він друкує рядок "Corrupt!" за кожен пакет
отримано у вузлі n3. Далі ми повертаємося до моделі помилок, щоб додати підклас, який працює
більш цікаве моделювання помилок.

додавати a Підклас
Тривіальний базовий клас ErrorModel не робить нічого цікавого, але він забезпечує a
корисний інтерфейс базового класу (Corrupt () і Reset ()), перенаправлений до віртуальних функцій, які
можуть бути підкласи. Давайте розглянемо те, що ми називаємо BasicErrorModel, на основі якої
нс-2 Клас ErrorModel (в ns-2/queue/errmodel.{cc,h}).

Які властивості ми хочемо мати, з точки зору інтерфейсу користувача? Ми хотіли б
щоб користувач міг тривіально замінити тип ErrorModel, який використовується в
NetDevice. Ми також хотіли б мати можливість встановлювати настроювані параметри.

Ось кілька простих вимог, які ми розглянемо:

· Можливість встановити випадкову величину, яка керує втратами (за замовчуванням UniformVariable)

· Можливість встановити одиницю (біт, байт, пакет, час) деталізації, за яку помилки
застосовано.

· Можливість встановити рівень помилок (наприклад, 10^-3), що відповідає наведеній вище одиниці
зернистість.

· Можливість увімкнути/вимкнути (за замовчуванням увімкнено)

Як до Підклас
Ми оголошуємо BasicErrorModel підкласом ErrorModel наступним чином:

клас BasicErrorModel: загальнодоступна модель помилки
{
громадськості:
статичний TypeId GetTypeId (void);
...
private:
// Реалізація чистих віртуальних функцій базового класу
віртуальний bool DoCorrupt (Ptr p);
віртуальний bool DoReset (void);
...
}

і налаштуйте функцію підкласу GetTypeId, встановивши унікальний рядок TypeId і
встановлення батьківського елемента на ErrorModel:

TypeId RateErrorModel::GetTypeId (недійсний)
{
static TypeId tid = TypeId ("ns3::RateErrorModel")
.SetParent ()
.AddConstructor ()
...

Будувати Core Функції та Блок Випробування
Assert Макрос
писемність Блок Випробування
Додавання a Нові Модулі до нс-3
Коли ви створили групу пов’язаних класів, прикладів і тестів, вони можуть бути
об'єднані в нс-3 таким чином, щоб їх можна було використовувати з існуючими нс-3 Модулі
та іншими дослідниками.

У цьому розділі описано кроки, необхідні для додавання нового модуля нс-3.

Крок 0 - Модулі макет
Усі модулі можна знайти в SRC каталог. Кожен модуль можна знайти в каталозі
який має таку саму назву, що й модуль. Наприклад, спектр модуль можна знайти тут:
src/спектр. Ми будемо цитувати з спектр модуль для ілюстрації.

Прототипний модуль має таку структуру каталогів і необхідні файли:

src /
назва модуля/
прив'язки/
doc/
приклади/
wscript
помічник/
модель/
тест /
examples-to-run.py
wscript

Не всі каталоги будуть присутні в кожному модулі.

Крок 1 - Створити a Модулі Скелет
У вихідному каталозі надається програма python, яка створить скелет для нового
модуль. Для цілей цього обговорення ми припустимо, що ваш новий модуль називається
новий модуль. З SRC виконайте такі дії, щоб створити новий модуль:

$ ./create-module.py новий модуль

Далі, cd в новий модуль; ви знайдете такий макет каталогу:

$ cd новий модуль
$ls
doc приклади допоміжної моделі тест wscript

Більш детально create-module.py сценарій створить каталоги, а також початкові
скелет wscript, .h, . CC та .по-перше файли. Виглядає повний модуль з файлами-скелетами
подобається це:

src /
новий-модуль/
doc/
новий-модуль.rst
приклади/
new-module-example.cc
wscript
помічник/
new-module-helper.cc
новий-модуль-помічник.h
модель/
новий-модуль.cc
новий-модуль.h
тест /
new-module-test-suite.cc
wscript

(Якщо потрібно, прив'язки/ каталог, зазначений у Крок 0 буде створено автоматично під час
збірка.)

Далі ми розглянемо, як налаштувати цей модуль. Інформування WAF про файли, які
створити свій модуль можна шляхом редагування двох wscript файли. Ми пройдемося по с
основні кроки в цьому розділі.

ВСІ нс-3 модулі залежать від ядро модуль і зазвичай на інші модулі. Ця залежність
зазначено в wscript файл (на верхньому рівні модуля, а не окремий wscript
файл у файлі Приклади каталог!). У скелеті wscript дзвінок, який оголосить ваш
новий модуль для WAF виглядатиме так (до редагування):

def build(bld):
module = bld.create_ns3_module('new-module', ['core'])

Припустимо, що новий модуль залежить від інтернет, мобільність та aodv модулі. Після
редагування його wscript файл має виглядати так:

def build(bld):
module = bld.create_ns3_module('new-module', ['internet', 'mobility', 'aodv'])

Зауважте, що в списку повинні бути вказані лише залежності модулів першого рівня, тому ми видалили
ядро; інтернет модуль, у свою чергу, залежить від ядро.

Ваш модуль, швидше за все, матиме вихідні файли моделі. Початкові скелети (які будуть
успішно скомпільовано) створюються в model/new-module.cc та модель/новий-модуль.h.

Якщо ваш модуль матиме допоміжні вихідні файли, вони потраплять до помічник/
довідник; знову початкові скелети створюються в цьому каталозі.

І, нарешті, гарною практикою є написання тестів і прикладів. Це майже напевно буде
необхідний для прийняття нових модулів в офіційний нс-3 вихідне дерево. Скелет
набір тестів і тестовий приклад створено в тест / каталог. Набір скелетних тестів буде
містить наведений нижче конструктор, який оголошує новий модульний тест під назвою новий модуль, При
один тестовий приклад, що складається з класу NewModuleTestCase1:

NewModuleTestSuite::NewModuleTestSuite ()
: TestSuite ("новий-модуль", UNIT)
{
AddTestCase (новий NewModuleTestCase1);
}

Крок 3 - Декларуйте Source Файли
Загальнодоступний заголовок і файли вихідного коду для вашого нового модуля слід вказати в
wscript файл, змінивши його за допомогою текстового редактора.

Як приклад, після оголошення спектр модуль, src/spectrum/wscript вказує
файли вихідного коду з таким списком:

def build(bld):

module = bld.create_ns3_module('spectrum', ['internet', 'propagation', 'antenna', 'applications'])

module.source = [
'model/spectrum-model.cc',
'model/spectrum-value.cc',
.
.
.
'model/microwave-oven-spectrum-value-helper.cc',
'helper/spectrum-helper.cc',
'helper/adhoc-aloha-noack-ideal-phy-helper.cc',
'helper/waveform-generator-helper.cc',
'helper/spectrum-analyzer-helper.cc',
]

Об’єкти, отримані в результаті компіляції цих джерел, будуть зібрані в бібліотеку посилань,
який буде пов’язано з будь-якими програмами, що покладаються на цей модуль.

Але як такі програми вивчають загальнодоступний API нашого нового модуля? Читай далі!

Крок 4 - Декларуйте громадськості Header Файли
Файли заголовків, що визначають загальнодоступний API вашої моделі та помічників, також мають бути
зазначені в wscript файлу.

Продовжуючи спектр модель ілюстрації, загальнодоступні файли заголовків вказані
з наступною строфою. (Зверніть увагу, що аргумент до блд функція розповідає WAF до
встановіть заголовки цього модуля разом з іншим нс-3 заголовки):

заголовки = bld(features='ns3header')

headers.module = 'спектр'

headers.source = [
'model/spectrum-model.h',
'model/spectrum-value.h',
.
.
.
'model/microwave-oven-spectrum-value-helper.h',
'helper/spectrum-helper.h',
'helper/adhoc-aloha-noack-ideal-phy-helper.h',
'helper/waveform-generator-helper.h',
'helper/spectrum-analyzer-helper.h',
]

Заголовки, опубліковані таким чином, будуть доступні користувачам вашої моделі за допомогою включення
заяви на кшталт

#include "ns3/spectrum-model.h"

Заголовки, які використовуються суто внутрішньо у вашій реалізації, не повинні включатися сюди. Вони
все ще доступні для вашої реалізації за допомогою таких операторів include

#include "my-module-implementation.h"

Крок 5 - Декларуйте Випробування
Якщо у вашому новому модулі є тести, то їх необхідно вказати у вашому wscript файл від
змінюючи його за допомогою текстового редактора.

Команда спектр моделі тестів уточнюються такою строфою:

module_test = bld.create_ns3_module_test_library('спектр')

module_test.source = [
'test/spectrum-interference-test.cc',
'test/spectrum-value-test.cc',
]

Читати Випробування щоб дізнатися більше про те, як писати тестові випадки.

Крок 6 - Декларуйте прикладів
Якщо у вашому новому модулі є приклади, то їх необхідно вказати у вашому приклади/wscript
файл. (Скелет верхнього рівня wscript буде рекурсивно включати приклади/wscript лише якщо
приклади було ввімкнено під час налаштування.)

Команда спектр модель визначає свій перший приклад у src/spectrum/examples/wscript з

def build(bld):
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 = ['new-module-example.cc', 'new-module-example-part.cc']

Приклади Python вказуються за допомогою наступного виклику функції. Зазначимо, що другий
аргумент для функції register_ns3_script() це список модулів, які Python
приклад залежить від:

bld.register_ns3_script('new-module-example.py', ['new-module'])

Крок 7 - прикладів прогін as Випробування
На додаток до запуску явного тестового коду, тестова структура також може бути оснащена інструментами
запустіть повні приклади програм, щоб спробувати вловити регресії в прикладах. Однак не всі
приклади підходять для регресійних тестів. Файл test/examples-to-run.py контролює
виклик прикладів під час запуску тестового фреймворку.

Команда спектр приклади моделей test.py зазначені в
src/spectrum/test/examples-to-run.py використовуючи наступні два списки C++ і Python
приклади:

# Список прикладів C++ для запуску, щоб переконатися, що вони залишаються
# можна будувати та запускати з часом. Кожен кортеж у списку містить
#
# (example_name, do_run, do_valgrind_run).
#
# Перегляньте test.py для отримання додаткової інформації.
cpp_examples = [
("adhoc-aloha-ideal-phy", "Правда", "Правда"),
("adhoc-aloha-ideal-phy-with-microwave-oven", "Правда", "Правда"),
("adhoc-aloha-ideal-phy-matrix-propagation-loss-model", "Правда", "Правда"),
]

# Список прикладів Python для запуску, щоб переконатися, що вони залишаються
# можна запускати з часом. Кожен кортеж у списку містить
#
# (example_name, do_run).
#
# Перегляньте test.py для отримання додаткової інформації.
python_examples = [
("sample-simulator.py", "True"),
]

Як зазначено в коментарі, кожен запис у списку C++ прикладів для запуску містить
кортеж (приклад_назви, do_run, do_valgrind_run), Де

· приклад_назва це виконуваний файл для запуску,

· do_run це умова виконання прикладу, і

· do_valgrind_run це умова, за якої можна запускати приклад у valgrind. (Це
необхідний, тому що NSC викликає збої незаконних інструкцій у деяких тестах, коли вони
запускаються під valgrind.)

Зверніть увагу, що дві умови є операторами Python, які можуть залежати від WAF конфігурація
змінні. Наприклад,

("tcp-nsc-lfn", "NSC_ENABLED == True", "NSC_ENABLED == False"),

Кожен запис у списку прикладів Python для запуску містить кортеж (приклад_назви,
do_run), де, як для прикладів C++,

· приклад_назва це сценарій Python, який потрібно запустити, і

· do_run є умовою для виконання прикладу.

Знову ж таки, умовою є оператор Python, який може залежати від WAF змінні конфігурації.
Наприклад,

("realtime-udp-echo.py", "ENABLE_REAL_TIME == False"),

Крок 8 - Конфігурувати та Будувати
Тепер ви можете налаштувати, зібрати та протестувати свій модуль як зазвичай. Ви повинні переналаштувати
проект як перший крок, щоб WAF зберігає нову інформацію у вашому wscript файли, або
інакше ваш новий модуль не буде включено до збірки.

$ ./waf configure --enable-examples --enable-tests
$ ./waf збірка
$ ./test.py

Знайдіть набір тестів нового модуля (і приклади програм, якщо вони є у вашому модулі).
увімкнено) у вихідних даних тесту.

Крок 9 - Python палітурки
Додавання прив’язок Python до вашого модуля є необов’язковим, і цей крок коментується
за замовчуванням у create-module.py сценарій

# bld.ns3_python_bindings()

Якщо ви хочете включити прив’язки Python (потрібно, лише якщо ви хочете написати Python ns-3
програми замість програм C++ ns-3), розкоментуйте наведене вище та інсталюйте
Систему сканування Python API (розглянуто в інших розділах цього посібника) і проскануйте свій модуль
генерувати нові прив'язки.

створення документація
нс-3 надає два види документації: пояснювальні розділи у стилі «посібник користувача» та
документація API вихідного коду.

Розділи «посібника користувача» написані від руки reStructuredText формат (.по-перше), який є
оброблено системою документації Python Сфінкс для створення веб-сторінок і pdf-файлів.
Документація API генерується з самого вихідного коду за допомогою Doxygen, генерувати
веб-сторінки з перехресними посиланнями. Обидва вони важливі: розділи про Сфінкса пояснюють чому
та огляд використання моделі; документація API пояснює як подробиці

У цьому розділі подано короткий огляд цих інструментів, наголошуючи на бажаному використанні та
налаштування для нс-3.

Щоб створити всю стандартну документацію:

$ ./waf документи

Про більш спеціалізовані варіанти читайте далі.

Документування з Сфінкс
Ми використовуємо Сфінкс створити пояснювальні розділи з описом дизайну та використання кожного з них
модуль. Прямо зараз ви читаєте документація Розділ. The Показати Source посилання в
бічна панель покаже джерело reStructuredText для цієї глави.

Додавання Нові глави
Для додавання нового розділу потрібно виконати три кроки (докладніше описано нижче):

1. вибирати Де? файл(и) документації буде жити.

2. посилання з існуючої сторінки на нову документацію.

3. Додайте новий файл до Makefile.

Де?
Документація для конкретного модуля, Foo, зазвичай має входити src/foo/doc/. Наприклад
src/foo/doc/foo.rst буде документом верхнього рівня для модуля. The
src/create-module.py сценарій створить цей файл для вас.

Деякі моделі потребують кількох .по-перше файли та фігури; все це має входити в
src/foo/doc/ каталог. Документи фактично створені за допомогою Sphinx Makefile. Для особливо
документацію, може бути корисним мати місцеву Makefile , src/foo/doc/
каталог для спрощення створення документації для цього модуля (антена є прикладом).
Налаштувати це не особливо складно, але це виходить за рамки цього розділу.

У деяких випадках документація охоплює декілька моделей; в мережу Розділ є прикладом. в
ці випадки додавання .по-перше файли безпосередньо до doc/models/source/ може бути доречним.

посилання
Сфінкс повинен знати де повинен з'явитися ваш новий розділ. У більшості випадків нова модель
розділ має з’явитися в моделі книга. Щоб додати свій розділ, відредагуйте
doc/models/source/index.rst

.. toctree::
:maxdepth: 1

організація
анімація
антена
aodv
застосування
...

Додайте назву свого документа (без .по-перше розширення) до цього списку. Будь ласка, збережіть
Моделюйте розділи в алфавітному порядку, щоб полегшити візуальне сканування окремих розділів.

Makefile
Ви також повинні додати свій документ до відповідного Makefile, так зробити знає це перевірити
для оновлень. Makefile книги моделей doc/models/Makefile, книга посібника Makefile є
doc/manual/Makefile.

# список усіх файлів бібліотеки моделей .rst, які потрібно скопіювати до $SOURCETEMP
ДЖЕРЕЛА = \
джерело/conf.py \
джерело/_static \
джерело/index.rst \
джерело/replace.txt \
джерело/організація.rst \
...
$(SRC)/antenna/doc/source/antenna.rst \
...

Ви додаєте свій .по-перше файли до ДЖЕРЕЛА змінна. Щоб додати цифри, читайте коментарі в
Makefile щоб побачити, яка змінна має містити файли зображень. Ще раз, будь ласка, збережіть це
в алфавітному порядку.

Обладнання для прокату Сфінкс документи
Створення документації Sphinx досить просте. Щоб побудувати всіх Сфінксів
документація:

$ ./waf сфінкс

Щоб створити лише документацію моделей:

$ make -C doc/models

Щоб переглянути згенеровану документацію, перейдіть у свій браузер doc/models/build/html.

Як бачите, Sphinx використовує Make для керування процесом. Ціль за замовчуванням створює все
включені форми виведення, які в нс-3 є багатосторінковими HTML, односторінковий singlehtml та
pdf (латекс). Щоб створити лише багатосторінковий html, ви додаєте HTML ціль:

$ make -C doc/models html

Це може бути корисним, щоб зменшити час збірки (і розмір балаканини збірки), як ви
пишуть ваш розділ.

Перш ніж передати свою документацію в репо, переконайтеся, що вона збирається без
помилки або попередження. Процес збирання генерує багато вихідних даних (переважно звичайну балаканину
з LaTeX), через що може бути важко побачити, чи є якісь попередження Sphinx або
помилки. Щоб знайти важливі попередження та помилки, створіть тільки HTML версії, потім знайдіть
журнал збірки для попередження or помилка.

нс-3 Конкретика
Сфінкс документація та підручник досить гарні. Ми не будемо дублювати основи
тут, натомість зосереджуючись на бажаному використанні для нс-3.

· Починайте документи з цих двох рядків:

.. включають:: replace.txt
.. виділити:: cpp

Перший рядок дозволяє виконати кілька простих замін. Наприклад, набір тексту |ns3| відображає як
нс-3. Другий встановлює стандартну мову підсвічування вихідного коду явно для
файл, оскільки припущення аналізатора не завжди точні. (Також можна встановити
мова явно для одного блоку коду, див. нижче.)

· Розділи:

Сфінкс досить ліберальний щодо позначення заголовків розділів. За умовами ми надаємо перевагу цьому
ієрархія:

.. ієрархія заголовків:
------------- Розділ
************* Розділ (#.#)
============= Підрозділ (#.#.#)
############## Підрозділ

· Підсвічування синтаксису:

Щоб використовувати стандартний підсвічувач синтаксису, просто запустіть блок вихідного коду:

┌─────────────────────────────────────────────────┬── ──────────────────────────────────┐
│Sphinx Джерело │ Відтворений результат │
├────────────────────────────────────────────────┼── ──────────────────────────────────┤
│ │ Фробніц має доступ: │
│ Доступ до ``Frobnitz`` має:: │ │
│ │ Foo::Frobnitz frob; │
│ Foo::Frobnitz frob; │ frob.Set (...); │
│ frob.Set (...); │ │
└─────────────────────────────────────────────────┴── ─────────────────────────────────┘

Щоб використовувати певний підсвічувач синтаксису, наприклад, бити команди оболонки:

┌───────────────────────────────────┬──────────────── ───┐
│Sphinx Джерело │ Відтворений результат │
├───────────────────────────────────┼──────────────── ───┤
│ │ │
│ .. вихідний код:: bash │ $ ls │
│ │ │
│ $ ls │ │
└───────────────────────────────────┴──────────────── ───┘

· Скорочені позначення:

Ці скорочення визначаються:

┌─────────────────────────┬───────────────────┐
│Sphinx Джерело │ Відтворений результат │
├─────────────────────────┼───────────────────┤
│ │ нс-3
│ |ns3| │ │
├─────────────────────────┼───────────────────┤
│ │ нс-2
│ |ns2| │ │
├─────────────────────────┼───────────────────┤
│ │ │
│ |перевірка| │ │
├─────────────────────────┼───────────────────┤
│ │ RFC 6282
│ :rfc:`6282` │ │
└─────────────────────────┴───────────────────┘

Документування з Doxygen
Ми використовуємо Doxygen генерувати доступний для перегляду Документація API. Doxygen надає ряд
корисні властивості:

· Зведена таблиця всіх учасників класу.

· Графи успадкування та співпраці для всіх класів.

· Посилання на вихідний код реалізації кожної функції.

· Посилання на кожне місце, де використовується учасник.

· Посилання на кожен об’єкт, який використовується для реалізації функції.

· Групування пов’язаних класів, наприклад, усіх класів, пов’язаних із певним протоколом.

Крім того, ми використовуємо TypeId систему для додавання до документації для кожного класу

· конфиг шляхи, якими можна дістатися до таких об'єктів.

· Документація на будь-яку Attributes, У тому числі Attributes визначені в батьківських класах.

· Документація на будь-яку Трасування джерела, визначені класом.

Doxygen працює, скануючи вихідний код, шукаючи спеціально позначені коментарі. Це
також створює перехресне посилання, вказуючи де кожен файл, клас, метод і змінна є
використаний

перевага стиль
Переважним стилем для коментарів Doxygen є стиль JavaDoc:

/ **
* Короткий опис цього класу або методу.
* Сусідні рядки стають одним абзацом.
*
* Довший опис із великою кількістю деталей.
*
* Пусті рядки відокремлюють абзаци.
*
* Поясніть, що робить клас або метод, використовуючи який алгоритм.
* Поясніть одиниці аргументів і значення, що повертаються.
*
* \note Зверніть увагу на будь-які обмеження чи проблеми.
*
* (Для функцій з аргументами або значеннями, що повертаються:)
* \param foo Коротка іменникова фраза, що описує цей аргумент.
* \param bar Примітка Регістр речення та кінцева точка.
* \return Коротка іменникова фраза, що описує значення.
*
* \внутрішній
*
* Ви також можете обговорити внутрішні деталі впровадження.
* Розуміння цього матеріалу не є обов’язковим для використання
* клас або метод.
*/
Приклад класу

У цьому стилі блок коментарів Doxygen починається з двох символів «*»: / **, і передує
предмет, який документується.

Для елементів, які потребують лише короткого опису, підходить будь-яка з цих коротких форм:

/** Реалізація деструктора. */
недійсний DoDispose ();

int m_count; //!< Кількість ...

Зверніть увагу на спеціальну форму коментаря до кінця рядка, //!, що вказує на те, що воно відноситься до
попередній пункт.

Деякі пункти, на які варто звернути увагу:

· Використовуйте відмінок речення, включаючи початкову велику.

· Використовуйте розділові знаки, особливо `.' в кінці речень або фраз.

· \коротко тег не потрібен; перше речення буде використано як коротке
опису

Кожен клас, метод, typedef, змінна-член, аргумент функції та значення, що повертається, повинні
бути задокументованим у всіх файлах вихідного коду, які утворюють офіційний API та реалізацію для
нс-3, Такі, як src/ /модель/*, src/ /помічник/* та src/ /utils/*.
Документація на предмети в src/ /тест/* та src/ /приклади/* надається перевага,
але не обов'язково.

Корисно Функції
· Успадковані учасники автоматично успадковують документи від батьківського (але їх можна замінити
за місцевою документацією).

1. Задокументуйте базовий клас.

2. У підкласі позначте успадковані функції звичайним коментарем:

// Успадковані методи
віртуальна порожнеча FooBar (пустота);
віртуальний int BarFoo (подвійний баз);

Зауважте, що підписи мають точно збігатися, тому додайте формальний аргумент (недійсна)

Це не працює для статичних функцій; побачити GetTypeId, нижче, для прикладу.

Обладнання для прокату Doxygen документи
Створення документації Doxygen досить просте:

$ ./waf 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 examples/routing/manet-routing-compare.cc
26 examples/stats/wifi-example-apps.h
....
----------------------------------------
967 файлів із попередженнями

Попередження за файлами (числові)

Графічний файл
----- ----------------------------------
374 src/lte/model/lte-asn1-header.h
280 src/lte/model/lte-rrc-sap.h
262 src/lte/model/lte-rrc-header.h
....
----------------------------------------
967 файлів із попередженнями

Резюме попереджень Doxygen
----------------------------------------
126 довідників
Файли 967
15765 попередження

Сценарій змінює конфігурацію, щоб відображати всі попередження та скорочувати час виконання.
Як бачите, на момент написання цього ми маємо a багато речей без документів. Звіт
підсумовує попередження за модулями src/*/*, і файлами, в алфавітному та нумераційному порядку.

У сценарії є кілька варіантів, щоб зменшити ситуацію та зробити це більш керованим. Для допомоги,
використовувати -h варіант. Запустивши його один раз, щоб зробити збірку Doxygen і створити повну
журнал попереджень, ви можете повторно обробити файл журналу за допомогою різних "фільтрів", не потребуючи цього
повна збірка Doxygen, знову використовуючи -s варіант. Ви можете виключити попередження з
*/приклади/* файли (-e опція) та/або */тест/* файли (-t).

Мабуть, найкориснішим варіантом під час написання коментарів до документації є -m , Яка
обмежить звіт лише відповідними файлами src/ /*, і стежити за звітом з
фактичні лінії попередження. Поєднувати з і ви можете зосередитися на попередженнях, які є
найбільш термінові в одному модулі:

$ doc/doxygen.warnings.report.sh -m mesh/helper
...
Резюме попереджень 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 Конкретика
Що стосується Сфінкса, то Доксіген Документи та посилання досить гарні. Ми не будемо дублювати
основи тут, натомість зосереджуючись на бажаному використанні для нс-3.

· Використовуйте Doxygen Модулі щоб згрупувати пов’язані елементи.

У головному заголовку для модуля створіть групу Doxgyen:

/ **
* \defgroup foo Протокол Foo.
*/

Позначте кожен пов’язаний клас як належний до групи:

/ **
* \ingroup foo
*
* Тип пакету Foo.
*/
клас Foo

· Ти знав typedefs може мати формальні аргументи? Це дозволяє документувати функцію
покажчик підписів:

/ **
* Підпис функції зворотного виклику панелі.
*
* \param ale Розмір пінти елю в імперських унціях.
*/
typedef void (* BarCallback)(const int ale);

· Скопіюйте атрибут довідкові рядки з GetTypeId метод для використання як короткий
описи асоційованих членів.

· \bugid{298} створить посилання на помилку 298 у нашій Bugzilla.

· \pname{foo} в описі буде формат Foo як \param Foo параметр, що робить його зрозумілим
що ви посилаєтесь на реальний аргумент.

· \RFC{301} створить посилання на RFC 301.

· \внутрішній слід використовувати лише для того, щоб розпочати обговорення деталей реалізації, а не для того, щоб
позначити приватний функції (вони вже позначені, як приватний!)

· Не створюйте класи з тривіальними назвами, наприклад клас A, навіть у наборах тестів. Ці
призводять до того, що всі екземпляри літералу імені класу `A' відображатимуться як посилання.

Як зазначалося вище, статичні функції не успадковують документацію тих самих функцій у
батьківський клас. нс-3 повсюдно використовує кілька статичних функцій; запропоноване
блок документації для цих випадків:

· Конструктор/деструктор за замовчуванням:

Мій клас (); //!< Конструктор за замовчуванням
~МійКлас (); //!< Деструктор

· Фіктивний деструктор і DoDispose:

/** Фіктивний деструктор, див. DoDispose. */
~МійКлас ();

/** Реалізація деструктора */
віртуальна порожнеча DoDispose ();

· GetTypeId:

/ **
* Зареєструйте цей тип.
* \return Об'єкт TypeId.
*/
статичний TypeId GetTypeId (void);

включення Підмножини of нс-3 Модулі
Як і в більшості програмних проектів, нс-3 постійно зростає з точки зору кількості модулів,
рядків коду та пам'яті. Однак користувачі можуть використовувати лише деякі з цих модулів
зараз. З цієї причини користувачі можуть захотіти явно ввімкнути лише підмножину
це можливо нс-3 модулі, які їм дійсно потрібні для дослідження.

У цьому розділі обговорюється, як увімкнути лише нс-3 модулі, які вас цікавлять
використання.

Як до включіть a підмножина of нс-3's Модулі
Якщо збираються спільні бібліотеки, увімкнення модуля спричинить принаймні один
бібліотека, яка буде створена:

libns3-modulename.so

Якщо модуль має бібліотеку тестів і бібліотеки тестів будуються, тоді

libns3-modulename-test.so

також буде побудовано. Інші модулі, від яких залежить модуль, і їхні тестові бібліотеки
також буде побудовано.

За замовчуванням усі модулі вбудовані нс-3. Є два способи ввімкнути підмножину з них
модулі:

1. Використання опції --enable-modules waf

2. Використання нс-3 файл конфігурації

включити Модулі використання waf's --enable-modules варіант
Щоб увімкнути лише основний модуль із прикладом і тестами, наприклад, спробуйте ці команди:

$ ./waf чистий
$ ./waf configure --enable-examples --enable-tests --enable-modules=core
$ ./waf збірка
$ cd build/debug/
$ls

і мають бути присутні такі бібліотеки:

прив'язки libns3-core.so ns3 scratch utils
приклади libns3-core-test.so зразки src

Зверніть увагу на ./waf очистити крок тут зроблено лише для того, щоб було очевидніше, які бібліотеки модулів
були побудовані. Ви не повинні робити ./waf очистити щоб увімкнути підмножини модулів.

Запуск test.py призведе до виконання лише тих тестів, які залежать від ядра модуля:

24 із 24 тестів пройдено (24 пройдено, 0 пропущено, 0 невдало, 0 збоїв, 0 помилок valgrind)

Повторіть наведені вище кроки для модуля «network» замість модуля «core» і
будується наступне, оскільки мережа залежить від ядра:

прив'язки libns3-core.so libns3-network.so ns3 scratch utils
приклади 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 міститься репозиторій вихідного коду
утиліти каталог. Причина цього полягає в тому, що він знаходиться в каталозі верхнього рівня
репозиторій, він буде схильний до випадкових перевірок від супроводжуючих, які вмикають
модулі, які вони хочуть використовувати. Таким чином, користувачам потрібно вручну скопіювати .ns3rc з
утиліти каталог у бажане місце (каталог верхнього рівня або домашній каталог).
увімкнути конфігурацію постійної модульної збірки.

Припускаючи, що ви на найвищому рівні нс-3 ви можете отримати копію .ns3rc
файл, який знаходиться в утиліти каталог таким чином:

$ cp utils/.ns3rc .

Файл .ns3rc тепер має бути на вашому верхньому рівні нс-3 каталог, і він містить
наступні:

#! /usr/bin/env пітон

# Список модулів, які будуть увімкнені під час запуску ns-3.
# Модулі, які залежать від перерахованих модулів, також будуть увімкнені.
#
# Усі модулі можна ввімкнути, вибравши 'all_modules'.
modules_enabled = ['усі_модулі']

# Встановіть значення true, якщо ви хочете, щоб приклади запускалися.
examples_enabled = False

# Встановіть значення true, якщо ви хочете, щоб тести запускалися.
tests_enabled = False

Використовуйте свій улюблений редактор, щоб змінити файл .ns3rc, щоб увімкнути лише основний модуль
такі приклади та тести:

#! /usr/bin/env пітон

# Список модулів, які будуть увімкнені під час запуску ns-3.
# Модулі, які залежать від перерахованих модулів, також будуть увімкнені.
#
# Усі модулі можна ввімкнути, вибравши 'all_modules'.
modules_enabled = ['core']

# Встановіть значення true, якщо ви хочете, щоб приклади запускалися.
examples_enabled = Правда

# Встановіть значення true, якщо ви хочете, щоб тести запускалися.
tests_enabled = Правда

Зараз буде ввімкнено лише основний модуль, якщо ви спробуєте виконати ці команди:

$ ./waf чистий
$ ./waf configure
$ ./waf збірка
$ cd build/debug/
$ls

і мають бути присутні такі бібліотеки:

прив'язки libns3-core.so ns3 scratch utils
приклади libns3-core-test.so зразки src

Зверніть увагу на ./waf очистити крок тут зроблено лише для того, щоб було очевидніше, які бібліотеки модулів
були побудовані. Ви не повинні робити ./waf очистити щоб увімкнути підмножини модулів.

Запуск test.py призведе до виконання лише тих тестів, які залежать від ядра модуля:

24 із 24 тестів пройдено (24 пройдено, 0 пропущено, 0 невдало, 0 збоїв, 0 помилок valgrind)

Повторіть наведені вище кроки для модуля «network» замість модуля «core» і
будується наступне, оскільки мережа залежить від ядра:

прив'язки libns3-core.so libns3-network.so ns3 scratch utils
приклади libns3-core-test.so libns3-network-test.so зразки src

Запуск test.py спричинить ті тести, які залежать лише від основного та мережевого модулів
запускати:

31 із 31 тестів пройдено (31 пройдено, 0 пропущено, 0 невдало, 0 збоїв, 0 помилок valgrind)

Увімкнення/вимкнення нс-3 Випробування та прикладів
Команда нс-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-tests

Запуск test.py на верхньому рівні нс-3 каталог викличе всі приклади та тести
для запуску:

170 із 170 тестів пройдено (170 пройдено, 0 пропущено, 0 невдало, 0 збоїв, 0 помилок valgrind)

Увімкнути / вимкнути Приклади та Тести використання WAF
Ви можете використовувати waf, щоб увімкнути/вимкнути приклади та тести один раз нс-3 було побудовано.

За замовчуванням приклади та тести не вбудовані нс-3.

З верхнього рівня нс-3 каталог, ви можете створити нс-3 просто без будь-яких прикладів чи тестів
виконуючи:

$ ./waf configure
$ ./waf збірка

Запуск test.py зараз не призведе до виконання прикладів або тестів:

0 із 0 тестів пройдено (0 пройдено, 0 пропущено, 0 невдало, 0 збоїв, 0 помилок valgrind)

Якщо ви хочете будувати нс-3 з прикладами та тестами, потім виконайте наступне зверху
рівень нс-3 каталог:

$ ./waf configure --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 міститься репозиторій вихідного коду
утиліти каталог. Причина цього полягає в тому, що він знаходиться в каталозі верхнього рівня
репозиторій, він буде схильний до випадкових перевірок від супроводжуючих, які вмикають
модулі, які вони хочуть використовувати. Таким чином, користувачам потрібно вручну скопіювати .ns3rc з
утиліти каталог у бажане місце (каталог верхнього рівня або домашній каталог).
дозволити постійну активацію прикладів і тестів.

Припускаючи, що ви на найвищому рівні нс-3 ви можете отримати копію .ns3rc
файл, який знаходиться в утиліти каталог таким чином:

$ cp utils/.ns3rc .

Файл .ns3rc тепер має бути на вашому верхньому рівні нс-3 каталог, і він містить
наступні:

#! /usr/bin/env пітон

# Список модулів, які будуть увімкнені під час запуску ns-3.
# Модулі, які залежать від перерахованих модулів, також будуть увімкнені.
#
# Усі модулі можна ввімкнути, вибравши 'all_modules'.
modules_enabled = ['усі_модулі']

# Встановіть значення true, якщо ви хочете, щоб приклади запускалися.
examples_enabled = False

# Встановіть значення true, якщо ви хочете, щоб тести запускалися.
tests_enabled = False

З верхнього рівня нс-3 каталог, ви можете створити нс-3 просто без будь-яких прикладів чи тестів
виконуючи:

$ ./waf configure
$ ./waf збірка

Запуск test.py зараз не призведе до виконання прикладів або тестів:

0 із 0 тестів пройдено (0 пройдено, 0 пропущено, 0 невдало, 0 збоїв, 0 помилок valgrind)

Якщо ви хочете будувати нс-3 з прикладами та тестами, використовуйте свій улюблений редактор для змін
значення у файлі .ns3rc для файлів examples_enabled і tests_enabled повинні мати значення True:

#! /usr/bin/env пітон

# Список модулів, які будуть увімкнені під час запуску ns-3.
# Модулі, які залежать від перерахованих модулів, також будуть увімкнені.
#
# Усі модулі можна ввімкнути, вибравши 'all_modules'.
modules_enabled = ['усі_модулі']

# Встановіть значення true, якщо ви хочете, щоб приклади запускалися.
examples_enabled = Правда

# Встановіть значення true, якщо ви хочете, щоб тести запускалися.
tests_enabled = Правда

З верхнього рівня нс-3 каталог, ви можете створити нс-3 з прикладами та тестами просто
робити:

$ ./waf configure
$ ./waf збірка

Запуск test.py призведе до виконання всіх прикладів і тестів:

170 із 170 тестів пройдено (170 пройдено, 0 пропущено, 0 невдало, 0 збоїв, 0 помилок valgrind)

Пошук і усунення несправностей
У цій главі міститься деяка інформація про можливі поширені помилки під час збирання або запуску
нс-3 програм.

Зверніть увагу, що вікі (http://www.nsnam.org/wiki/Troubleshooting), можливо, зробили свій внесок
предметів.

Будувати Помилки
Час виконання Помилки
Іноді після успішного збирання в програмі можуть виникати помилки. Це час виконання
помилки, які зазвичай можуть виникати, коли пам'ять пошкоджено або значення покажчика є неочікуваними
нуль.

Ось приклад того, що може статися:

$ ./waf --запустити TCP-точка-точка
Вхід до каталогу '/home/tomh/ns-3-nsc/build'
Компіляція успішно завершена
Команда ['/home/tomh/ns-3-nsc/build/debug/examples/tcp-point-to-point'] завершилася з кодом -11

У повідомленні про помилку сказано, що програма завершилася невдало, але це незрозуміло
з цієї інформації, що може бути не так. Щоб уважніше розглянути, спробуйте запустити його під
gdb відладчик:

$ ./waf --run tcp-point-to-point --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-point-to-point
Читання символів зі спільного об’єкта, зчитаного з цільової пам’яті... виконано.
Завантажена система надала DSO на 0xf5c000

Програма отримала сигнал SIGSEGV, помилка сегментації.
0x0804aa12 в основному (argc=1, argv=0xbfdfefa4)
на ../examples/tcp-point-to-point.cc:136
136 Ptr localSocket = socketFactory->CreateSocket ();
(gdb) p localSocket
$1 = {m_ptr = 0x3c5d65}
(gdb) p socketFactory
$2 = {m_ptr = 0x0}
(gdb) вийти
Програма запущена. Все одно вийти? (y або n) y

Спочатку зверніть увагу на те, як було викликано програму - передайте команду запуску як аргумент у
шаблон команди "gdb %s".

Це говорить нам, що була спроба розіменувати нульовий покажчик socketFactory.

Давайте розглянемо рядок 136 tcp-point-to-point, як пропонує gdb:

Ptr socketFactory = n2->GetObject (Tcp::iid);
Ptr localSocket = socketFactory->CreateSocket ();
localSocket->Bind ();

Виною цьому є те, що значення, яке повертає GetObject, не перевіряється, а може перевірятися
нуль.

Іноді вам може знадобитися скористатися валгринд пам'ять шашка для більш тонких помилок. знову
ви викликаєте використання valgrind аналогічно:

$ ./waf --run tcp-point-to-point --command-template="valgrind %s"

ДЖЕРЕЛО


Цей документ написаний на reStructuredText та цінності Сфінкс і підтримується в
док/посібник каталог вихідного коду ns-3.

Використовуйте ns-3-manual онлайн за допомогою сервісів onworks.net


Безкоштовні сервери та робочі станції

Завантажте програми для Windows і Linux

Команди Linux

Ad




×
реклама
❤️Робіть покупки, бронюйте або купуйте тут — безкоштовно, це допомагає зберегти послуги безкоштовними.