Tutoriel du simulateur de réseau ns-3. chapitre 4

Tutoriel du simulateur de réseau ns-3. chapitre 4
chapitre 1,2
chapitre 3

4 Aperçu du concept
4.1 Abstractions clés
4.1.1 Nœud
4.1.2 Demande
4.1.3 Canal
4.1.4 Périphérique réseau
4.1.5 Assistants topologiques
4.2 Premier script ns-3
4.2.1 Code passe-partout
4.2.2 Plug-ins
4.2.3 Espace de noms ns3
4.2.4 Journalisation
4.2.5 Fonction principale
4.2.6 Utilisation des assistants de topologie
4.2.7 Utilisation de l'application
4.2.8 Simulateur
4.2.9 Construire votre script
4.3 ns-3Code source

Chapitre 4

Aperçu du concept

La première chose que nous devons faire avant de commencer à apprendre ou à écrire du code ns-3 est d'expliquer quelques concepts et abstractions de base du système. Une grande partie de cela peut sembler évidente à certains, mais nous vous recommandons de prendre le temps de lire cette section pour vous assurer de partir sur des bases solides.

4.1 Abstractions clés

Dans cette section, nous examinerons certains termes couramment utilisés sur le Web mais qui ont une signification spécifique dans ns-3.

4.1.1 Nœud

Dans le jargon Internet, un périphérique informatique qui se connecte à un réseau est appelé un hôte ou parfois un système final. NS-3 étant un simulateur de réseau et non un simulateur Internet, nous n'utilisons délibérément pas le terme hôte, car il est étroitement lié à Internet et à ses protocoles. Au lieu de cela, nous utilisons un terme plus général, également utilisé par d'autres simulateurs, qui trouve son origine dans la théorie des graphes : nœud (nœud).

Dans ns-3, l'abstraction sous-jacente d'un dispositif informatique est appelée un nœud. Cette abstraction est représentée en C++ par la classe Node. Classe NœudNœud (nœud) fournit des méthodes pour manipuler les représentations de dispositifs informatiques dans les simulations.

Tu dois comprendre Nœud comme un ordinateur auquel vous ajoutez des fonctionnalités. Vous ajouterez des éléments tels que des applications, des piles de protocoles et des cartes périphériques avec des pilotes qui permettent à l'ordinateur d'effectuer un travail utile. Nous utilisons le même modèle de base dans ns-3.

4.1.2 Demande

Généralement, les logiciels informatiques sont divisés en deux grandes classes. Le logiciel système organise diverses ressources informatiques telles que la mémoire, les cycles du processeur, le disque, le réseau, etc. selon un modèle informatique. Le logiciel système n'utilise généralement pas ces ressources pour effectuer des tâches qui profitent directement à l'utilisateur. Un utilisateur exécute généralement une application pour atteindre un objectif spécifique, qui obtient et utilise des ressources contrôlées par le logiciel système.

Souvent, la ligne de séparation entre les logiciels système et les logiciels d'application est tracée au niveau des changements de niveau de privilège qui se produisent dans les pièges du système d'exploitation. ns-3 n'a pas de véritable concept de système d'exploitation et donc aucun concept de niveaux de privilèges ou d'appels système. Nous avons cependant une idée d’application. Tout comme dans le « monde réel », les applications logicielles s’exécutent sur des ordinateurs pour effectuer des tâches, les applications ns-3 s’exécutent sur les nœuds ns-3 pour contrôler les simulations dans le monde simulé.

Dans ns-3, l'abstraction de base d'un programme utilisateur qui génère une activité de modélisation est une application. Cette abstraction est représentée en C++ par la classe Application. La classe Application fournit des méthodes pour manipuler les vues de notre version utilisateur des applications dans les simulations. Les développeurs sont censés spécialiser la classe Application dans un sens de programmation orientée objet pour créer de nouvelles applications. Dans ce tutoriel, nous utiliserons les spécialisations de la classe Application appelées UdpEchoClientApplicationUdpEchoClientApplication и UdpEchoServerApplicationUdpEchoServerApplication. Comme on peut s'y attendre, ces applications constituent un ensemble d'applications client/serveur utilisées pour générer et faire écho aux paquets réseau.

4.1.3 Canal

Dans le monde réel, vous pouvez connecter un ordinateur à un réseau. Souvent, les supports sur lesquels les données sont transmises dans ces réseaux sont appelés canaux. Lorsque vous branchez un câble Ethernet sur une prise murale, vous connectez votre ordinateur à une liaison Ethernet. Dans le monde ns-3 simulé, un nœud est connecté à un objet représentant un canal de communication. Ici, l'abstraction de base du sous-réseau de communication est appelée canal et est représentée en C++ par la classe Channel.

classe CanalCanal fournit des méthodes pour gérer l'interaction des objets de sous-réseau et y connecter des hôtes. Les canaux peuvent également être spécialisés par les développeurs dans le sens d'une programmation orientée objet. La spécialisation des canaux peut modéliser quelque chose d'aussi simple qu'un fil. Un canal dédié peut également modéliser des éléments complexes comme un grand commutateur Ethernet ou un espace tridimensionnel rempli d'obstacles dans le cas des réseaux sans fil.

Nous utiliserons des versions spécialisées de la chaîne dans ce tutoriel appelé CsmaChannelCsmaChannel, PointÀPointChannelPointÀPointChannel и WifiChannelWifiChannel. CsmaChannel, par exemple, modélise une version d'un sous-réseau de communications qui implémente un environnement de communications à accès multiple à détection de porteuse. Cela nous donne une fonctionnalité de type Ethernet.

4.1.4 Périphérique réseau

