- PVSM.RU - https://www.pvsm.ru -
OMNeT++ (Objective Modular Network Testbed in C++) Discrete Event Simulator – это модульная, компонентно‑ориентированная [1] C++ библиотека и фреймворк для дискретно‑событийного моделирования, используемая прежде всего для создания симуляторов сетей. Попросту говоря это “симулятор дискретных событий”, включающий: IDE для создания моделей, и сам симулятор (GUI).
INET Framework – “библиотека” сетевых моделей [2] для OMNeT++.

Полная версия GIF (15.7 MiB) [3]
В предыдущих частях…
0. Автоматическое определение топологии сети и неуправляемые коммутаторы. Миссия невыполнима? [4] (+ classic Habrahabr UserCSS [5])
В этой части:
Note: дополнительная информация [6] для читателей хаба “Mesh-сети”.
{ объем изображений: 2.2+(2.1) MiB; текста: 484 KiB; смайликов: 22 шт. }
Note: [про используемую структуру разделов] структура разделов tutorial/how‑to обычно отличается от структуры разделов в справочнике: в справочнике – структура разделов позволяет за минимальное количество шагов дойти до искомой информации (сбалансированное дерево); в tutorial/how‑to, где разделы сильно связаны логически, а отдельный раздел, по сути, является одним из шагов в последовательности шагов, структура представляет собой иерархию закладок (якорей), которая позволяет в любом месте tutorial/how‑to напомнить (сослаться) о фрагменте описанном ранее.
Как хорошо, что в HTML5 появился тег <section>, с его помощью стало возможным напрямую задавать уровень вложенности раздела (при помощи манипуляции вложенностью тегов <section> друг в друга). Структуру текста теперь можно было явно отразить во вложенности (иерархии) тегов.
Это повлияло и на теги заголовков <h#>, т.к. теперь вложенность разделов определяется вложенностью тега <section>, то для указания названия раздела – достаточно было использовать всего лишь один тег <h1> в виде: “<section><h1>название раздела</h1>текст раздела</section>”.
Я этим пользовался уже давно (с самого появления <section>), но создавая эту статью, увидел еще одно достоинство использования <section>.
Хорошее название раздела должно точно отражать его суть, однако бывают случаи, когда нужно придержать (не раскрывать) суть до середины раздела. То есть, такой раздел должен вначале притворится “рутинным”, а в середине создать “wow/wtf‑эффект”. Логически это все – один раздел, но если раскрыть его название в самом начале раздела, то само название будет являться спойлером [7]. Представьте книгу (детектив), на обложке которой будет вся информация [8] о “убийце”.
Здесь “на сцену выходит” тег <section>. Он позволяет определить название раздела в любом месте внутри себя, т.е. не обязательно в самом начале. Пример: “<section>текст раздела<h1>название раздела</h1>продолжение текста раздела</section>”. Получается, мы можем одновременно сохранить логическую структуру текста, и показать название раздела в нужный момент. Можно даже сделать так, чтобы название раздела визуально появлялось в его начале, после того как читатель дойдет до определенного момента (до тега <h1> в html).
Вот только более чем за 9 лет существования <section>, браузеры так и не научились правильно строить “HTML5 document outline” [9] для обеспечения доступности [10].
Почему не научились? В документе со сложной структурой трудно* [11] определить, начиная с какого тега (section, article, …) следует начать нумерацию заголовков (h1, h2, h3, …). А теперь представьте, что сам документ размещен на странице подобной этой (с множеством дополнительных блоков, не имеющих отношение к самому документу, но имеющих заголовки), причем везде для заголовков используется h1. А если на одной странице не один документ, а несколько? Тем не менее, визуально все выглядит хорошо (пример документа [12]).
стандарте [13] все описано [14], но в реальности это не работает (объяснение см. ниже).
Почему визуально все выглядит хорошо? Здесь, благодаря стилям [15], появилась дополнительная информация – соответствие между иерархией section и уровнями заголовков (h#). Так может при построении “HTML5 document outline” следует воспользоваться информацией из CSS? Для этого потребуется добавить в CSS дополнительное свойство для элемента заголовка, указывающее его уровень, например:
body>section>h2 { heading-level: 1; font-size: 1.8em; }
body>section>section>h2 { heading-level: 2; font-size: 1.4em; }
body>section>section>section>h2 { heading-level: 3; font-size: 1.17em; }
body>section>section>section>section>h2 { heading-level: 4; font-size: 1em; }
body>section>section>section>section>section>h2 { heading-level: 5; font-size: 0.83em; }
Либо более строгий вариант – в одной секции допускается использовать только один заголовок. В этом случае уровень заголовка задает сама секция:
body>section { heading-level: 1; }
body>section>section { heading-level: 2; }
body>section>section>section { heading-level: 3; }
body>section>section>section>section { heading-level: 4; }
body>section>section>section>section>section { heading-level: 5; }
, и неважно, какой в итоге будет использоваться тег заголовка: h1 или h5.
Однако, если раньше для создания “heading-level outline [13]” достаточно было иметь только разметку (HTML), то теперь нужны еще и стили (CSS). Может можно ограничиться только разметкой (HTML)? Этим вопросом мы вплотную подошли к проблеме алгоритма построения “heading-level outline”, описанного в стандарте. Так вот, проблема не в самом алгоритме, а в том, что в качестве “sectioning root [14]” элемента может выступать только ограниченный (фиксированный) набор тегов. Но у людей часто возникают “нестандартные желания”: “я хочу, чтобы на моей странице со списком статей тег article являлся ‘sectioning root’ элементом”, “а я хочу, чтобы произвольная секция стала ‘sectioning root’ элементом”. Раньше им достаточно было для этого использовать несколько тегов h1 на одной странице (и они это делали). Так может сделать так, чтобы любая секция (теги: section, article, …) становилась “sectioning root” элементом, если заголовок в ней задан при помощи тега h1?..

НЛОприлетелоиоставилоэтотпробелздесь? Обратная сторона листочка из предыдущей статьи [17].
В начале определим, что нам нужно включить в протокол. На примере LLTR Basic.
Основа LLTR – это итерации сбора статистики на множестве хостов во время сканирования сети. Итераций в LLTR много ( >1), поэтому первое, что нужно включить в протокол – управление запуском и остановкой каждой итерации. Если учесть, что хостов тоже много ( >1), то управление будет заключаться в том, чтобы определенным способом сообщать всем хостам время начала итерации и время окончания итерации. То есть синхронизировать все хосты.
В каждой итерации есть свой unicast src хост и unicast dst хост, поэтому следующее, что нужно включить – способ назначения для каждой итерации unicast src и dst. То есть в каждой итерации один из хостов должен “осознавать” себя unicast src хостом, цель которого посылать трафик на unicast dst хост.
И последнее. По завершению всех итераций, всю собранную статистику со всех хостов нужно отправить на один хост для обработки. Этот хост проанализирует собранную статистику, и построит топологию сети.
Также, на этом шаге, можно подумать про некоторые детали реализации (ограничения) протокола. Например, мы хотим, чтобы программа, использующая LLTR, смогла работать без root прав, и из пространства пользователя (т.е. без установки в систему специального драйвера), значит, LLTR должен работать, например, поверх TCP и UDP.
Все остальные делали реализации, определятся сами, в процессе создания модели. То есть, конечно, можно сразу же продумать все до мелочей, но при этом есть риск “скатится в локальный оптимум”, и не заметить “более лучший” вариант реализации. Хорошо, когда моделей будет несколько – если для каждого варианта реализации будет своя модель, то появится возможность комбинировать модели, и шаг за шагом приходить к лучшей реализации. Вспоминая генетический алгоритм ;). Например, в одной реализации/модели может быть централизованное управление, в другой – децентрализованное, в третей – комбинация лучших частей из предыдущих двух вариантов.
Теперь настало время определится с симулятором сети, в котором будем создавать модели и ставить эксперименты.
В основном, от симулятора сети нам нужна возможность реализации “своего” протокола. Не все симуляторы позволяют легко это сделать.
А вот присутствие эмуляторов ОС реального сетевого оборудования “мировых брендов”, наоборот – не нужно. Скорее всего, эмуляторы создадут множество ограничений, которые будут только мешать в ходе экспериментов.
С выбором симулятора мне помогла статья Evaluating Network Simulation Tools [20] (наши требования к симулятору во многом совпадали) и OMNeT++ General 'Network' Simulation [21].
Загружаем OMNeT++ [23] 5.0 [24].
И так как OMNeT++ – это всего лишь “симулятор дискретных событий”, то понадобится еще и INET [2] – библиотека сетевых моделей (протоколы и устройства). Качаем INET [25] 3.4.0 [26]. На самом деле его можно было установить из IDE [27], но я рекомендую поставить вручную (позже будет ясно почему).
Установка в *nix и в Windows мало чем отличается. Продолжу на примере Windows.
Распаковываем OMNeT++ в %ProgramData% (C:ProgramData), и открываем файл INSTALL.txt (C:ProgramDataomnetpp-5.0INSTALL.txt). В нем сказано, что подробная инструкция находится в “doc/InstallGuide.pdf”, дальше написано, что если не хотите ее читать, то просто выполните:
$. setenv
$ ./configure
$ make
Но не спешите это делать!
Во‑первых, обратите внимание на первую команду “. setenv”. В директории “omnetpp-5.0” нет файла “setenv” (в версии 5.0b1 он был). Он и не нужен (для Windows), поэтому просто запускаем “mingwenv.bat” (советую перед запуском посмотреть, что он делает… во избежание [28] внезапного rm [29] ). По окончании отколется терминал (mintty).
Во‑вторых, советую немного подправить файл “configure.user” (если упомянутый параметр закомментирован в файле, то его нужно раскомментировать):
PREFER_CLANG=yesCFLAGS_RELEASE='-O2 -march=native -DNDEBUG=1'PREFER_CLANG=noCFLAGS_RELEASE='-O2 -mfpmath=sse,387 -ffast-math -fpredictive-commoning -ftree-vectorize -march=native -freorder-blocks-and-partition -pipe -DNDEBUG=1'CFLAGS_RELEASE='-O2 -fpredictive-commoning -march=native -freorder-blocks-and-partition -pipe -DNDEBUG=1'CFLAGS_RELEASE='-O2 -march=native -freorder-blocks-and-partition -pipe -DNDEBUG=1'-std=c++11 '+CFLAGS_RELEASE. Например:CXXFLAGS='-std=c++11 -O2 -fpredictive-commoning -march=native -freorder-blocks-and-partition -pipe -DNDEBUG=1'JAVA_CFLAGS=-fno-strict-aliasingPREFER_QTENV=yesWITH_OSG=noWITH_PARSIM=yesЕсли его явно не использовать, то он не нужен (в теории). Подробнее в разделе 16.1, 16.3, и 16.3.2 “Parallel Simulation Example” в “doc/InstallGuide.pdf”, или тут [31].
Теперь в терминале (mintty) можно выполнить:
./configure && make clean MODE=release
make MODE=release –j17
Note: “17” следует заменить на количество ядер CPU + 1, либо на 1.5×ядер.
В директории “tools/win32” находится MSYS2 [32] его пакеты компиляторов можно обновлять:
А OMNeT++ можно собрать под 64bit [39].
Но OMNeT++ может просто не собраться более новой версией GCC (так было с первой бэткой пятой версии OMNeT++ – без правки исходников она нормально собиралась только с GCC 4.x). А для перехода на 64bit потребуется еще больше усилий. Для начала потребуется пересмотреть опции компиляции (fPIC [40], не нужен? [41]). Затем, если пролистаете исходники OMNeT++, то увидите, что там часто используется тип long вместо int32_t, size_t и ptrdiff_t (а также uintptr_t и intptr_t) [42]. Чем это грозит? В *nix в 64bit (LP64) сборке размер long будет 64bit, а в Windows (LLP64) – 32bit (см. модели данных [43]). Придется заменять long на size_t и ptrdiff_t, но и здесь вас будут поджидать “подводные камни”. Например, можно открыть “src/utils/opp_lcg32_seedtool.cc”, и взглянуть на строку 231 – index либо можно оставить 32bit (заменить на int32_t), либо сделать 64bit и модифицировать все битовые_маски+описания+(возможно)немного_логики. Поэтому часть long переменных нужно будет оставить 32bit, а другую часть сделать 64bit. В общем, для корректной работы, нужно проделать все пункты из:
Причем то же самое надо проделать и с многочисленными библиотеками для OMNeT++, например, с INET.
В общем, предостерегаю от попыток сделать 64bit сборку OMNeT++.
Под *nix я также рекомендую использовать 32bit сборку (по крайне мере с версией 5.0 и меньше).
Возможно, когда‑нибудь Andrey2008 [47] возьмется проверить код OMNeT++ и INET… А пока предлагаю просто найти и просмотреть все “FIXME”/“Fix” в коде ;).
P.S. упоминания о том, что код OMNeT++ проверяли статическим анализатором кода – отсутствуют, а вот в файлах “ChangeLog” INET 3.4.0 можно найти 70 упоминаний про устранение дефектов после сканирования в Coverity.
OMNeT++ использует Eclipse в качестве IDE. Для удобства можно создать ярлык на IDE “%ProgramData%omnetpp-5.0ideomnetpp.exe”, и расположить его в легкодоступном месте. В директории “ide/jre/” находится JRE v1.8.0_66-b18. Если в системе уже установлен совместимый JRE/JDK, то директорию “ide/jre/” можно спокойно удалить, заменив символьной ссылкой [48] на местоположение системного JRE.
При первом запуске Eclipse предлагает поместить workspace в директорию “samples”, однако лучше расположить ее в любой другой удобной вам директории вне “%ProgramData%”. Главное, чтобы в пути к новой директории использовались только латинские буквы (+ символы), и не было пробелов.
После закрытия Welcome, IDE предложит установить INET (как было написано выше), и импортировать примеры – откажитесь от обоих пунктов.
Опции JVM. Добавить в файл “ide/omnetpp.ini” (для правки подойдет любой редактор, понимающий LF перевод строки; notepad не подойдет), сохранив пустую последнюю строку:
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC
-XX:+AggressiveOpts
-XX:+TieredCompilation
-XX:CompileThreshold=100
![LLTR Часть 1: Первые шаги в OMNeT++ и INET - 4 Eclipse tuning (un[7z]me)](http://www.pvsm.ru/images/2018/08/16/LLTR-chast-1-pervye-shagi-v-OMNeT-i-INET-4.png)
Чтобы сделать Eclipse, таким как на картинке – загляни внутрь картинки.
Настало время установить INET. Директорию “inet” из скаченного ранее архива (inet-3.4.0-src.tgz) нужно перенести в workspace. В директории есть файл “INSTALL” с пошаговым описанием установки. Можно воспользоваться им (раздел “If you are using the IDE”), но только не собирайте (Build) проект!
Импортируем INET:
Настроим проект:
#include” (случается, если несколько раз менять “Current builder”; может случиться и в других случаях).
Перед настройкой {A} надо подправить один из файлов проекта. В файле “inet/.oppfeatures” есть строка “inet.examples.visualization” нужно добавить после нее пустую строку, в которой написать “inet.tutorials.visualization”, желательно сохранив отступ слева (по аналогии с другими параметрами “nedPackages” в файле). Если это не сделать, то ничего страшного не случится, просто после настройки в “Problems” (Alt+Shift+Q,X) будут всегда висеть ошибки, связанные с “inet.tutorials.visualization”. Можно вначале сделать {A}, и посмотреть на ошибки, а затем подправить файл “inet/.oppfeatures” – при этом Eclipse предупредит о нарушении целостности в настройках, и предложит профиксить их (соглашаемся на это).
Приступим (панель “Project Explorer” > проект “inet” > контекстное меню > Properties):
make MODE=release CONFIGNAME=${ConfigName} -j17” (“17” заменить на предыдущее значение в строке, т.е. на выбранный N) {E}, то же самое можно сделать и для конфигурации “gcc-debug”, заменив в строке “MODE=release” на “MODE=debug”, после этого не забудь переключиться обратно на “gcc-release [ Active ]”.../src” с выбранными “Add to all configurations” и “Add to all languages” {G} – изначально “../src” есть в языке “GNU C++”, но, в неопределенный момент, он может стереться из списка;../src” появилось во всех языках и конфигурациях.__cplusplus” со значением “201103L” и выбранными “Add to all configurations” и “Add to all languages” – {F} подробнее [51];__cplusplus” значение “201103L”./inet/src” {G}, если там что‑то другое (например, просто “/inet”), то удаляй то, что есть и добавь (“Add Folder…”) “/inet/src”. Затем кнопка “Apply”, и возвращение к {A}, т.к. все фильтры при удалении были стерты. Кстати, “/inet” на самом деле можно оставить – с ним тоже все нормально собирается, но лучше сузить до оригинального “/inet/src”.-std=c++11 ” перед “${FLAGS}” в “Command to get compiler specs”, должно получится примерно так `${COMMAND} -std=c++11 ${FLAGS} -E -P -v -dD "${INPUTS}"` {F}, подробнее здесь [52] и здесь [53];__cplusplus”; не меняем порядок, удаляем все упоминания “__cplusplus” из “CDT Managed Build System Entries”, и следим, чтобы он там не появлялся в будущем);__cplusplus=201103L” (она будет ближе к концу).
Некоторые проблемы могут возникнуть с {E}. Поясню. Если все нормально, то Eclipse должен подхватить [55] те настройки, которые были заданы в “configure.user” перед конфигурированием OMNeT++ (./configure). В таком случае Eclipse передаст нужные параметры в g++ через make. Однако не всегда все идет, как планировалось, и лучше проверить, что происходит в реальности. Проверить можно, дописав в “Build command” {E} “--just-print [56]” или “--trace [57]”, и, запустив сборку (панель “Project Explorer” > проект “inet” > контекстное меню > “Clean Project” и “Build Project”), открыть “Console” (Alt+Shift+Q,C), в нем должно выводится что‑то похожее на “g++ -c -std=c++11 -O2 -fpredictive-commoning -march=native -freorder-blocks-and-partition -pipe -DNDEBUG=1 …”. Если этого нет, то можно последовать совету из уже упомянутой статьи [55].
Опять открываем настройки проекта (панель “Project Explorer” > проект “inet” > контекстное меню > Properties):
CFLAGS”, тип “String”, значение “-O2 -fpredictive-commoning -march=native -freorder-blocks-and-partition -pipe”;CXXFLAGS”, тип “String”, значение “-std=c++11 -O2 -fpredictive-commoning -march=native -freorder-blocks-and-partition -pipe”;CFLAGS”, значение “${CFLAGS}”;CXXFLAGS”, значение “${CXXFLAGS}”;
Кстати, при некоторой сноровке, параметры запуска g++ можно было посмотреть, не используя флаги “--just-print [56]” и “--trace [57]”, а используя Process Explorer [58]. В Process Explorer также можно посмотреть, во что раскрывается “-march=native” при передаче в “cc1plus.exe”.
Теперь, наконец, можно собрать INET! Проверьте, что сейчас активна конфигурация “gcc-release” {B}, и если добавляли ранее флаги “--just-print [56]” или “--trace [57]” для проверки {E}, то их нужно убрать. Собираем (панель “Project Explorer” > проект “inet” > контекстное меню > “Clean Project” и “Build Project”), за процессом можно наблюдать в “Console” (Alt+Shift+Q,C).
Если все прошло хорошо, то рекомендую закрыть Eclipse, и сделать бекап файла “.cproject” и директории “.settings” с настройками проекта {B-G}, а также файлов: “.oppfeatures”, “.oppfeaturestate”, “.nedexclusions” – {A}.
Наконец, настройка завершена, и можно перейти к самому интересному.
Note: Первое, что я сделал после настройки окружения – стал изучать содержимое директории “doc” у OMNeT++ и INET. Это были Simulation Manual и User Guide, позже к ним присоединился Stack Overflow (в виде stackoverflow.com, и в виде состояния ). Ниже я покажу, как можно сделать первые шаги, не читая всю документацию, и расскажу, с какими “особенностями” можно столкнуться.
Note: Для тех, кто еще не успел установить себе OMNeT++ и INET, но уже хочет посмотреть на код, текст ниже содержит ссылки на исходники INET в GitHub. Все ссылки ведут на исходники версии 3.4.0 (эти ссылки будут доступны всегда, даже если в будущих версиях расположение файлов в INET изменится).
Перед созданием своего проекта хорошо бы посмотреть на уже готовые модели в INET, посмотреть, как они устроены. Может в нем уже реализовано то, что нам нужно?
После непродолжительного блуждания по дереву INET в “Project Explorer”, можно наткнуться на директорию “inet/src/inet/applications”, и обнаружить в ней “udpapp [61]” (UDP Application). UDP пригодится нам для broadcast рассылки. Внутри директории лежат несколько моделей, и, судя по названию и размеру исходников, самый простой из них, это “UDPEchoApp [62]”. Там есть еще и “UDPBasicApp”, но он оказался [63] не таким уж и “Basic”. Каждая модель состоит из “.cc”, “.h” и “.ned” файлов. Пока не ясно, зачем нужны “.ned” файлы, но судя по их содержанию (наличию строчки “parameters:” [64]) в них могут описываться параметры модели.
Продолжим поиски интересных моделей. Посмотрим, какие примеры (inet/examples [65]) есть в INET. И нам повезло, в нем есть пример с названием “broadcast” (inet/examples/inet/broadcast [66])! Этот пример помимо файлов “.cc”, “.h” и “.ned”, содержит еще “.ini” и “.xml” файлы. Пора разобраться, зачем эти файлы нужны:
К сожалению, этот пример (“broadcast”) нам не подойдет, т.к. в его сеть включены маршрутизаторы [78]. Однако, по аналогии с ним, можно создать свой проект.
Simulation Manual [79]. Как видите, он достаточно большой, браузеру требуется время (и RAM) для его открытия. Для решения этой проблемы я сделал небольшой JS [80]‑bookmark [81]let [82]. После его [83] запуска все ссылки, ведущие на разделы Simulation Manual, перестанут плодить вкладки (пожирая ресурсы), и начнут переключать разделы в одной единственной дополнительной вкладке (на самом деле он просто прописывает target для каждой ссылки на Simulation Manual). Bookmarklet расположен в первом комментарии [83] к этой статье. И, для того, чтобы отличить ссылки на Simulation Manual от остальных ссылок, bookmarklet изменяет их цвет.
При повторном открытии статьи bookmarklet придется запускать заново. На Хабре авторы статей могут в любой момент изменить содержимое статьи. Содержимое комментария можно изменить только в течение первых 5-и минут. При первом запуске bookmarklet вы наверняка проверили, что он делает.
⇒ запускать bookmarklet из тела статьи потенциально не безопасно – они могут в любой момент изменится; если же bookmarklet размещен в комментарии, то достаточно проверить его всего один раз (по истечении 5-и минут с момента публикации комментария) – в будущем он не изменится.
Пустой проект “LLTR”, с директориями “src” и “simulations”, и единственной конфигурацией “gcc-release” (File → New → OMNeT++ Project…):

