Настольное приложение на PyQt5 для проектирования топологий программно-конфигурируемых сетей (ПКС) и расчёта на них маршрутов с ограничениями по качеству обслуживания.
Курсовая работа, версия 1.4.
Автор: Жаднов Александр
Топология из 22 коммутаторов с контроллером c0. У каждой связи подписана
задержка; красным выделен найденный маршрут, справа — плавающие панели свойств
двух связей и одного коммутатора. Вертикальный тулбар слева переключает режимы
работы.
Рисуете сеть мышкой — хосты, коммутаторы, контроллер OpenFlow, связи с задержкой, потерями и пропускной способностью. Приложение считает на этой сети маршруты под заданными ограничениями QoS, подсвечивает найденные пути на холсте, показывает их в таблице с метриками — и умеет сгенерировать готовый к запуску скрипт Mininet для эмуляции этой топологии.
холст ──▶ метрики связей ──▶ матрицы смежности ──▶ алгоритм маршрутизации
│
результат ◀── подсветка путей + таблица QoS
экспорт ──▶ *.sdn.xml | *.sdn.py (Mininet) | *.txt
Рисование и редактирование
- 5 режимов работы: выделение, добавление хоста / коммутатора / контроллера, проведение связи. Режим переключается вертикальным тулбаром слева.
- Связи подписываются метриками; переключение по кругу
задержка → полоса → потери → все(кнопка в тулбаре). - Свойства устройства (ID, тип, IP, MAC, порт) и связи (полоса, задержка, потери) редактируются в док-панелях, а не только в плавающих окнах.
- IP/MAC/порт проставляются автоматически: хостам
10.0.0.N, контроллерам127.0.0.N, порт6653 + N - 1. - Плавающие окна без рамки, поверх всех, с перетаскиванием.
Построены на Yen's k-shortest paths и собственном Дейкстре. Метрики: задержка
(мс), потери (%), полоса (Мбит/с). Реализация — ui/algorithms.py.
| Алгоритм | Формулировка | Возвращает |
|---|---|---|
| MCP | Multi-Constrained Path — все k кандидатов, удовлетворяющих порогу по метрике 1, плюс все, удовлетворяющие порогу по метрике 2 | список допустимых маршрутов |
| MCOP | Multi-Constrained Optimal Path — лексикографически: минимум по метрике 1, при равенстве — минимум по метрике 2 | один оптимальный |
| CSP | Constrained Shortest Path — k кандидатов по оптимизируемой метрике, фильтр по ограничивающей, затем минимум | один маршрут |
| LARAC | Lagrangian Relaxation — агрегированная метрика m₁ + λ·m₂, порог r₁ + λ·r₂, k кандидатов по агрегату |
список |
Диалог настройки (QoSDialog) позволяет выбрать любую пару «оптимизируемая /
ограничивающая» метрику, k от 1 до 20, оба порога и λ ∈ [0, 10]. Настройки
сохраняются в QSettings. Видимые поля переключаются в зависимости от
выбранного алгоритма.
Полоса перед передачей в алгоритм инвертируется в 1/bw — иначе «больше
лучше» превратилось бы в «меньше лучше» для минимизации.
ui/fuzzy_qos.py. Классические алгоритмы выше требуют от аналитика заранее
задать числовые пороги и веса. Здесь вместо этого каждое ребро оценивается
нечётким числом качества, и уже эти оценки становятся весами для маршрутизации.
Классический нечёткий вывод Мамдани в три этапа.
1. Фаззификация — треугольные функции принадлежности, три терма на метрику (низкая / средняя / высокая):
def fuzzify_delay(self, delay):
low = max(0, min(1, (50 - delay) / 30)) if delay <= 50 else 0
medium = max(0, min(1, (delay - 20) / 30, (80 - delay) / 30)) if 20 <= delay <= 80 else 0
high = max(0, min(1, (delay - 50) / 30)) if delay >= 50 else 0Пороги подобраны так, чтобы шкалы задержки (мс), потерь (%) и полосы (Мбит/с) давали сопоставимые по смыслу термы.
2. Правила — четыре нечёткие импликации, агрегация min по предпосылкам
и max по заключениям:
| Правило | Предпосылка | → | Заключение |
|---|---|---|---|
| 1 | задержка низкая И потери низкие И полоса высокая | → | excellent |
| 2 | задержка низкая И (потери средние ИЛИ полоса средние) | → | good |
| 3 | задержка средняя И потери средние | → | average |
| 4 | задержка высокая ИЛИ потери высокие | → | poor |
rules_output['excellent'] = min(delay['low'], loss['low'], bandwidth['high'])
rules_output['good'] = min(delay['low'], max(loss['medium'], bandwidth['medium']))
rules_output['poor'] = max(delay['high'], loss['high'])3. Дефаззификация — взвешенное среднее по центрам термов (0.9 / 0.7 / 0.5 / 0.2):
numerator = 0.9*excellent + 0.7*good + 0.5*average + 0.2*poor
denominator = sum(rules_output.values())
return numerator / denominator if denominator > 0 else 0Результат — число в [0, 1].
Маршрутизация по нечётким оценкам. Итоговая оценка ребра — средневзвешенная
качество по трём метрикам; вес ребра для маршрутизации — 1 - quality, то есть
чем лучше связь, тем дешевле. Дальше по этой матрице работает тот же
yen:
quality = self.calculate_link_quality(delay_matrix[i][j],
loss_matrix[i][j],
bandwidth_matrix[i][j])
fuzzy_weights[i][j] = 1.0 - quality
...
routes = yen(fuzzy_weights, src, dst, k)То есть аналитику достаточно выбрать «fuzzy logic» вместо ручных порогов — и Yen's остаётся тем же алгоритмом, меняется только функция стоимости ребра.
Отдельный диалог Fuzzy QoS Routing Results показывает для каждого найденного
маршрута суммарную задержку, потери, минимальную полосу по пути и итоговую
нечёткую оценку качества.
ui/algorithms1.py — четыре алгоритма разбиения сети на сегменты:
| Алгоритм | Метод |
|---|---|
Girvan_Newman_Segmentation |
итеративное удаление ребра с максимальной betweenness (алгоритм Брандеса), затем выделение компонент связности |
binarySegmentation |
BFS-разметка прыжками от источника, затем повторное деление пополам |
greedySegmentation |
BFS-разметка, деление узлов на n примерно равных групп |
connectivitySegmentation |
минимальное остовное дерево (Прим, кучей), группировка листьев с родителями, слияние сегментов при Q = внутренние / (внешние + ε) < 0.3 |
Читается и пишется собственный XML (utils/file_io.py), парсер — стандартный
xml.etree.ElementTree, без внешних библиотек.
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE topology>
<Network>
<Hosts> <Host x="100" y="80" ip="10.0.0.2" mac="00:00:00:00:00:02"/>
</Hosts>
<Switches> <Switch x="508" y="458"/>
</Switches>
<Controllers> <Controller x="461" y="194" ip="127.0.0.1" port="6653"/>
</Controllers>
<SSLinks> <Link node1="s2" node2="s1" bandwidth="1" delay="22" loss="0"/>
</SSLinks>
<CSLinks> <Link node1="c0" node2="s1"/>
</CSLinks>
<Texts/>
</Network>SSLinks — связи коммутатор↔хост/коммутатор, несут метрики. CSLinks —
контроллер↔коммутатор, метрики игнорируются и при импорте заменяются на
1.0 / 1.0 / 0.0.
Узлы в связях адресуются ролевыми именами h1…hN, s1…sN, c0…cN-1;
первый символ выбирает секцию, число — 1-based индекс (для контроллеров
0-based) в порядке документа. При импорте настоящие идентификаторы
(host1, switch1, controller1) генерируются заново по порядку документа,
при экспорте устройства перегруппировываются по типу и нумеруются обратно в
ролевые имена. Схемы и XSD нет — парсер снисходителен, отсутствующее
поле молча берёт значение по умолчанию.
Главная хрупкость схемы — привязка к порядку документа. Вставка хоста в
середину <Hosts> сдвигает нумерацию всех, кто после него.
| Формат | Назначение |
|---|---|
*.sdn.xml |
собственный формат топологии topology.sdn12.xml, round-trip |
*.sdn.py |
готовый скрипт Mininet: OVSKernelSwitch, TCLink с bw/delay/loss, RemoteController на 127.0.0.1:6653 |
*.txt |
метрики в формате n1-n2:задержка,полоса,потери — вход для внешних алгоритмов |
main.py точка входа, настройка логирования, обработчик исключений
core/
app.py SDNVisualizerApp — QApplication + QGraphicsView
models.py DeviceType, @dataclass Device и Link
scene.py NetworkScene + элементы графа (самая большая часть)
ui/
main_window.py главное окно, меню, док-панели, пайплайн QoS
algorithms.py dijkstra, recover, yen, MCP, MCOP, CSP, LARAC
fuzzy_qos.py нечёткий вывод Мамдани + маршрутизация по fuzzy-весам
algorithms1.py 4 алгоритма сегментации графа
algorithms2.py копия algorithms.py
device_panel.py свойства устройства
link_panel.py свойства связи
toolbar.py вертикальный тулбар, режимы, горячие клавиши
theme.py палитра и генерация Qt StyleSheet
segmentation_dialog.py диалог выбора алгоритма сегментации
floating_windows.py окна без рамки, QoSDialog, QoSResultsDialog
utils/file_io.py импорт/экспорт XML, генератор Mininet, экспорт метрик
others/ тестовые топологии + парсер метрик + пример Mininet-скрипта
icons/ SVG-иконки
NetworkScene — самая большая часть. Классы: SvgDeviceItem (SVG-иконка +
жирная подпись короткого ID), NetworkLinkItem (с метрикой-плашкой, подсветкой
QoS, отрисовкой рамки выделения), NetworkDeviceItem (устаревший цветной круг,
фактически мёртвый), плюс два notifier-класса на QObject для оповещений об
изменении позиции и свойств.
Связи перерисовываются в реальном времени при перетаскивании узла: сигнал
positionChanged → update_position(). Во время проведения связи рисуется
живая пунктирная резиновая линия. Выделение рамкой, Qt-эффекты выделения,
z-порядок (узлы 10, связи 5, подсветка 10).
Зависимость ровно одна: PyQt5 (+ PyQt5_svg для рендера иконок).
Всё остальное — стандартная библиотека. networkx и matplotlib в коде
не используются: матрицы смежности — обычные вложенные списки.
Нечёткая логика реализована вручную, numpy в fuzzy_qos.py импортируется,
но не используется.
pip install PyQt5==5.15.11 PyQt5_svg
python main.pyPython 3.12. Запускать из корня sdn_visualizer/: пакетных __init__.py
нет, импорты абсолютные (from core.app import ...).
Приложение в рабочем состоянии, но код не чистился. Что есть:
ui/algorithms1.py— файл продублирован дословно: строки 1–311 повторены как 313–623, включая импорты. Вторые определения затирают первые. Модуль при этом не импортируется ниоткуда — сегментация в приложении сейчас недоступна.ui/algorithms2.py— побайтовая копияui/algorithms.py(разница в 1 байт). Тоже не используется.SegmentationDialogимпортируется вmain_window.py, но ни разу не создаётся. Кнопка в тулбаре подписана «Run Segmentation Algorithm», хотя вызывает пайплайн маршрутизации. Подпись осталась от прежней версии.- В
FuzzyQoS.__init__параметрыdelay_weight,loss_weight,bandwidth_weightиquality_thresholdсохраняются в поля, но нигде не используются — правила вfuzzy_rulesзахардкожены. То есть настроить веса метрик через диалог нельзя, несмотря на то что поля под это заведены.quality_thresholdне фильтрует маршруты, а только хранится. TransparentPanelопределён дважды — вdevice_panel.pyиlink_panel.py, идентично.closeEventвmain_window.pyопределён дважды; второй перекрывает первый, поэтому док-панели при выходе не закрываются.scene.pyвызываетself.scene().link_double_clicked(...)— такого метода наNetworkSceneнет, двойной клик прямо по линии падает сAttributeError. Работает только ветка через двойной клик по подписи.algorithm()пишетothers/metric_data.txtвнутрь репозитория при каждом запуске расчёта — файл перезаписывается, вgitэто даст лишний diff. Вsdn_visualizer.log(104 КБ) видно, что лог тоже растёт в рабочем каталоге.- Типизация практически отсутствует: аннотаций нет нигде, кроме полей
dataclass в
models.py, трёх функций вtheme.pyи сигнатурыfuzzy_qos. - Тестов нет вообще. Файлы
others/test1.xml…test4.xml— ручные фикстуры, а не автотесты. - Язык смешанный: докстринги и комментарии на русском, строки UI частично на
русском («Свойства устройства», «Сохранить изменения»), частично на
английском (
File,Open,Algorithm, интерфейсQoSDialog,Fuzzy QoS Routing Results), сообщения лога — на английском.
SVG-иконки в icons/ — сторонняя графика, перекрашенная под палитру
приложения. python_export.svg явно производная от логотипа Python. Лицензия
и происхождение из репозитория не установлены — атрибуция не указана.
fig21.sdn.xml и fig22.sdn.xml (13 и 22 коммутатора) названы по рисункам из
внешнего источника — скорее всего из методических материалов или статьи. Перед
публикацией стоит уточнить происхождение.
MIT.