Autrefois, si vous vouliez connecter un ordinateur à un réseau, vous deviez acheter un câble réseau spécifique et un périphérique matériel appelé (dans la terminologie PC) une carte périphérique qui devait être installée dans l'ordinateur. Si une carte périphérique implémentait certaines fonctions réseau, elles étaient appelées cartes d'interface réseau ou cartes réseau. Aujourd'hui, la plupart des ordinateurs sont dotés d'un matériel d'interface réseau intégré et ne sont pas considérés par les utilisateurs comme des appareils distincts.

Une carte réseau ne fonctionnera pas sans un pilote logiciel qui contrôle son matériel. Sous Unix (ou Linux), un équipement périphérique est classé comme un périphérique. Les périphériques sont gérés à l'aide de pilotes de périphérique et les périphériques réseau (NIC) sont gérés à l'aide de pilotes de périphérique réseau (pilotes de périphériques réseau) et sont collectivement appelés périphériques réseau (appareils Internet). Sous Unix et Linux, vous faites référence aux périphériques réseau par des noms tels que eth0.

Dans ns-3, l'abstraction du périphérique réseau couvre à la fois le pilote logiciel et le matériel modélisé. Dans la simulation, un périphérique réseau est « installé » dans un nœud pour lui permettre de communiquer avec d'autres nœuds via des canaux. Tout comme un véritable ordinateur, un nœud peut être connecté à plusieurs canaux via plusieurs appareils NetDevices.

L'abstraction réseau d'un périphérique est représentée en C++ par la classe NetDevice... Classer NetDevice fournit des méthodes pour gérer les connexions aux objets Node et Channel ; et peut être spécialisé par les développeurs dans le sens de la programmation orientée objet. Dans ce tutoriel, nous utiliserons plusieurs versions spécialisées de NetDevice appelées Périphérique CsmaNet, PointVersPointNetDevice и WifiNetAppareil. Tout comme un adaptateur réseau Ethernet est conçu pour fonctionner avec un réseau Ethernet, Périphérique CsmaNet conçu pour fonctionner avec CsmaChannel, PointVersPointNetDevice conçu pour fonctionner avec PointVersPointChannelEt WifiNetAppareil - conçu pour fonctionner avec WifiCanal.

4.1.5 Assistants topologiques

Dans un réseau réel, vous trouverez des ordinateurs hôtes avec des cartes réseau ajoutées (ou intégrées). Dans ns-3, nous dirions que vous verrez des nœuds avec des NetDevices attachés. Dans un grand réseau simulé, vous devrez organiser les connexions entre de nombreux objets Nœud, NetDevice и Développement.

Depuis la connexion des NetDevices aux nœuds, des NetDevices aux liens, l'attribution d'adresses IP, etc. dans ns-3, c'est une tâche courante, pour rendre cela aussi simple que possible, nous fournissons ce que l'on appelle des assistants de topologie. Par exemple, pour créer un NetDevice, vous devez effectuer de nombreuses opérations sur le noyau ns-3, ajouter une adresse MAC, installer le périphérique réseau dans Node, configurer la pile de protocoles du nœud, puis connecter le NetDevice au canal. Encore plus de travail sera nécessaire pour connecter plusieurs appareils à des liaisons multipoints, puis connecter les réseaux individuels dans un réseau Internetworks. Nous fournissons des objets d'assistance topologique qui combinent ces nombreuses opérations dans un modèle facile à utiliser pour votre commodité.

4.2 Premier script ns-3

Si vous avez installé le système comme suggéré ci-dessus, vous aurez la version ns-3 dans un répertoire appelé repos dans votre répertoire personnel. Aller au répertoire libérer

Si vous n'avez pas un tel répertoire, cela signifie que vous n'avez pas spécifié le répertoire de sortie lors de la construction de la version finale de ns-3, construisez comme ceci :
$ ./waf configure —build-profile=release —out=build/release,
$ ./waf construit

là, vous devriez voir une structure de répertoires similaire à la suivante :

AUTHORS       examples      scratch       utils       waf.bat*
bindings      LICENSE       src           utils.py    waf-tools
build         ns3           test.py*      utils.pyc   wscript
CHANGES.html  README        testpy-output VERSION     wutils.py
doc           RELEASE_NOTES testpy.supp   waf*        wutils.pyc

Aller au répertoire exemples/tutoriel. Vous devriez voir un fichier appelé premier.cc. Il s'agit d'un script qui créera une simple connexion point à point entre deux nœuds et transmettra un paquet entre les nœuds. Regardons ce script ligne par ligne ; pour ce faire, ouvrez first.cc dans votre éditeur préféré.

4.2.1 Code passe-partout
La première ligne du fichier est la ligne du mode éditeur emacs. Il indique à emacs les conventions de formatage (style de codage) que nous utilisons dans notre code source.

/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */

Il s’agit toujours d’une question assez controversée, nous devons donc remettre les pendules à l’heure pour que cela soit réglé immédiatement. Le projet ns-3, comme la plupart des grands projets, a adopté un style de codage auquel tout le code contribué doit se conformer. Si vous souhaitez apporter votre code au projet, vous devrez éventuellement vous conformer à la norme de codage ns-3, comme décrit dans le fichier doc/codingstd.txt ou affiché sur la page Web du projet : https://www.nsnam.org/develop/contributing-code/coding-style/.

Nous vous recommandons de vous habituer à l'apparence du code ns-3 et d'appliquer cette norme chaque fois que vous travaillez avec notre code. L'ensemble de l'équipe de développement et les contributeurs ont accepté cela après quelques grognements. La ligne de mode emacs ci-dessus facilite le formatage correct si vous utilisez l'éditeur emacs.