Осталось настроить проект также как и “inet”, и можно будет двигаться дальше. В основном, настройка будет отличаться отсутствием необходимости настраивать “gcc-debug” (т.к. он отсутствует в “LLTR”), и добавлением в зависимости “inet”. Более конкретно: вместо {A,B,G} надо открыть раздел “Project References”, и включить зависимость от “inet”.
Если посмотрите на файлы, которые создал Wizard, то увидите, что файл “package.ned” встречается дважды: в директории “src”, и в “simulations”. Содержимое тоже отличается – “package lltr;” и “package lltr.simulations;” соответственно. Один из этих файлов нам не понадобится.
Если провести аналогию со структурой проекта INET, то директория “inet/src” – это “LLTR/src”, а “inet/examples” – это “LLTR/simulations”. То есть в “LLTR/simulations” лучше размещать файлы “.ned” c Network [68], а в “LLTR/src” – составные части сети (модули).
Существует еще один нюанс – в INET очень хорошая внутренняя структура директорий, и если в будущем нам потребуется изменить один из стандартных модулей в INET, то лучше будет создать новый модуль, и положить его рядом с оригиналом в INET. То же самое можно применить и к модулю, созданному с нуля – найти ему подходящее место в INET.
В свете вышеописанного, “.ned” в директории “LLTR/src” нам не нужен (все будет в “inet/src”), также как и не нужен дополнительный подпакет “package lltr.simulations;” в “LLTR/simulations”. Поэтому переносим “package.ned” из “LLTR/src” в “LLTR/simulations”.
Попробуйте запустить LLTR. Для этого достаточно открыть файл “LLTR/simulations/omnetpp.ini”, и нажать (Run > Run As > 1 OMNeT++ Simulation):