Le simulateur ns-3 est sous licence utilisant GNU General Public License. Vous verrez l'en-tête légal GNU approprié dans chaque fichier de distribution ns-3. Souvent, vous verrez un avis de droit d'auteur pour l'une des institutions participantes au projet ns-3 au-dessus du texte GPL et de l'auteur, indiqués ci-dessous.

/* 
* This program is free software; you can redistribute it and/or modify 
* it under the terms of the GNU General Public License version 2 as 
* published by the Free Software Foundation; 
*
* This program is distributed in the hope that it will be useful, 
* but WITHOUT ANY WARRANTY; without even the implied warranty of 
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
* GNU General Public License for more details. 
* 
* You should have received a copy of the GNU General Public License 
* along with this program; if not, write to the Free Software 
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
*/

4.2.2 Plug-ins

Le code lui-même commence par une série d'instructions d'inclusion (comprendre).

#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/internet-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/applications-module.h"

Pour aider nos utilisateurs de scripts de haut niveau à faire face au grand nombre de fichiers d'en-tête présents dans le système, nous les regroupons en fonction de leur utilisation dans de grands modules. Nous fournissons un seul fichier d'en-tête qui chargera de manière récursive tous les fichiers d'en-tête utilisés dans un module donné. Au lieu d'avoir à rechercher exactement l'en-tête dont vous avez besoin et éventuellement à obtenir la liste correcte des dépendances, nous vous offrons la possibilité de télécharger un groupe de fichiers avec une grande granularité. Ce n'est pas l'approche la plus efficace, mais elle facilite certainement l'écriture de scripts.

Chacun des fichiers d'inclusion ns-3 est placé dans un répertoire appelé ns3 (sous-répertoire build) pour éviter les conflits de noms de fichiers pendant le processus de construction. Déposer ns3/core-module.h correspond au module ns-3, que vous trouverez dans le répertoire src/noyau dans la version que vous avez installée. Dans le listing de ce répertoire vous trouverez un grand nombre de fichiers d'en-tête. Quand vous faites le montage, Waf place les fichiers d'en-tête publics dans le répertoire ns3 dans un sous-répertoire construire/déboguer

Si vous n'avez pas un tel répertoire, cela signifie que vous n'avez pas spécifié le répertoire de sortie lors de la construction de la version finale de ns-3, construisez comme ceci :
$ ./waf configurer --build-profile=debug --out=build/debug
$ ./waf construit
ou
$ ./waf configure --build-profile=optimized --out=build/optimized
$ ./waf construit

ou construire/optimisé, en fonction de votre configuration. Waf générera également automatiquement un fichier d'inclusion de module pour charger tous les fichiers d'en-tête publics. Puisque vous suivez bien sûr religieusement ce guide, vous avez déjà fait

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

pour configurer le projet pour exécuter des versions de débogage qui incluent des exemples et des tests. Tu as aussi fait

$ ./waf

pour assembler le projet. Alors maintenant, quand tu regardes dans l'annuaire ../../build/debug/ns3, vous y trouverez, entre autres, les fichiers d'en-tête des quatre modules présentés ci-dessus. Vous pouvez consulter le contenu de ces fichiers et constater qu'ils incluent tous les fichiers publics utilisés par les modules correspondants.

4.2.3 Espace de noms ns3

Ligne suivante dans le script premier.cc est une déclaration d'espace de noms.

using namespace ns3;

Le projet ns-3 est implémenté dans un espace de noms C++ appelé ns3. Cela regroupe toutes les déclarations liées à ns-3 dans une portée en dehors de l'espace de noms global, ce qui, espérons-le, facilitera l'intégration avec d'autres codes. L'utilisation de l'opérateur C++ introduit l'espace de noms ns-3 dans la région déclarative (globale) actuelle. C'est une façon élégante de dire qu'après cette déclaration, vous n'aurez pas besoin de taper l'opérateur d'autorisation ns3::scope avant tout votre code ns-3 pour l'utiliser. Si vous n'êtes pas familier avec les espaces de noms, reportez-vous à presque tous les didacticiels C++ et comparez l'espace de noms ns3 à l'aide de l'espace de noms et de la déclaration std. using namespace std; dans des exemples de travail avec l'opérateur de sortie cout et des ruisseaux.

4.2.4 Journalisation

La ligne suivante du script est :

NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");

Nous utiliserons cette déclaration comme un endroit pratique pour discuter de notre système de documentation doxygen. Si vous consultez le site Web du projet ns-3, vous trouverez un lien Documentation dans la barre de navigation. Si vous cliquez sur ce lien, vous serez redirigé vers notre page de documentation. Il existe un lien « Dernière version » qui vous mènera à la documentation de la dernière version stable de ns-3. Si vous sélectionnez le lien « Documentation API », vous serez redirigé vers la page de documentation de l'API ns-3.

Sur le côté gauche de la page, vous trouverez une représentation graphique de la structure de la documentation. Un bon point de départ est le « livre » des modules ns-3 dans l'arborescence de navigation ns-3. Si tu révèles Modules, vous verrez une liste de la documentation des modules ns-3. Comme indiqué ci-dessus, le concept de module ici est directement lié aux fichiers inclus dans le module ci-dessus. Le sous-système de journalisation ns-3 est abordé dans la section Utilisation du module de journalisation, nous y reviendrons donc plus tard dans ce tutoriel, mais vous pouvez en apprendre davantage sur l'instruction ci-dessus en consultant le module Corepuis j'ouvre le livre Outils de débogagepuis en sélectionnant la page Journal. Cliquer sur Journal.

Vous devriez maintenant consulter la documentation doxygen pour module Journal. Dans la liste des macros en haut de la page, vous verrez une entrée pour NS_LOG_COMPONENT_DEFINE. Avant de cliquer sur le lien, assurez-vous de consulter la « Description détaillée » du module d'inscription pour comprendre son fonctionnement en général. Pour ce faire, vous pouvez faire défiler vers le bas ou sélectionner "Plus..." sous le graphique.

Une fois que vous avez une idée générale de ce qui se passe, allez-y et consultez la documentation du NS_LOG_COMPONENT_DEFINE spécifique. Je ne dupliquerai pas la documentation ici, mais pour résumer, cette ligne déclare un composant d'enregistrement appelé ExemplePremierScript, qui vous permet d'activer ou de désactiver la journalisation des messages sur la console en faisant référence à un nom.

4.2.5 Fonction principale

Dans les lignes suivantes du script, vous verrez,

int 
main (int argc, char *argv[])
{ 

Il s'agit simplement d'une déclaration de la fonction principale de votre programme (script). Comme pour tout programme C++, vous devez définir une fonction principale, celle-ci est exécutée en premier. Il n'y a rien de spécial ici. Votre script ns-3 n'est qu'un programme C++. La ligne suivante définit la résolution temporelle sur 1 nanoseconde, qui est la valeur par défaut :

Time::SetResolution (Time::NS);

La résolution temporelle, ou simplement la résolution, est la plus petite valeur temporelle pouvant être utilisée (la plus petite différence représentable entre deux temps). Vous pouvez modifier la résolution exactement une fois. Le mécanisme qui offre cette flexibilité consomme de la mémoire, donc une fois la résolution explicitement définie, nous libérons la mémoire, empêchant ainsi d'autres mises à jour. (Si vous ne définissez pas explicitement la résolution, elle sera par défaut d'une nanoseconde et la mémoire sera libérée au démarrage de la simulation.)

Les deux lignes de script suivantes sont utilisées pour activer deux composants de journalisation intégrés aux applications EchoClient и ÉchoServeur:

LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO); LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO);

Si vous lisez la documentation du composant Logging, vous verrez qu'il existe plusieurs niveaux de journalisation/granularité que vous pouvez activer sur chaque composant. Ces deux lignes de code permettent la journalisation du débogage au niveau INFO pour les clients et serveurs Echo. À ce niveau, l'application imprimera des messages au fur et à mesure qu'elle enverra et recevra des paquets pendant la simulation.

Nous allons maintenant passer à la création de la topologie et à l'exécution de la simulation. Nous utilisons des objets d'assistance topologique pour rendre ce travail aussi simple que possible.

4.2.6 Utilisation des assistants de topologie

Les deux prochaines lignes de code de notre script créeront en fait les objets Node ns-3 qui représenteront les ordinateurs dans la simulation.

NodeContainer nodes;
nodes.Create (2);

Avant de continuer, trouvons la documentation de la classe Conteneur de nœud. Une autre façon d'accéder à la documentation d'une classe donnée consiste à utiliser l'onglet Cours sur les pages doxygen. Si Doxygen est déjà ouvert, faites simplement défiler vers le haut de la page et sélectionnez l’onglet Classes. Vous devriez voir un nouvel ensemble d’onglets, dont l’un est une liste de classes. Sous cet onglet, vous verrez une liste de toutes les classes NS-3. Faites défiler jusqu'à ns3 ::NodeContainer. Lorsque vous trouvez une classe, sélectionnez-la pour accéder à la documentation de la classe.

Comme nous nous en souvenons, l'une de nos abstractions clés est le nœud. Il représente l'ordinateur auquel nous allons ajouter des éléments tels que des piles de protocoles, des applications et des cartes périphériques. Assistant de topologie Conteneur de nœud fournit un moyen pratique de créer, gérer et accéder à tous les objets Nœud, que nous créons pour exécuter la simulation. La première ligne ci-dessus déclare simplement Conteneur de nœud, que nous appelons nœuds. La deuxième ligne appelle la méthode Create sur l'objet nodes et demande au conteneur de créer deux nœuds. Comme décrit dans doxygen, le conteneur demande au système ns-3 de créer deux objets Nœud et stocke les pointeurs vers ces objets en interne.

Les nœuds créés dans le script ne font encore rien. La prochaine étape dans la construction de la topologie consiste à connecter nos nœuds au réseau. La forme de réseau la plus simple que nous prenons en charge est une connexion point à point entre deux nœuds. Nous allons maintenant créer une telle connexion.

PointÀPointHelper

Nous créons une connexion point à point à l'aide d'un modèle familier, en utilisant un objet d'assistance topologique pour effectuer le travail de bas niveau requis pour la connexion. Rappelons que nos deux abstractions clés NetDevice и Développement. Dans le monde réel, ces termes correspondent à peu près aux cartes périphériques et aux câbles réseau. En règle générale, ces deux choses sont étroitement liées l'une à l'autre et personne ne peut compter sur le partage, par exemple, d'appareils. Ethernet sur un canal sans fil. Nos assistants de topologie suivent cette relation étroite et vous utiliserez donc un seul objet dans ce scénario PointÀPointHelper pour configurer et connecter des objets ns-3 PointVersPointNetDevice и PointVersPointChannel. Les trois lignes suivantes du script :

PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps")); 
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));

Première ligne,

PointToPointHelper pointToPoint;

crée une instance d'un objet sur la pile PointÀPointHelper. D'un point de vue de haut niveau, la ligne suivante,

pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));

raconte l'objet PointÀPointHelper utilisez la valeur « 5 Mbit/s » (cinq mégabits par seconde) comme «Débit de données».