При этом Eclipse предложит создать новую конфигурацию “simulations” для запуска симулятора. Соглашаемся, и сразу же сталкиваемся с проблемой: “LLTR/src/LLTR.exe” не был найден. Все верно, ведь “LLTR.exe” никто не собирал, поэтому вначале собираем проект (меню Project → Build Project), а затем опять запускаем симулятор (тем же самым способом).
После запуска симулятора появилось предупреждение “No network specified in the configuration.”, его можно исправить, добавив строку “network = lltr.Network” в секцию “[General]” файла “omnetpp.ini”, и добавив строку “network Network {}” в конец файла “package.ned”. Этим мы создали пустую сеть (в “.ned” файле), и настроили (в “.ini” файле) симулятор на загрузку этой сети (Network – имя сети) при запуске.
Теперь можно попробовать опять запустить симулятор (Run > Run As > 1 OMNeT++ Simulation), и вместо ошибки должно открыться серое поле (прямоугольник) сети Network на зеленом фоне.
Note: Есть различие между запуском через (Run > Run As > 1 OMNeT++ Simulation), и через (Run > 1 simulations): в первом случае запуск проходит быстрее, т.к. во втором случае, перед запуском симулятора, Eclipse начинает собирать проект.
тег a1_v0.1.0 [87] (“a” – article) “git checkout -b ‹my_branch› tags/a1_v0.1.0 [88]”)
[87]
Репозиторий я создавал таким образом, чтобы:
Note: без веток “article_#” можно было бы обойтись, и указывать, при клонировании, название последнего тега части (которое еще надо найти), но с веткой проще/быстрее.
Как забрать репозиторий “к себе”? Лучше всего, вначале его форкнуть на GitHub [90], а затем свой форк:
git clone”;git clone --branch ‹article_#› --single-branch [91]” (без использования “--depth [92]”), а для получения коммитов следующей части использовать “git remote set-branches –add [93]” (и если что‑то пойдет не так… [94])
Далее, для создания личной ветки на основе конкретного тега, можно использовать “git checkout -b ‹my_branch› tags/‹tag_name› [88]”.
Как создавать свою версию кода, т.е. изменять код? Если в будущем не возникнет желания сделать Pull Request, то ничего вам не мешает делать с форком что хотите >:-), однако я советую, при появлении изменений, которые хочется сохранить, делать так):