D'un point de vue plus précis, la chaîne "DataRate" correspond à ce que l'on appelle un attribut PointVersPointNetDevice. Si tu regardes doxygen pour la classe ns3 :: PointToPointNetDevice et dans la documentation de la méthode ObtenirTypeId vous trouverez une liste d'attributs définis pour l'appareil. Parmi eux se trouvera l'attribut "Débit de données" La plupart des objets NS-3 visibles par l'utilisateur ont des listes d'attributs similaires. Nous utilisons ce mécanisme pour mettre en place facilement la simulation sans recompilation, comme vous le verrez dans la section suivante.

Comme "Débit de données" dans PointToPointNetDevice, vous retrouverez l'attribut "Delay" associé au PointToPointChannel. La dernière ligne

pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));

dit PointÀPointHelper utiliser la valeur "2 ms" (deux millisecondes) comme valeur du délai de propagation pour la liaison point à point qu'il crée ensuite.

NetDeviceContainer

Pour le moment nous avons dans le script Conteneur de nœud, qui contient deux nœuds. Nous avons PointÀPointHelper, qui est préparé pour créer des objets PointToPointNetDevices et en les connectant à l'aide d'un objet PointToPointChannel. Tout comme nous avons utilisé l'objet d'assistance de topologie NodeContainer pour créer des nœuds, nous demanderons PointÀPointHelper effectuer pour nous des travaux liés à la création, à la configuration et à l'installation de nos appareils. Nous avons besoin d'une liste de tous les objets créés NetDevice, donc on utilise NetDeviceContainer pour les stocker de la même manière que nous l'utilisions Conteneur de nœud pour stocker les nœuds que nous avons créés. Les deux lignes de code suivantes,

NetDeviceContainer devices;
devices = pointToPoint.Install (nodes);

configuration complète de l’appareil et des canaux. La première ligne déclare le conteneur de périphériques mentionné ci-dessus et la seconde effectue le travail principal. Méthode Installer objet PointÀPointHelper prend Conteneur de nœud comme paramètre. À l'intérieur NetDeviceContainer pour chaque nœud situé dans Conteneur de nœud est créé (pour une communication point à point, il doit y en avoir exactement deux) PointVersPointNetDevice est créé et enregistré dans le conteneur de périphérique. PointVersPointChannel est créé et deux y sont attachés PointToPointNetDevices. Après avoir créé des objets, les attributs stockés dans PointÀPointHelper, permettent d'initialiser les attributs correspondants dans les objets créés.

Après avoir passé un appel pointToPoint.Install (nœuds) nous aurons deux nœuds, chacun avec un périphérique réseau point à point installé et une liaison point à point entre eux. Les deux appareils seront configurés pour transmettre des données à une vitesse de cinq mégabits par seconde avec un délai de transmission de deux millisecondes sur le canal.

InternetStackHelper

Nous avons maintenant des nœuds et des périphériques configurés, mais nos nœuds n'ont pas de piles de protocoles installées. Les deux prochaines lignes de code s’en chargeront.

InternetStackHelper stack;
stack.Install (nodes);

InternetStackHelper - est un assistant de topologie pour les piles Internet, similaire à PointToPointHelper pour les périphériques réseau point à point. Méthode Installer prend NodeContainer comme paramètre. Une fois exécuté, il installera la pile Internet (TCP, UDP, IP, etc.) sur chaque nœud de conteneur.

Assistant d'adresse IPv4

Ensuite, nous devons associer nos appareils à des adresses IP. Nous fournissons un assistant de topologie pour gérer l'attribution des adresses IP. La seule API visible par l'utilisateur consiste à définir l'adresse IP de base et le masque de réseau à utiliser lors de la distribution réelle de l'adresse (cela se fait à un niveau inférieur dans l'assistant). Les deux lignes de code suivantes dans notre exemple de script premier.cc,

Ipv4AddressHelper address;
address.SetBase ("10.1.1.0", "255.255.255.0");

déclarez l'objet d'assistance d'adresse et dites-lui qu'il doit commencer à attribuer des adresses IP à partir du réseau 10.1.1.0, en utilisant le masque de bits 255.255.255.0 pour le déterminer. Par défaut, les adresses allouées commenceront à un et augmenteront de façon monotone, donc la première adresse allouée à partir de cette base sera 10.1.1.1, puis 10.1.1.2, etc. En réalité, à un niveau bas, le système NS-3 mémorise toutes les adresses IP allouées et génère une erreur fatale si vous créez accidentellement une situation dans laquelle la même adresse est générée deux fois (d'ailleurs, cette erreur est difficile à déboguer).

La ligne de code suivante,

Ipv4InterfaceContainer interfaces = address.Assign (devices);

effectue l'attribution d'adresse proprement dite. Dans ns-3 nous établissons une connexion entre une adresse IP et un appareil en utilisant l'objet Interface IPv4. Tout comme nous avons parfois besoin d'une liste de périphériques réseau créés par l'assistant pour une utilisation ultérieure, nous avons parfois besoin d'une liste d'objets Interface IPv4. Conteneur d'interface IPv4 fournit cette fonctionnalité.

Nous avons construit un réseau point à point, avec des piles installées et des adresses IP attribuées. Nous avons désormais besoin d'applications dans chaque nœud pour générer du trafic.

4.2.7 Utilisation de l'application

Une autre des principales abstractions du système ns-3 est Application (application). Dans ce scénario, nous utilisons deux spécialisations de classe de base Application ns-3 appelé UdpEchoServerApplicationUdpEchoServerApplication и UdpEchoClientApplicationUdpEchoClientApplication. Comme dans les cas précédents, nous utilisons des objets auxiliaires pour configurer et gérer les objets de base. Ici, nous utilisons UdpEchoServerHelper и UdpEchoClientAider des objets pour nous faciliter la vie.

UdpEchoServerHelper

Les lignes de code suivantes de notre exemple de script first.cc sont utilisées pour configurer une application de serveur d'écho UDP sur l'un des nœuds que nous avons créés précédemment.

UdpEchoServerHelper echoServer (9);

ApplicationContainer serverApps = echoServer.Install (nodes.Get (1));
serverApps.Start (Seconds (1.0));
serverApps.Stop (Seconds (10.0));

La première ligne de code de l'extrait ci-dessus crée UdpEchoServerHelper. Comme d'habitude, ce n'est pas une application en soi, c'est un objet qui nous aide à créer de véritables applications. L'une de nos conventions consiste à transmettre les attributs requis au constructeur de l'objet assistant. Dans ce cas, l'assistant ne peut rien faire d'utile à moins de lui donner le numéro de port sur lequel le serveur va écouter les paquets, ce numéro doit également être connu du client. Dans ce cas, nous transmettons le numéro de port au constructeur assistant. Le constructeur, à son tour, fait simplement Définir l'attribut avec la valeur transmise. Plus tard, si vous le souhaitez, vous pouvez utiliser SetAttribute pour définir une valeur différente pour l'attribut Port.

Comme beaucoup d'autres objets auxiliaires, l'objet UdpEchoServerHelper a une méthode Installer. L'exécution de cette méthode crée efficacement une application de serveur d'écho de base et la lie à l'hôte. Il est intéressant de noter que la méthode Installer prend NodeContainer comme paramètre comme les autres Installer méthodes que nous avons vues.

La conversion implicite C++ fonctionnant ici prend le résultat de la méthode nœud.Get(1) (qui renvoie un pointeur intelligent vers l'objet nœud - Ptr ) et l'utilise dans le constructeur de l'objet anonyme Conteneur de nœudqui est ensuite transmis à la méthode Installer. Si vous ne parvenez pas à déterminer dans le code C++ quelle signature de méthode est compilée et exécutée, recherchez parmi les conversions implicites.

Maintenant nous voyons que echoServer.Installer sur le point d'installer l'application UdpEchoServerApplicationUdpEchoServerApplication sur trouvé dans Conteneur de nœudque nous utilisons pour gérer nos nœuds, nœud d'index 1. Méthode Installer renverra un conteneur contenant des pointeurs vers toutes les applications (dans ce cas, une, puisque nous avons passé un anonyme Conteneur de nœud, contenant un nœud) créé par l'assistant.

Les applications doivent spécifier quand commencer à générer du trafic "Démarrer" et il peut être nécessaire de spécifier en outre une heure à laquelle l'arrêter "arrêter". Nous proposons les deux options. Ces horaires sont fixés selon les méthodes ApplicationContainerApplicationContainer Accueil и Arrêter. Ces méthodes acceptent des paramètres de type Temps. Dans ce cas, nous utilisons une séquence explicite de conversions C++ pour prendre C++ double 1.0 et convertissez-le en un objet tns-3 Time qui utilise l'objet Seconds pour le convertir en secondes. N'oubliez pas que les règles de conversion peuvent être contrôlées par l'auteur du modèle et que C++ a ses propres règles, vous ne pouvez donc pas toujours compter sur la conversion des paramètres comme vous l'espériez. Deux lignes

serverApps.Start (Seconds (1.0));
serverApps.Stop (Seconds (10.0));

entraînera le démarrage (l'activation automatique) de l'application Echo Server une seconde après le démarrage de la simulation et l'arrêt (l'extinction) après dix secondes de simulation. Du fait que nous avons déclaré un événement de simulation (événement d'arrêt de l'application), qui sera exécuté dans dix secondes, au moins dix secondes de fonctionnement du réseau seront simulées.

UdpEchoClientHelperUdpEchoClientHelper

Demande client echo configuré d'une manière presque similaire au serveur. Il existe un objet de base UdpEchoClientApplicationUdpEchoClientApplication, qui est géré
UdpEchoClientHelperUdpEchoClientHelper.

UdpEchoClientHelper echoClient (interfaces.GetAddress (1), 9);
echoClient.SetAttribute ("MaxPackets", UintegerValue (1));
echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.0)));
echoClient.SetAttribute ("PacketSize", UintegerValue (1024));

ApplicationContainer clientApps = echoClient.Install (nodes.Get (0));
clientApps.Start (Seconds (2.0));
clientApps.Stop (Seconds (10.0));;

Cependant, pour le client echo, nous devons définir cinq attributs différents. Les deux premiers attributs sont définis au moment de la création UdpEchoClientHelperUdpEchoClientHelper. Nous transmettons les paramètres qui sont utilisés (à l'intérieur de l'assistant) pour définir les attributs "Adresse distante" и "Port distant" conformément à notre accord pour transmettre les paramètres nécessaires au constructeur assistant.

Rappelons que nous avons utilisé Conteneur d'interface IPv4 pour suivre les adresses IP que nous avons attribuées à nos appareils. L'interface nulle dans le conteneur d'interfaces correspondra à l'adresse IP du nœud nul dans le conteneur de nœuds. La première interface du conteneur d'interfaces correspond à l'adresse IP du premier nœud du conteneur de nœuds. Ainsi, dans la première ligne de code (ci-dessus), nous créons un assistant et lui disons que l'adresse distante du client sera l'adresse IP attribuée à l'hôte où se trouve le serveur. Nous disons également que nous devons faire en sorte que les paquets soient envoyés au port neuf.

L'attribut "MaxPackets" indique au client le nombre maximum de paquets que nous pouvons envoyer pendant la simulation. L'attribut "Intervalle" indique au client combien de temps attendre entre les paquets, et l'attribut "PacketSize" indique au client la taille de la charge utile du paquet. Avec cette combinaison d'attributs, nous demandons au client d'envoyer un seul paquet de 1024 octets.