Одинаковая схема наименования тегов поможет в будущем избежать коллизий, даже не смотря на то, что теги при Pull Request не переносятся [95].
Note: Если я в будущем буду вносить изменения в репозиторий, то я поступлю также: оригинальный код сохранится, а измененный будет идти параллельно оригинальному (с “накатанными” всеми изменениями из остальных (будущих) тегов, и с новыми именами тегов). Только вместо добавления “-u” к именам новых тегов тегам, я буду увеличивать номер. Например, теги оригинального кода “a1_v0.1.0”, “a1_v0.2.0”, … – теги измененного кода “a1_v0.1.1”, “a1_v0.2.1”, … При следующем изменении, номер еще раз увеличится: “a1_v0.1.2”, “a1_v0.2.2”, …
Note: в tutorial все места, завершающие очередной “шажок”, помечены значком git
, и рядом с ним будет ссылка на соответствующий git tag.
Note: git diff использовался стандартный, патчи генерировались автоматически, и они редко будут показывать логической связи в произошедших изменениях (в частности, при добавлении нового кода и изменении уровня вложенности / форматирования существующего кода) (здесь бы пригодилось отслеживание изменений на уровне AST [96]), похожее на этот проект для Java [97].
Откроем “package.ned” в режиме графического редактирования схемы (вкладка “Design” снизу), и попробуем набросать сеть из КДПВ [100]:

Сеть построена из тех же модулей, которые были использованы в примере broadcast [101]:
А вот в качестве “провода” (канала связи) выбран Eth100M (скорость: 100 Mbps; длина: 10 метров). Кстати, почему именно 10 метров, где они задаются, и можно ли поменять это значение? (ответ чуть ниже)
увидеть примерно это (git tag a1_v0.2.0) [102]
[103]. Пояснение структуры:
package ‹<a href="https://omnetpp.org/doc/omnetpp/manual/#sec:ned-ref:packages">имя пакета</a>›; //<a href="https://omnetpp.org/doc/omnetpp/manual/#sec:ned-ref:directory-structure">особенности наименования</a>
import ‹<a href="https://omnetpp.org/doc/omnetpp/manual/#sec:ned-lang:imports-and-name-resolution">имя подключаемого пакета</a>›;
network ‹<a href="https://omnetpp.org/doc/omnetpp/manual/#sec:ned-lang:warmup:network">название описываемой сети</a>›
{
@display(‹визуальные параметры сети, например, размер области›);
<a href="https://omnetpp.org/doc/omnetpp/manual/#sec:ned-ref:submodules">submodules</a>:
‹<a href="https://omnetpp.org/doc/omnetpp/manual/#sec:ned-lang:submodules">название узла</a>›: ‹тип узла› { @display(‹визуальные параметры узла, например, местоположение›); }
<a href="https://omnetpp.org/doc/omnetpp/manual/#sec:ned-ref:connections">connections</a>:
‹название узла›.‹<a href="https://omnetpp.org/doc/omnetpp/manual/#sec:ned-lang:gates">точка соединения</a>› <--> ‹тип канала связи› <--> ‹название узла›.‹точка соединения›;
}
Warning: К сожалению Хабр пока не поддерживает вставку ссылок при помощи тега <a>...</a> – вместо ссылок сейчас в код “вставляются” сами теги. И так происходит не только с этим блоком кода, но и со всеми ниже, в которых использовалась вставка ссылок, либо выделение частей кода при помощи тегов (<strong>...</strong>, <em>...</em>).
package ‹имя пакета [104]›; //особенности наименования [105]
import ‹имя подключаемого пакета [106]›;
network ‹название описываемой сети [68]›
{
@display(‹визуальные параметры сети, например, размер области›);
submodules [107]:
‹название узла [108]›: ‹тип узла› { @display(‹визуальные параметры узла, например, местоположение›); }
connections [109]:
‹название узла›.‹точка соединения [110]› <--> ‹тип канала связи› <--> ‹название узла›.‹точка соединения›;
}
Отдельно стоит сказать про “точки соединения” (Gates) и каналы связи [111]:
‹название узла›.‹gate›[‹номер›]”, либо автоматически – инкрементально [109] “‹название узла›.‹gate›++”.… <--> { delay = 100ms; } <--> …”), либо могут иметь имя/тип [114], на которое можно ссылаться [115] (как в примере broadcast [116]: “… <--> C <--> …”), либо могут иметь тип и быть переопределены на месте [117] (например: “… <--> FastEthernet {per = 1e-6;} <--> …”), либо… [118]output / input; соединители при подключении: --> / <--), и двунаправленными [119] (тип при объявлении: inout; соединитель при подключении: <--> ). Двунаправленные состоят из двух однонаправленных, к которым можно обратиться напрямую, дописав суффикс “$i” либо “$o” [120].Warning: К сожалению парсер Хабра пока смог обработать только 1⁄3 публикации за отведенные ему 20 секунд (приходит ошибка 504 “Gateway Time-out”). Но даже эти 1⁄3 позволили обнаружить еще один баг в парсере. Небольшой пример (исходная разметка):
Выполните в точности эту <a href="#set">команду: “<code>set: p=1.87548</code>”</a> в терминале своего портативного ядерного реактора.
После парсера:
Выполните в точности эту <a href="#set"><code>команду: “set: p=1.87548</code>”</a> в терминале своего портативного ядерного реактора.
Увидеть этот баг в действии можно, взглянув на конец 3‑го пункта в списке выше. Его оригинальная разметка выглядела так:
можно обратиться напрямую, <a href="https://omnetpp.org/doc/omnetpp/manual/#sec:ned-ref:inout-gates">дописав суффикс “<strong><code>$i</code></strong>” либо “<strong><code>$o</code></strong>”</a>.
Хорошая новость в том, что парсер [121] сейчас переписывают [122]. И, чтобы не ждать окончания этого процесса, я разместил полную версию публикации на GitHub Pages:
Note: В полной версии я упростил активацию target у ссылок на Simulation Manual – вместо запуска bookmarklet'а, достаточно нажать на кнопку здесь [124]. К тому же при открытии полной версии через кнопку «Читать дальше →», активация произойдет автоматически.
Note: Разметка, CSS и JS этой страницы могут показаться странными – все дело в том, что процесс подготовки публикации у меня разбит на 3 этапа, и в GitHub Pages находится немного измененный результат 2‑го этапа (обычный HTML, пригодный для просмотра в браузере, и, при этом, максимально близкий к хабра‑разметке). 3‑й этап – это модификация разметки под Хабр.
Небольшой опрос. Первый вопрос поможет мне лучше определить время для публикации следующей части. Второй – улучшить статью. Остальные вопросы – чистое любопытство.
Автор: ZiroKyl
Источник [128]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/qt-2/289379
Ссылки в тексте:
[1] компонентно‑ориентированная: https://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BC%D0%BF%D0%BE%D0%BD%D0%B5%D0%BD%D1%82%D0%BD%D0%BE-%D0%BE%D1%80%D0%B8%D0%B5%D0%BD%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D0%BE%D0%B5_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5?stable=1
[2] “библиотека” сетевых моделей: https://inet.omnetpp.org/Introduction.html
[3] Полная версия GIF (15.7 MiB): https://hsto.org/getpro/habr/post_images/a8b/399/99a/a8b39999a18513692acc46bd4ee80209.gif#splash.gif
[4] Автоматическое определение топологии сети и неуправляемые коммутаторы. Миссия невыполнима?: https://habr.com/post/414799/
[5] classic Habrahabr UserCSS: https://habr.com/post/414799/#user-css
[6] дополнительная информация: https://habr.com/post/414799/#comment_18833769
[7] спойлером: https://ru.wikipedia.org/wiki/%D0%A1%D0%BF%D0%BE%D0%B9%D0%BB%D0%B5%D1%80_(%D1%85%D1%83%D0%B4%D0%BE%D0%B6%D0%B5%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D1%8B%D0%B5_%D0%BF%D1%80%D0%BE%D0%B8%D0%B7%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D1%8F)?stable=1
[8] вся информация: https://ru.wiktionary.org/wiki/%D1%81%D0%BF%D0%BE%D0%B9%D0%BB%D0%B5%D1%80#%D0%97%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B5
[9] не научились правильно строить “HTML5 document outline”: http://html5doctor.com/computer-says-no-to-html5-document-outline/
[10] обеспечения доступности: https://www.w3.org/TR/WCAG20-TECHS/H42.html#H42-description
[11] *: #html5-section-h_footnote-difficult
[12] пример документа: http://zirokyl.github.io/DFD2015-TeHI/TeHI-PoC/
[13] стандарте: https://www.w3.org/TR/html5/sections.html#outline
[14] описано: https://www.w3.org/TR/html5/sections.html#sectioning-roots
[15] стилям: https://github.com/ZiroKyl/DFD2015-TeHI/blob/695d699dfe3f4fce11945d6047b9c417ca670ad2/TeHI-PoC/css/main.css#L51-L55
[16] #: #pervye-shagi-pered-modelirovaniem--mozgovoy-shturm
[17] листочка из предыдущей статьи: https://habr.com/post/414799/#fig_sticker2
[18] #: #detalizaciya-protokola
[19] #: #vybor-simulyatora-seti
[20] Evaluating Network Simulation Tools: http://www.finmars.co.uk/blog/4-evaluating-network-simulation-tools
[21] OMNeT++ General 'Network' Simulation: http://www.finmars.co.uk/blog/8-omnet-general-network-simulation
[22] #: #ustanovka-omnet-i-inet
[23] Загружаем OMNeT++: https://omnetpp.org/omnetpp
[24] 5.0: https://omnetpp.org/component/jdownloads/download/32-release-older-versions/2307-omnetpp-50-windows
[25] Качаем INET: https://inet.omnetpp.org/Download.html
[26] 3.4.0: https://github.com/inet-framework/inet/releases/tag/v3.4.0
[27] установить из IDE: https://inet.omnetpp.org/Installation.html
[28] во избежание: https://habrahabr.ru/post/204580
[29] внезапного rm: http://www.opennet.ru/opennews/art.shtml?num=41897
[30] красивая: https://omnetpp.org/21-articles/3737-3ddemo
[31] тут: https://omnetpp.org/doc/omnetpp/manual/#sec:parallel-exec:parallel-simulation-example
[32] MSYS2: http://www.linux.org.ru/forum/desktop/10819573
[33] msys2.github.io: http://msys2.github.io
[34] sourceforge.net/p/msys2/wiki/MSYS2 installation: https://web.archive.org/web/20161011161459/https://sourceforge.net/p/msys2/wiki/MSYS2%20installation
[35] sourceforge.net/p/msys2/wiki/MSYS2 re-installation: https://web.archive.org/web/20151108111604/https://sourceforge.net/p/msys2/wiki/MSYS2%20re-installation/
[36] sourceforge.net/p/msys2/wiki/Contributing to MSYS2: https://web.archive.org/web/20151128115031/http://sourceforge.net:80/p/msys2/wiki/Contributing%20to%20MSYS2/
[37] wiki.archlinux.org/index.php/Downgrading_packages: https://wiki.archlinux.org/index.php/Downgrading_packages
[38] sourceforge.net/projects/msys2/files/REPOS/MSYS2/x86_64/: https://sourceforge.net/projects/msys2/files/REPOS/MSYS2/x86_64/
[39] собрать под 64bit: http://stackoverflow.com/questions/16888270/omnet-4-3-build-issue-on-mac-os-x-lion
[40] fPIC: https://github.com/michaelkirsche/6lowpan4omnet-diy/blob/master/1_contiki_platform_omnet/contiki-2.6/platform/omnetpp/Makefile.omnetpp#L36
[41] не нужен?: http://www.cyberforum.ru/cpp-beginners/thread1506530.html
[42] size_t и ptrdiff_t (а также uintptr_t и intptr_t): http://www.viva64.com/ru/t/0030/
[43] модели данных: http://www.viva64.com/ru/a/0050/#ID0EOB
[44] 7 шагов по переносу программы на 64-битную систему: http://www.viva64.com/ru/a/0042/
[45] Коллекция примеров 64-битных ошибок в реальных программах: https://habrahabr.ru/company/pvs-studio/blog/97751/
[46] 20 ловушек переноса Си++ – кода на 64-битную платформу: http://www.viva64.com/ru/a/0004/
[47] Andrey2008: https://habr.com/users/andrey2008/
[48] символьной ссылкой: https://ru.wikipedia.org/wiki/%D0%A1%D0%B8%D0%BC%D0%B2%D0%BE%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F_%D1%81%D1%81%D1%8B%D0%BB%D0%BA%D0%B0?stable=1
[49] включим параллельную компиляцию: http://www.gnu.org/software/make/manual/make.html#Parallel
[50] использовать все ядра CPU для компиляции: http://stackoverflow.com/a/414725
[51] подробнее: http://stackoverflow.com/questions/13591020/eclipse-cdt-parser-support-for-c11/24628502#24628502
[52] здесь: https://www.eclipse.org/forums/index.php?t=msg&th=490066&goto=1068001&#msg_1068001
[53] здесь: http://stackoverflow.com/questions/9131763/eclipse-cdt-c11-c0x-support/24561615#24561615
[54] подробнее: http://www.linux.org.ru/forum/development/9680812#comment-9684038
[55] должен подхватить: http://adamcavendish.is-programmer.com/posts/42316.html
[56] --just-print: http://www.gnu.org/software/make/manual/make.html#index-printing-of-recipes
[57] --trace: http://www.gnu.org/software/make/manual/make.html#index-_002d_002dtrace
[58] Process Explorer: https://technet.microsoft.com/ru-ru/bb896653.aspx
[59] #: #sozdanie-pervogo-proekta
[60] мозга: http://www.braintools.ru
[61] udpapp: https://github.com/inet-framework/inet/tree/v3.4.0/src/inet/applications/udpapp
[62] UDPEchoApp: https://github.com/inet-framework/inet/blob/v3.4.0/src/inet/applications/udpapp/UDPEchoApp.cc
[63] оказался: https://github.com/inet-framework/inet/blob/v3.4.0/src/inet/applications/udpapp/UDPBasicApp.cc
[64] строчки “parameters:”: https://github.com/inet-framework/inet/blob/v3.4.0/src/inet/applications/udpapp/UDPEchoApp.ned#L31
[65] inet/examples: https://github.com/inet-framework/inet/tree/v3.4.0/examples
[66] inet/examples/inet/broadcast: https://github.com/inet-framework/inet/tree/v3.4.0/examples/inet/broadcast
[67] файл/язык: https://omnetpp.org/doc/omnetpp/manual/#cha:ned-lang
[68] Network: https://omnetpp.org/doc/omnetpp/manual/#sec:ned-lang:warmup:network
[69] Simple modules: https://omnetpp.org/doc/omnetpp/manual/#sec:ned-lang:warmup:the-simple-modules
[70] Compound module: https://omnetpp.org/doc/omnetpp/manual/#sec:warmup:ned-lang:node-compound-module
[71] так: https://omnetpp.org/doc/omnetpp/manual/#sec:overview:modeling-concepts
[72] файл: https://omnetpp.org/doc/omnetpp/manual/#sec:overview:parameters
[73] задать/переопределить: https://omnetpp.org/doc/omnetpp/manual/#sec:config-sim:config-file
[74] Named Configurations: https://omnetpp.org/doc/omnetpp/manual/#sec:config-sim:named-configurations
[75] просто файл: https://omnetpp.org/doc/omnetpp/manual/#sec:ned-lang:xml-parameters
[76] настройками: https://github.com/inet-framework/inet/blob/v3.4.0/examples/inet/broadcast/UDPBroadcastNetwork.ned#L39
[77] IPv4NetworkConfigurator: https://github.com/inet-framework/inet/blob/v3.4.0/examples/inet/broadcast/UDPBroadcastNetwork.ned#L37
[78] включены маршрутизаторы: https://github.com/inet-framework/inet/blob/v3.4.0/examples/inet/broadcast/UDPBroadcastNetwork.ned#L29-L36
[79] Simulation Manual: https://omnetpp.org/doc/omnetpp/manual/
[80] JS: http://javascript.ru/unsorted/bookmarklet
[81] bookmark: http://habrahabr.ru/post/52346/
[82] let: https://ru.wikipedia.org/wiki/%D0%91%D1%83%D0%BA%D0%BC%D0%B0%D1%80%D0%BA%D0%BB%D0%B5%D1%82
[83] его: #comment_18998409
[84] #: #sozdaem-proekt
[85] #: #struktura-proekta
[86] #: #probnyy-zapusk
[87] тег a1_v0.1.0: https://github.com/ZiroKyl/LLTR-Simulation-Model/tree/a1_v0.1.0
[88] git checkout -b ‹my_branch› tags/a1_v0.1.0: http://stackoverflow.com/questions/791959/download-a-specific-tag-with-git/792027#792027
[89] #: #rekomendacii-po-ispolzovaniyu-repozitoriya
[90] форкнуть на GitHub: https://github.com/ZiroKyl/LLTR-Simulation-Model/network/members
[91] git clone --branch ‹article_#› --single-branch: https://stackoverflow.com/questions/1778088/how-to-clone-a-single-branch-in-git/9920956#9920956
[92] --depth: https://stackoverflow.com/questions/20280726/how-to-git-clone-a-specific-tag/27421557#27421557
[93] git remote set-branches –add: https://stackoverflow.com/questions/17714159/how-do-i-undo-a-single-branch-clone/27860061#27860061
[94] если что‑то пойдет не так…: https://stackoverflow.com/questions/41075972/how-to-update-a-git-shallow-clone/41369314#41369314
[95] теги при Pull Request не переносятся: https://stackoverflow.com/questions/12278660/adding-tags-to-a-pull-request
[96] AST: https://ru.wikipedia.org/wiki/%D0%90%D0%B1%D1%81%D1%82%D1%80%D0%B0%D0%BA%D1%82%D0%BD%D0%BE%D0%B5_%D1%81%D0%B8%D0%BD%D1%82%D0%B0%D0%BA%D1%81%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B5_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE?stable=1
[97] этот проект для Java: https://bitbucket.org/sealuzh/tools-changedistiller/wiki/Home#markdown-header-references
[98] #: #sozdanie-pervoy-modeli-link-layer-topology-reveal
[99] #: #shag-1-sobiraem-set
[100] КДПВ: #LLTR_a1_habr-pic
[101] broadcast: https://github.com/inet-framework/inet/blob/v3.4.0/examples/inet/broadcast/UDPBroadcastNetwork.ned
[102] увидеть примерно это (git tag a1_v0.2.0): https://github.com/ZiroKyl/LLTR-Simulation-Model/blob/a1_v0.2.0/LLTR/simulations/package.ned
[103] Image: https://github.com/ZiroKyl/LLTR-Simulation-Model/compare/a1_v0.1.0...a1_v0.2.0
[104] package ‹имя пакета: https://omnetpp.org/doc/omnetpp/manual/#sec:ned-ref:packages
[105] особенности наименования: https://omnetpp.org/doc/omnetpp/manual/#sec:ned-ref:directory-structure
[106] имя подключаемого пакета: https://omnetpp.org/doc/omnetpp/manual/#sec:ned-lang:imports-and-name-resolution
[107] submodules: https://omnetpp.org/doc/omnetpp/manual/#sec:ned-ref:submodules
[108] название узла: https://omnetpp.org/doc/omnetpp/manual/#sec:ned-lang:submodules
[109] connections: https://omnetpp.org/doc/omnetpp/manual/#sec:ned-ref:connections
[110] точка соединения: https://omnetpp.org/doc/omnetpp/manual/#sec:ned-lang:gates
[111] каналы связи: https://omnetpp.org/doc/omnetpp/manual/#sec:ned-lang:warmup:introducing-a-channel
[112] Gates могут быть объявлены как векторы: https://web.archive.org/web/20150508223508/http://omnetpp.org/doc/omnetpp/tictoc-tutorial/part3.html#s10
[113] заданы в месте использования: https://omnetpp.org/doc/omnetpp/manual/#sec:ned-lang:channel-specification
[114] имя/тип: https://web.archive.org/web/20150508223508/http://omnetpp.org/doc/omnetpp/tictoc-tutorial/part3.html#s11
[115] на которое можно ссылаться: https://omnetpp.org/doc/omnetpp/manual/#sec:ned-lang:channel-names
[116] broadcast: https://github.com/inet-framework/inet/blob/v3.4.0/examples/inet/broadcast/UDPBroadcastNetwork.ned#L15
[117] переопределены на месте: https://omnetpp.org/doc/omnetpp/manual/#sec:ned-ref:static-channel-type
[118] либо…: https://omnetpp.org/doc/omnetpp/manual/#sec:ned-ref:parametric-channel-type
[119] двунаправленными: https://web.archive.org/web/20150508223508/http://omnetpp.org/doc/omnetpp/tictoc-tutorial/part3.html#s12
[120] дописав суффикс “$i” либо “$o”: https://omnetpp.org/doc/omnetpp/manual/#sec:ned-ref:inout-gates
[121] парсер: https://habr.com/company/tm/blog/397119/#comment_18831833
[122] переписывают: https://habr.com/company/tm/blog/397119/#comment_18830561
[123] Image: https://zirokyl.github.io/LLTR-Simulation-Model/a1/#i-come-from-habr
[124] здесь: https://zirokyl.github.io/LLTR-Simulation-Model/a1/#js-bookmarklet
[125] #: #to-be-continued
[126] в конце Джон умрет: #hack-is%20here
[127] #: #poll
[128] Источник: https://habr.com/post/420327/?utm_campaign=420327
Нажмите здесь для печати.