Comme pour le serveur echo, nous définissons les attributs du client echo Accueil и Arrêter, mais ici on démarre le client une seconde après la mise sous tension du serveur (deux secondes après le début de la simulation).

4.2.8 Simulateur

À ce stade, nous devons exécuter la simulation. Cela se fait en utilisant la fonction globale Simulateur :: Exécuter.

Simulator::Run ();

Lorsque nous appelions précédemment les méthodes,

serverApps.Start (Seconds (1.0));
serverApps.Stop (Seconds (10.0));
... 
clientApps.Start (Seconds (2.0));
clientApps.Stop (Seconds (10.0));

nous avons en fait programmé des événements dans le simulateur à 1,0 seconde, 2,0 secondes et deux événements à 10,0 secondes. Après l'appel Simulateur :: Exécuter, le système commencera à afficher la liste des événements programmés et à les exécuter. Il déclenchera d'abord un événement après 1,0 seconde, ce qui déclenchera l'application du serveur d'écho (cet événement peut à son tour planifier de nombreux autres événements). Il déclenchera ensuite un événement programmé à t = 2,0 secondes qui lancera l'application client echo. Encore une fois, cet événement pourrait avoir de nombreux autres événements prévus. L'implémentation de l'événement de démarrage dans le client echo commencera la phase de transfert de données de la simulation en envoyant un paquet au serveur.

L'acte d'envoyer un paquet au serveur déclenchera une chaîne d'événements qui seront automatiquement programmés en coulisses et qui mettront en œuvre les mécanismes d'envoi d'un paquet d'écho selon les paramètres de timing que nous avons définis dans le script.

En conséquence, puisque nous envoyons un seul paquet (rappelez-vous, l'attribut MaxPaquets était défini sur un), la chaîne d'événements initiée par ce ping client unique se terminera et la simulation passera en mode veille. Une fois que cela se produit, les événements programmés restants seront les événements Arrêter pour le serveur et le client. Lorsque ces événements sont exécutés, il ne reste plus aucun événement pour un traitement ultérieur et Simulateur :: Exécuter reprendra le contrôle. La simulation est terminée.

Il ne reste plus qu'à nettoyer après vous. Cela se fait en appelant la fonction globale Simulateur :: Détruire. Parce que les fonctions d'assistance (ou code ns-3 de bas niveau) ont été appelées, qui sont organisées de manière à ce que des hooks soient insérés dans le simulateur pour détruire tous les objets créés. Vous n'aviez pas besoin de suivre vous-même ces objets : il vous suffisait d'appeler Simulateur :: Détruire et sors. Le système ns-3 fera ce travail difficile à votre place. Les lignes restantes de notre premier script ns-3, first.cc, font exactement cela :

Simulator::Destroy ();
return 0;
}

Quand le simulateur s’arrêtera-t-il ?

ns-3 est un simulateur d'événements discrets (DE). Dans un tel simulateur, chaque événement est associé à son temps d'exécution, et la simulation se poursuit en traitant les événements dans l'ordre dans lequel ils surviennent au fur et à mesure de la progression de la simulation. Les événements peuvent entraîner la planification d'événements futurs (par exemple, un minuteur peut se reprogrammer pour terminer le décompte dans l'intervalle suivant).

Les événements initiaux sont généralement initiés par l'entité, par exemple IPv6 planifiera la découverte des services sur le réseau, les requêtes des voisins, etc. L'application planifie le premier événement d'envoi de paquets, et ainsi de suite. Lorsqu'un événement est traité, il peut générer zéro, un ou plusieurs événements. Au fur et à mesure que la simulation progresse, des événements se produisent, soit en mettant fin, soit en créant de nouveaux. La simulation s'arrêtera automatiquement si la file d'attente des événements est vide ou si un événement spécial est détecté Arrêter. Événement Arrêter généré par la fonction Simulateur :: Arrêter (temps d'arrêt).

Il existe un cas typique où Simulator::Stop est absolument nécessaire pour arrêter la simulation : lorsqu'il y a des événements auto-entretenus. Les événements autonomes (ou répétitifs) sont des événements qui sont toujours reprogrammés. En conséquence, ils gardent toujours la file d’attente des événements non vide. Il existe de nombreux protocoles et modules contenant des événements répétitifs, par exemple :

• FlowMonitor - vérification périodique des paquets perdus ;

• RIPng – diffusion périodique des mises à jour des tables de routage ;

• etc.

Dans ces cas Simulateur :: Arrêter nécessaire pour arrêter correctement la simulation. De plus, lorsque ns-3 est en mode émulation, le RealtimeSimulator est utilisé pour synchroniser l'horloge de simulation avec l'horloge de la machine, et Simulateur :: Arrêter nécessaire d’arrêter le processus.

De nombreux programmes de simulation du manuel n'appellent pas Simulateur :: Arrêter explicitement, puisqu'ils se terminent automatiquement lorsque les événements en file d'attente sont épuisés. Cependant, ces programmes accepteront également l’appel Simulator::Stop. Par exemple, l'instruction supplémentaire suivante dans le premier exemple de programme programmerait un arrêt explicite à 11 secondes :

+ Simulator::Stop (Seconds (11.0));
  Simulator::Run ();
  Simulator::Destroy ();
  return 0;
}

Ce qui précède ne changera pas réellement le comportement de ce programme, puisque cette simulation particulière se termine naturellement après 10 secondes. Mais si vous deviez modifier le temps d'arrêt dans l'instruction ci-dessus de 11 secondes à 1 seconde, vous remarquerez que la simulation s'arrête avant qu'une sortie n'atteigne l'écran (puisque la sortie se produit après environ 2 secondes de temps de simulation).

Il est important d’appeler Simulator::Stop avant d’appeler Simulator::Run ; sinon Simulator::Run risque de ne jamais rendre le contrôle au programme principal pour exécuter l'arrêt !

4.2.9 Construire votre script

Nous avons rendu la création de vos scripts simples triviale. Tout ce que vous avez à faire est de mettre votre script dans le répertoire scratch et il sera automatiquement construit si vous exécutez Waf. Essayons. Revenez au répertoire de niveau supérieur et copiez exemples/tutoriel/first.cc cataloguer gratter

$ cd ../.. 
$ cp examples/tutorial/first.cc scratch/myfirst.cc

Créez maintenant votre premier exemple de script en utilisant waf:

$ ./waf

Vous devriez voir des messages indiquant que votre premier exemple a été créé avec succès.

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
[614/708] cxx: scratch/myfirst.cc -> build/debug/scratch/myfirst_3.o
[706/708] cxx_link: build/debug/scratch/myfirst_3.o -> build/debug/scratch/myfirst
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (2.357s)

Vous pouvez maintenant exécuter l'exemple (notez que si vous construisez votre programme dans le répertoire scratch, vous devez l'exécuter à partir de gratter):

$ ./waf --run scratch/myfirst

Vous devriez voir un résultat similaire :

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.418s) Sent 1024 bytes to 10.1.1.2
Received 1024 bytes from 10.1.1.1
Received 1024 bytes from 10.1.1.2

Ici, vous pouvez voir que le système de build vérifie que le fichier a été construit puis l'exécute. Vous voyez l'entrée du composant sur le client Echo indique qu'il a envoyé un seul paquet de 1024 10.1.1.2 octets au serveur Echo 1024. Vous voyez également le composant de journalisation sur le serveur d'écho pour indiquer qu'il a reçu 10.1.1.1 octets de XNUMX. Le serveur d'écho relit le paquet en silence et vous pouvez voir dans le journal du client d'écho qu'il a reçu son paquet du serveur.

4.3 ns-3Code source

Maintenant que vous avez utilisé certains des assistants ns-3, vous pouvez jeter un œil à une partie du code source qui implémente cette fonctionnalité. Le dernier code peut être consulté sur notre serveur Web au lien suivant : https://gitlab.com/nsnam/ns-3-dev.git. Vous y verrez la page de résumé Mercurial de notre arbre de développement ns-3. En haut de la page, vous verrez plusieurs liens,

summary | shortlog | changelog | graph | tags | files

Allez-y et sélectionnez le lien des fichiers. Voici à quoi ressemblera le niveau supérieur de la plupart de nos référentiels :

drwxr-xr-x                               [up]
drwxr-xr-x                               bindings python  files
drwxr-xr-x                               doc              files
drwxr-xr-x                               examples         files
drwxr-xr-x                               ns3              files
drwxr-xr-x                               scratch          files
drwxr-xr-x                               src              files
drwxr-xr-x                               utils            files
-rw-r--r-- 2009-07-01 12:47 +0200 560    .hgignore        file | revisions | annotate
-rw-r--r-- 2009-07-01 12:47 +0200 1886   .hgtags          file | revisions | annotate
-rw-r--r-- 2009-07-01 12:47 +0200 1276   AUTHORS          file | revisions | annotate
-rw-r--r-- 2009-07-01 12:47 +0200 30961  CHANGES.html     file | revisions | annotate
-rw-r--r-- 2009-07-01 12:47 +0200 17987  LICENSE          file | revisions | annotate
-rw-r--r-- 2009-07-01 12:47 +0200 3742   README           file | revisions | annotate
-rw-r--r-- 2009-07-01 12:47 +0200 16171  RELEASE_NOTES    file | revisions | annotate
-rw-r--r-- 2009-07-01 12:47 +0200 6      VERSION          file | revisions | annotate
-rwxr-xr-x 2009-07-01 12:47 +0200 88110  waf              file | revisions | annotate
-rwxr-xr-x 2009-07-01 12:47 +0200 28     waf.bat          file | revisions | annotate
-rw-r--r-- 2009-07-01 12:47 +0200 35395  wscript          file | revisions | annotate
-rw-r--r-- 2009-07-01 12:47 +0200 7673   wutils.py        file | revisions | annotate

Nos exemples de scripts sont dans le répertoire exemples. Si vous cliquez sur les exemples, vous verrez une liste de sous-répertoires. Un des fichiers du sous-répertoire tutoriel - first.cc. Si vous cliquez sur premier.cc vous verrez le code que vous venez d'apprendre.

Le code source se trouve principalement dans le répertoire src. Vous pouvez afficher le code source en cliquant sur le nom du répertoire ou en cliquant sur le lien des fichiers à droite du nom du répertoire. Si vous cliquez sur le répertoire src, vous obtiendrez une liste des sous-répertoires src. Si vous cliquez ensuite sur le sous-répertoire principal, vous trouverez une liste de fichiers. Le premier fichier que vous verrez (au moment de la rédaction de ce guide) est abandonner.h. Si vous cliquez sur le lien abandonner.h, vous serez redirigé vers le fichier source pour abandonner.h, qui contient des macros utiles pour quitter les scripts si des conditions anormales sont détectées. Le code source des helpers que nous avons utilisés dans ce chapitre se trouve dans le répertoire src/Applications/aide. N'hésitez pas à parcourir l'arborescence des répertoires pour savoir où se trouve et comprendre le style des programmes ns-3.

Source: habr.com

Ajouter un commentaire