Englishfrançaisespagnol

Icône de favori OnWorks

ns-3-tutorial - En ligne dans le Cloud

Exécutez ns-3-tutorial dans le fournisseur d'hébergement gratuit OnWorks sur Ubuntu Online, Fedora Online, l'émulateur en ligne Windows ou l'émulateur en ligne MAC OS

Il s'agit de la commande ns-3-tutorial qui peut être exécutée dans le fournisseur d'hébergement gratuit OnWorks en utilisant l'un de nos multiples postes de travail en ligne gratuits tels que Ubuntu Online, Fedora Online, l'émulateur en ligne Windows ou l'émulateur en ligne MAC OS

PROGRAMME:

Nom


Tutoriel ns-3 - Tutoriel ns-3

Il s'agit de la ns-3 Tutoriel. La documentation principale du projet ns-3 est disponible en cinq
formes:

· ns-3 doxygen: Documentation des API publiques du simulateur

· Didacticiel (ce document), Manuel et Bibliothèque de modèles pour le derniers libérer et votre
développant arbre

· ns-3 wiki

Ce document est rédigé en Texterestructuré pour Sphinx et est maintenu dans le
doc/tutoriel répertoire du code source de ns-3.

INTRODUCTION


Notre ns-3 Le simulateur est un simulateur de réseau à événements discrets destiné principalement à la recherche
et l'utilisation pédagogique. Les ns-3 Projet, démarré en 2006, est un projet open source
développement ns-3.

Le but de ce tutoriel est d'introduire de nouveaux ns-3 utilisateurs au système de manière structurée
manière. Il est parfois difficile pour les nouveaux utilisateurs de glaner des informations essentielles à partir de
manuels et de convertir ces informations en simulations de travail. Dans ce tutoriel, nous
construira plusieurs exemples de simulations, introduisant et expliquant les concepts clés et
fonctionnalités au fur et à mesure.

Au fur et à mesure du déroulement du didacticiel, nous présenterons le ns-3 documentation et fournir
des pointeurs vers le code source pour ceux qui souhaitent approfondir le fonctionnement du
système.

Quelques points clés méritent d'être notés au début :

· ns-3 est open-source, et le projet s'efforce de maintenir un environnement ouvert pour
chercheurs à contribuer et à partager leurs logiciels.

· ns-3 n'est pas une extension rétrocompatible de ns-2; c'est un nouveau simulateur. Les deux
les simulateurs sont tous deux écrits en C++ mais ns-3 est un nouveau simulateur qui ne prend pas en charge le
ns-2 Apis. Certains modèles de ns-2 ont déjà été portés depuis ns-2 à ns-3L’
le projet continuera à maintenir ns-2 tout en ns-3 est en cours de construction et étudiera
mécanismes de transition et d'intégration.

À propos ns-3
ns-3 a été développé pour fournir une plate-forme de simulation de réseau ouverte et extensible, pour
recherche et éducation en réseau. En bref, ns-3 fournit des modèles de la façon dont les données par paquets
les réseaux fonctionnent et fonctionnent, et fournit un moteur de simulation pour les utilisateurs
expériences de simulation. Certaines des raisons d'utiliser ns-3 inclure pour effectuer des études qui
sont plus difficiles ou impossibles à réaliser avec des systèmes réels, pour étudier le comportement du système
dans un environnement hautement contrôlé et reproductible, et d'apprendre comment fonctionnent les réseaux.
Les utilisateurs remarqueront que le modèle disponible défini dans ns-3 se concentre sur la modélisation de la façon dont Internet
les protocoles et les réseaux fonctionnent, mais ns-3 ne se limite pas aux systèmes Internet ; plusieurs utilisateurs
utilisent ns-3 pour modéliser des systèmes non basés sur Internet.

De nombreux outils de simulation existent pour les études de simulation de réseau. Ci-dessous quelques
traits distinctifs de ns-3 contrairement à d'autres outils.

· ns-3 est conçu comme un ensemble de bibliothèques qui peuvent être combinées entre elles et aussi avec d'autres
bibliothèques de logiciels externes. Alors que certaines plates-formes de simulation offrent aux utilisateurs un
environnement d'interface utilisateur graphique unique et intégré dans lequel toutes les tâches sont effectuées
Départ, ns-3 est plus modulaire à cet égard. Plusieurs animateurs externes et analyse de données
et les outils de visualisation peuvent être utilisés avec ns-3. Cependant, les utilisateurs doivent s'attendre à travailler à
la ligne de commande et avec les outils de développement logiciel C++ et/ou Python.

· ns-3 est principalement utilisé sur les systèmes Linux, bien qu'il existe un support pour FreeBSD, Cygwin
(pour Windows) et la prise en charge native de Windows Visual Studio est en train d'être
développé.

· ns-3 n'est un produit logiciel officiellement pris en charge par aucune entreprise. Soutien ns-3
se fait au mieux sur la liste de diffusion ns-3-users.

Pour ns-2 Utilisateurs
Pour ceux qui connaissent ns-2 (un outil populaire qui a précédé ns-3), le plus visible vers l'extérieur
changer lors du passage à ns-3 est le choix du langage de script. Programmes en ns-2 are
scripté dans OTcl et les résultats des simulations peuvent être visualisés à l'aide de Network Animator
nom. Il n'est pas possible d'exécuter une simulation dans ns-2 purement à partir de C++ (c'est-à-dire en tant que main()
programme sans OTcl). De plus, certains composants de ns-2 sont écrits en C++ et
d'autres en OTcl. Dans ns-3, le simulateur est entièrement écrit en C++, avec Python en option
reliures. Les scripts de simulation peuvent donc être écrits en C++ ou en Python. Nouveaux animateurs
et des visualiseurs sont disponibles et en cours de développement. Depuis ns-3 génère pcap
fichiers de trace de paquets, d'autres utilitaires peuvent également être utilisés pour analyser les traces. Dans ce
tutoriel, nous allons d'abord nous concentrer sur le scriptage directement en C++ et l'interprétation des résultats
via des fichiers de trace.

Mais il y a aussi des similitudes (tous deux, par exemple, sont basés sur des objets C++, et certains
code de ns-2 a déjà été porté sur ns-3). Nous essaierons de mettre en évidence les différences
jusqu'à XNUMX fois ns-2 et votre ns-3 au fur et à mesure que nous procédons dans ce tutoriel.

Une question que l'on entend souvent est « Dois-je encore utiliser ns-2 ou déménager à ns-3?" Dans ce
l'opinion de l'auteur, à moins que l'utilisateur ne soit d'une manière ou d'une autre ns-2 (soit sur la base de l'existant
confort personnel et connaissance de ns-2, ou sur la base d'un modèle de simulation spécifique qui
est uniquement disponible dans ns-2), un utilisateur sera plus productif avec ns-3 pour la suite
les raisons:

· ns-3 est activement maintenu avec une liste de diffusion d'utilisateurs actifs et réactifs, tandis que ns-2 is
seulement légèrement maintenu et n'a pas vu de développement significatif dans son arbre de code principal
pour plus d'une décennie.

· ns-3 fournit des fonctionnalités non disponibles dans ns-2, comme une exécution de code d'implémentation
environnement (permettant aux utilisateurs d'exécuter du code d'implémentation réel dans le simulateur)

· ns-3 fournit un niveau d'abstraction de base inférieur à celui de ns-2, lui permettant d'aligner
mieux avec la façon dont les systèmes réels sont assemblés. Certaines limites trouvées dans ns-2 (Tels que
prenant en charge plusieurs types d'interfaces sur les nœuds correctement) ont été corrigés dans ns-3.

ns-2 a un ensemble plus diversifié de modules contribués que ns-3, en raison de sa longue
l'histoire. Cependant, ns-3 a des modèles plus détaillés dans plusieurs domaines de recherche populaires
(y compris les modèles LTE et WiFi sophistiqués) et sa prise en charge du code d'implémentation
admet un spectre très large de modèles haute-fidélité. Les utilisateurs peuvent être surpris d'apprendre que
l'ensemble de la pile réseau Linux peut être encapsulé dans un ns-3 nœud, en utilisant le Direct
Cadre d'exécution de code (DCE). ns-2 les modèles peuvent parfois être portés vers ns-3, En particulier
s'ils ont été implémentés en C++.

En cas de doute, une bonne ligne de conduite serait de regarder les deux simulateurs (ainsi que d'autres
simulateurs), et en particulier les modèles disponibles pour vos recherches, mais gardez à l'esprit
que votre expérience peut être meilleure dans l'utilisation de l'outil qui est activement développé et
entretenu (ns-3).

Contribuer
ns-3 est un simulateur de recherche et d'enseignement, par et pour la communauté des chercheurs. Ce sera
compter sur les contributions continues de la communauté pour développer de nouveaux modèles, déboguer ou
maintenir celles existantes et partager les résultats. Il y a quelques politiques qui, nous l'espérons,
encourager les gens à contribuer à ns-3 comme ils l'ont fait pour ns-2:

· Licences open source basées sur la compatibilité GNU GPLv2

· wiki

· Contribution Code page, semblable à ns-2Code de contribution populaire de page

· Ouvert bug traqueur

Nous réalisons que si vous lisez ce document, contribuer au projet est
probablement pas votre principale préoccupation à ce stade, mais nous voulons que vous sachiez que
contribuer est dans l'esprit du projet et que même le fait de nous laisser une note
sur votre première expérience avec ns-3 (par exemple "cette section de tutoriel n'était pas claire..."),
les rapports de documentation périmée, etc. sont très appréciés.

Tutoriel Nom de l'entreprise
Le didacticiel suppose que les nouveaux utilisateurs peuvent initialement suivre un chemin tel que le suivant :

· Essayez de télécharger et de créer une copie ;

· Essayez d'exécuter quelques exemples de programmes ;

· Regardez la sortie de la simulation et essayez de l'ajuster.

En conséquence, nous avons essayé d'organiser le didacticiel le long des grandes séquences ci-dessus de
événements.

RESSOURCES


Notre Site web
Il existe plusieurs ressources importantes dont toute ns-3 l'utilisateur doit être au courant. La toile principale
le site est situé à http://www.nsnam.org et donne accès à des informations de base sur les
ns-3 système. Une documentation détaillée est disponible sur le site Web principal à l'adresse
http://www.nsnam.org/documentation/. Vous pouvez également trouver des documents relatifs au système
architecture de cette page.

Il existe un wiki qui complète le principal ns-3 site internet que vous trouverez sur
http://www.nsnam.org/wiki/. Vous y trouverez des FAQ utilisateurs et développeurs, ainsi que
guides de dépannage, code fourni par des tiers, documents, etc.

Le code source peut être trouvé et consulté sur http://code.nsnam.org/. Là vous trouverez
l'arbre de développement actuel dans le référentiel nommé ns-3-dev. Les versions antérieures et
des référentiels expérimentaux des principaux développeurs peuvent également y être trouvés.

Mercuriel
Les systèmes logiciels complexes ont besoin d'un moyen de gérer l'organisation et les modifications apportées au
le code et la documentation sous-jacents. Il existe de nombreuses façons d'accomplir cet exploit, et vous pouvez
ont entendu parler de certains des systèmes qui sont actuellement utilisés pour ce faire. Le concurrent
Version System (CVS) est probablement le plus connu.

Notre ns-3 projet utilise Mercurial comme système de gestion de code source. Bien que vous ne
besoin d'en savoir plus sur Mercurial pour terminer ce tutoriel, nous vous recommandons
se familiariser avec Mercurial et l'utiliser pour accéder au code source. Mercurial a un
site web à http://www.selenic.com/mercurial/, à partir duquel vous pouvez obtenir binaire ou source
versions de ce système de gestion de la configuration logicielle (SCM). Selenic (le développeur
of Mercurial) propose également un tutoriel sur
http://www.selenic.com/mercurial/wiki/index.cgi/Tutorial/, et un guide de démarrage rapide sur
http://www.selenic.com/mercurial/wiki/index.cgi/QuickStart/.

Vous pouvez également trouver des informations vitales sur l'utilisation de Mercurial et ns-3 sur le principal ns-3 web
site.

Waf
Une fois que vous avez téléchargé le code source sur votre système local, vous devrez le compiler
source pour produire des programmes utilisables. Tout comme dans le cas de la gestion du code source, il
sont de nombreux outils disponibles pour effectuer cette fonction. Probablement le plus connu d'entre eux
des outils est a prendre une. En plus d'être le plus connu, a prendre une est probablement le plus difficile
à utiliser dans un système très vaste et hautement configurable. Pour cette raison, de nombreuses alternatives
a été développé. Récemment, ces systèmes ont été développés en utilisant le Python
la langue.

Le système de construction Waf est utilisé sur le ns-3 projet. Il fait partie de la nouvelle génération de
Systèmes de construction basés sur Python. Vous n'aurez pas besoin de comprendre Python pour construire le
existant ns-3 système.

Pour ceux qui s'intéressent aux détails sanglants du Waf, le site Web principal se trouve à l'adresse
http://code.google.com/p/waf/.

Développement Environnement
Comme mentionné ci-dessus, les scripts dans ns-3 se fait en C++ ou Python. La plupart ns-3 L'API est
disponible en Python, mais les modèles sont écrits en C++ dans les deux cas. Un travail
la connaissance du C++ et des concepts orientés objet est supposée dans ce document. Nous prendrons
un peu de temps pour revoir certains des concepts les plus avancés ou un langage éventuellement inconnu
caractéristiques, expressions idiomatiques et modèles de conception tels qu'ils apparaissent. Nous ne voulons pas que ce tutoriel
se transformer en un didacticiel C++, nous nous attendons donc à une maîtrise de base du langage.
Il existe un nombre presque inimaginable de sources d'informations sur le C++ disponibles sur le
Web ou imprimé.

Si vous débutez en C++, vous souhaiterez peut-être trouver un livre ou un site Web basé sur un didacticiel ou un livre de recettes.
et travaillez au moins sur les caractéristiques de base de la langue avant de continuer. Pour
exemple, ceci. tutoriel.

Notre ns-3 système utilise plusieurs composants de la "chaîne d'outils" GNU pour le développement. UNE
La chaîne d'outils logiciels est l'ensemble des outils de programmation disponibles dans l'environnement donné. Pour
un examen rapide de ce qui est inclus dans la chaîne d'outils GNU voir,
http://en.wikipedia.org/wiki/GNU_toolchain. ns-3 utilise gcc, GNU binutils et gdb.
Cependant, nous n'utilisons pas les outils du système de compilation GNU, ni make ni autotools. Nous utilisons Waf
pour ces fonctions.

Typiquement un ns-3 l'auteur travaillera sous Linux ou dans un environnement similaire à Linux. Pour ceux
fonctionnant sous Windows, il existe des environnements qui simulent l'environnement Linux pour
divers degrés. Les ns-3 projet a dans le passé (mais pas actuellement) soutenu
développement dans l'environnement Cygwin pour ces utilisateurs. Voir http://www.cygwin.com/ pour
détails sur le téléchargement, et visitez le ns-3 wiki pour plus d'informations sur Cygwin et
ns-3. MinGW n'est actuellement pas officiellement pris en charge. Une autre alternative à Cygwin est de
installer un environnement de machine virtuelle tel qu'un serveur VMware et installer une machine virtuelle Linux
machine.

Douille Programmation
Nous supposerons une facilité de base avec l'API Berkeley Sockets dans les exemples utilisés dans ce
Didacticiel. Si vous êtes nouveau sur les sockets, nous vous recommandons de revoir l'API et certaines utilisations courantes
cas. Pour une bonne vue d'ensemble de la programmation des sockets TCP/IP, nous vous recommandons TCP / IP sockets in
C, Donahoo et votre Calvert.

Il existe un site Web associé qui inclut la source des exemples du livre, qui
vous pouvez trouver sur : http://cs.baylor.edu/~donahoo/practical/CSockets/.

Si vous comprenez les quatre premiers chapitres du livre (ou pour ceux qui n'ont pas accès
à une copie du livre, les clients et serveurs d'écho indiqués sur le site Web ci-dessus), vous
être en forme pour comprendre le tuto. Il existe un livre similaire sur la multidiffusion
Douilles Multicast Douilles Makofské et votre Almeroth. qui couvre le matériel dont vous pourriez avoir besoin
comprendre si vous regardez les exemples de multidiffusion dans la distribution.

OBTENIR A DÉBUTÉ


Cette section vise à amener un utilisateur à un état de fonctionnement en commençant par une machine qui
n'a peut-être jamais eu ns-3 installée. Il couvre les plates-formes prises en charge, les conditions préalables, les moyens de
obtenir ns-3, façons de construire ns-3, et des moyens de vérifier votre build et d'exécuter des programmes simples.

Aperçu
ns-3 est construit comme un système de bibliothèques logicielles qui fonctionnent ensemble. Les programmes utilisateur peuvent être
écrit qui se lie avec (ou importe à partir de) ces bibliothèques. Les programmes utilisateur sont écrits en
soit les langages de programmation C++ ou Python.

ns-3 est distribué en tant que code source, ce qui signifie que le système cible doit disposer d'un
environnement de développement logiciel pour créer d'abord les bibliothèques, puis créer l'utilisateur
. ns-3 pourraient en principe être distribués sous forme de bibliothèques pré-construites pour
systèmes, et à l'avenir, il peut être distribué de cette façon, mais à l'heure actuelle, de nombreux utilisateurs
font réellement leur travail en éditant ns-3 lui-même, donc avoir le code source à reconstruire
les bibliothèques sont utiles. Si quelqu'un souhaite entreprendre le travail de fabrication de pré-construits
bibliothèques et packages pour les systèmes d'exploitation, veuillez contacter le mailing ns-developers
liste.

Dans ce qui suit, nous examinerons deux façons de télécharger et de créer ns-3. Le premier est
pour télécharger et créer une version officielle à partir du site Web principal. La seconde est d'aller chercher
et créer des copies de développement de ns-3. Nous allons parcourir les deux exemples puisque les outils
impliqués sont légèrement différents.

Téléchargement ns-3
Notre ns-3 le système dans son ensemble est un système assez complexe et a un certain nombre de dépendances sur
autres composants. En plus des systèmes avec lesquels vous aurez probablement affaire tous les jours (le
chaîne d'outils GNU, Mercurial, un éditeur de texte), vous devrez vous assurer qu'un certain nombre de
des bibliothèques supplémentaires sont présentes sur votre système avant de continuer. ns-3 fournit un wiki
page qui comprend des pages avec de nombreux conseils et astuces utiles. Une de ces pages est la
page "Installation", http://www.nsnam.org/wiki/Installation.

La section "Prérequis" de cette page wiki explique quels packages sont requis pour
prise en charge commune ns-3 options, et fournit également les commandes utilisées pour les installer pour
variantes courantes de Linux. Les utilisateurs de Cygwin devront utiliser le programme d'installation de Cygwin (si vous êtes un
utilisateur de Cygwin, vous l'avez utilisé pour installer Cygwin).

Vous voudrez peut-être profiter de cette occasion pour explorer les ns-3 wiki un peu car il y a vraiment
une mine d'informations là-bas.

A partir de maintenant, nous allons supposer que le lecteur travaille sous Linux ou un
Environnement d'émulation Linux (Linux, Cygwin, etc.) et la chaîne d'outils GNU est installée et
vérifiés ainsi que les prérequis mentionnés ci-dessus. Nous allons également supposer que
vous avez Mercurial et Waf installés et exécutés sur le système cible.

Notre ns-3 le code est disponible dans les dépôts Mercurial sur le serveur http://code.nsnam.org.
Vous pouvez également télécharger une version tarball sur http://www.nsnam.org/release/, ou vous pouvez travailler
avec des référentiels utilisant Mercurial. Nous vous recommandons d'utiliser Mercurial à moins qu'il n'y ait un bon
raison de ne pas le faire. Voir la fin de cette section pour des instructions sur la façon d'obtenir une archive tar
libérer.

La façon la plus simple de commencer à utiliser les référentiels Mercurial est d'utiliser le ns-3-allinone
environnement. Il s'agit d'un ensemble de scripts qui gère le téléchargement et la création de
divers sous-systèmes de ns-3 pour vous. Nous vous recommandons de commencer votre ns-3 travailler dans ce
environnement.

Une pratique consiste à créer un répertoire appelé espace de travail dans son répertoire personnel sous lequel
on peut conserver des dépôts Mercurial locaux. N'importe quel nom de répertoire fera l'affaire, mais nous supposerons
qui espace de travail est utilisé ici (remarque : repos peut également être utilisé dans certains documents comme
exemple de nom de répertoire).

Téléchargement ns-3 En utilisant a archiver
Une archive tar est un format particulier d'archive de logiciel où plusieurs fichiers sont regroupés
ensemble et l'archive éventuellement compressée. ns-3 les versions logicielles sont fournies via un
tarball téléchargeable. Le processus de téléchargement ns-3 via tarball est simple; tu viens de
devez choisir une version, la télécharger et la décompresser.

Supposons que vous, en tant qu'utilisateur, souhaitez créer ns-3 dans un répertoire local appelé
espace de travail. Si vous adoptez le espace de travail approche par répertoire, vous pouvez obtenir une copie d'une version
en tapant ce qui suit dans votre shell Linux (remplacez les numéros de version appropriés,
bien sûr):

$ cd
$ mkdir espace de travail
$ cd espace de travail
$ wget http://www.nsnam.org/release/ns-allinone-3.22.tar.bz2
$ tar xjf ns-allinone-3.22.tar.bz2

Si vous changez dans le répertoire ns-allinone-3.22 vous devriez voir un certain nombre de fichiers :

$ls
Bake constants.py ns-3.22 README
build.py netanim-3.105 pybindgen-0.16.0.886 util.py

Vous êtes maintenant prêt à construire la base ns-3 distribution.

Téléchargement ns-3 En utilisant Cuire
Bake est un outil d'intégration et de construction distribués, développé pour le ns-3 .
Bake peut être utilisé pour récupérer les versions de développement du ns-3 logiciel, et pour télécharger et
construire des extensions à la base ns-3 distribution, telle que l'exécution directe du code
environnement, Network Simulation Cradle, possibilité de créer de nouvelles liaisons Python, etc.

Au cours des dernières ns-3 versions, Bake a été inclus dans l'archive de la version. La config
fichier inclus dans la version publiée permettra de télécharger tout logiciel qui a été
courant au moment de la sortie. C'est, par exemple, la version de Bake qui est
distribué avec le ns-3.21 release peut être utilisé pour récupérer des composants pour cela ns-3 libérer
ou antérieure, mais ne peut pas être utilisé pour récupérer des composants pour des versions ultérieures (à moins que le
bakeconf.xml fichier est mis à jour).

Vous pouvez également obtenir la copie la plus récente de cuire en tapant ce qui suit dans votre Linux
shell (en supposant que vous ayez installé Mercurial):

$ cd
$ mkdir espace de travail
$ cd espace de travail
$ hg clone http://code.nsnam.org/bake

Au fur et à mesure que la commande hg (Mercurial) s'exécute, vous devriez voir quelque chose comme ce qui suit
affiché,


répertoire de destination : cuire
demander toutes les modifications
ajout d'ensembles de modifications
ajout de manifestes
ajout de modifications de fichier
ajouté 339 ensembles de modifications avec 796 modifications apportées à 63 fichiers
mise à jour vers la branche par défaut
45 fichiers mis à jour, 0 fichiers fusionnés, 0 fichiers supprimés, 0 fichiers non résolus

Une fois la commande clone terminée, vous devriez avoir un répertoire appelé cuire, les contenus
qui devrait ressembler à ce qui suit :

$ls
bake bakeconf.xml doc generate-binary.py TODO
test d'exemples de bake.py

Notez que vous venez vraiment de télécharger des scripts Python et un module Python appelé
cuire. La prochaine étape consistera à utiliser ces scripts pour télécharger et créer le ns-3
diffusion de votre choix.

Il existe quelques cibles de configuration disponibles :

1. ns-3.22: le module correspondant à la version ; il téléchargera des composants similaires
à l'archive de publication.

2. ns-3-dev: un module similaire mais utilisant l'arbre de code de développement

3. ns-allinone-3.22: le module qui inclut d'autres fonctionnalités optionnelles telles que le clic
routage, openflow pour ns-3, et le berceau de simulation de réseau

4. ns-3-allinone: similaire à la version publiée du module allinone, mais pour
code de développement.

L'instantané de développement actuel (non publié) de ns-3 peut être trouvé à
http://code.nsnam.org/ns-3-dev/. Les développeurs tentent de conserver ces référentiels dans
états cohérents et fonctionnels, mais ils sont dans une zone de développement avec du code non publié
présent, vous pouvez donc envisager de rester avec une version officielle si vous n'avez pas besoin
fonctionnalités nouvellement introduites.

Vous pouvez trouver la dernière version du code soit en inspectant la liste des référentiels
ou en allant au "ns-3 Sorties" page Web et en cliquant sur le lien de la dernière version.
Nous allons procéder dans cet exemple de tutoriel avec ns-3.22.

Nous allons maintenant utiliser l'outil de cuisson pour faire descendre les différents morceaux de ns-3 vous serez
à l'aide de. Tout d'abord, nous allons dire un mot sur l'exécution de bake.

bake fonctionne en téléchargeant les packages sources dans un répertoire source et en installant
bibliothèques dans un répertoire de construction. bake peut être exécuté en référençant le binaire, mais si l'on
choisit d'exécuter bake depuis l'extérieur du répertoire dans lequel il a été téléchargé, il est conseillé
pour mettre bake dans votre chemin, comme suit (exemple de shell bash Linux). Tout d'abord, changez
dans le répertoire 'bake', puis définissez les variables d'environnement suivantes

$ export BAKE_HOME=`mot de passe`
$ export PATH=$PATH:$BAKE_HOME:$BAKE_HOME/build/bin
$ export PYTHONPATH=$PYTHONPATH:$BAKE_HOME:$BAKE_HOME/build/lib

Cela mettra le programme bake.py dans le chemin du shell et permettra à d'autres programmes de
trouver des exécutables et des bibliothèques créés par bake. Bien que plusieurs cas d'utilisation de la cuisson ne
nécessitent de définir PATH et PYTHONPATH comme ci-dessus, des versions complètes de ns-3-allinone (avec le
packages facultatifs) le font généralement.

Entrez dans le répertoire de l'espace de travail et tapez ce qui suit dans votre shell :

$ ./bake.py configurer -e ns-3.22

Ensuite, nous demanderons à bake de vérifier si nous avons suffisamment d'outils pour télécharger divers composants.
Type :

$ ./bake.py chèque

Vous devriez voir quelque chose comme ce qui suit,

> Python - D'accord
> Compilateur GNU C++ - OK
> Mercuriel - OK
> CVS - OK
> GIT - OK
> Bazar - OK
> Outil de goudron - OK
> Outil de décompression - OK
> Outil Unrar - est manquant
> Utilitaire de compression de données 7z - OK
> Utilitaire de compression de données XZ - OK
> Faire - OK
> cMake - OK
> outil de patch - OK
> outil d'autoreconf - OK

> Chemin recherché pour les outils : /usr/lib64/qt-3.3/bin /usr/lib64/ccache
/ usr / local / bin / bin / usr / bin / usr / local / sbin / usr / sbin / sbin
/home/tomh/bin bin

En particulier, les outils de téléchargement tels que Mercurial, CVS, GIT et Bazaar sont nos principaux
préoccupations à ce stade, car ils nous permettent de récupérer le code. Veuillez installer manquant
outils à ce stade, de la manière habituelle pour votre système (si vous en êtes capable), ou contactez
votre administrateur système si nécessaire pour installer ces outils.

Ensuite, essayez de télécharger le logiciel :

$ ./bake.py télécharger

devrait donner quelque chose comme:

>> Recherche de dépendances système pygoocanvas - OK
>> Recherche de dépendances système python-dev - OK
>> Recherche de dépendances système pygraphviz - OK
>> Téléchargement de pybindgen-0.16.0.886 - OK
>> Recherche de dépendances système g++ - OK
>> Recherche de dépendances système qt4 - OK
>> Téléchargement de netanim-3.105 - OK
>> Téléchargement ns-3.22 - OK

Ce qui précède suggère que trois sources ont été téléchargées. Vérifier la source annuaire
maintenant et tapez ls; il faut voir :

$ls
netanim-3.105 ns-3.22 pybindgen-0.16.0.886

Vous êtes maintenant prêt à construire le ns-3 distribution.

Développement ns-3
Développement avec build.py
Lorsque vous travaillez à partir d'un tarball publié, la première fois que vous construisez le ns-3 projet, vous pouvez
construire en utilisant un programme pratique trouvé dans le allinone annuaire. Ce programme s'appelle
build.py. Ce programme obtiendra le projet configuré pour vous dans le plus souvent
manière utile. Cependant, veuillez noter qu'une configuration plus avancée et un travail avec ns-3 sera
impliquent généralement l'utilisation du natif ns-3 système de build, Waf, qui sera introduit plus tard dans ce
tutoriel.

Si vous avez téléchargé à l'aide d'une archive tar, vous devriez avoir un répertoire appelé quelque chose comme
ns-allinone-3.22 sous votre ~/espace de travail annuaire. Tapez ce qui suit :

$ ./build.py --enable-examples --enable-tests

Parce que nous travaillons avec des exemples et des tests dans ce tutoriel, et parce qu'ils ne sont pas
construit par défaut dans ns-3, les arguments de build.py lui disent de les construire pour nous. Les
Par défaut, le programme construit également tous les modules disponibles. Plus tard, vous pouvez construire ns-3
sans exemples et tests, ou éliminer les modules qui ne sont pas nécessaires à votre travail,
si vous le souhaitez.

Vous verrez de nombreux messages de sortie du compilateur typiques affichés au fur et à mesure que le script de construction se construit
les différents morceaux que vous avez téléchargés. Finalement, vous devriez voir ce qui suit :

Waf : quitter le répertoire `/path/to/workspace/ns-allinone-3.22/ns-3.22/build'
'construction' terminée avec succès (6m25.032s)

Modules construits :
antenne aodv applications
bâtiments de pont config-store
noyau csma csma-layout
dsdv dsr énergie
fd-net-device flux-moniteur internet
maille lr-wpan lte
mobilité mpi netanim (pas de Python)
réseau nix-vector-routing olsr
propagation de disposition point à point point à point
statistiques du spectre sixlowpan
test de tap-bridge (pas de Python) lecture de topologie
une vague de périphériques réseau virtuels
wifi wifi

Modules non construits (voir tutoriel ns-3 pour explication):
brite cliquez sur openflow
visualiseur

Quitter le répertoire `./ns-3.22'

Concernant la partie sur les modules non construits :

Modules non construits (voir tutoriel ns-3 pour explication):
brite cliquez sur openflow
visualiseur

Cela signifie simplement que certains ns-3 les modules qui ont des dépendances sur des bibliothèques externes peuvent ne pas
ont été construits, ou que la configuration a spécifiquement demandé de ne pas les construire. Cela fait
ne signifie pas que le simulateur n'a pas été construit avec succès ou qu'il fournira de mauvais
résultats pour les modules répertoriés comme étant en cours de construction.

Développement avec cuire
Si vous avez utilisé bake ci-dessus pour récupérer le code source des référentiels de projet, vous pouvez continuer à
l'utiliser pour construire ns-3. Type

Construction de $ ./bake.py

et vous devriez voir quelque chose comme :

>> Construire pybindgen-0.16.0.886 - OK
>> Bâtiment netanim-3.105 - OK
>> Bâtiment ns-3.22 - OK

Allusion: vous vous aussi effectuer tous les deux pas, download et votre construire by appel 'cuire.py déployer'.

S'il y a un échec, veuillez regarder ce que dit la commande suivante
tu; cela peut donner un indice quant à une dépendance manquante :

$ ./bake.py spectacle

Cela listera les différentes dépendances des packages que vous essayez de construire.

Développement avec Waf
Jusqu'à présent, nous avons utilisé soit le build.py scénario, ou le cuire outil, pour obtenir
commencé par construire ns-3. Ces outils sont utiles pour construire ns-3 et supportant
bibliothèques, et ils font appel au ns-3 répertoire pour appeler l'outil de construction Waf pour faire le
bâtiment réel. La plupart des utilisateurs passent rapidement à l'utilisation directe de Waf pour configurer et
construire ns-3. Donc, pour continuer, veuillez changer votre répertoire de travail pour le ns-3 annuaire
que vous avez initialement construit.

Ce n'est pas strictement obligatoire à ce stade, mais il sera utile de faire un léger détour
et regardez comment apporter des modifications à la configuration du projet. Probablement le plus
le changement de configuration utile que vous pouvez apporter sera de construire la version optimisée du
code. Par défaut, vous avez configuré votre projet pour générer la version de débogage. disons
le projet pour faire une construction optimisée. Pour expliquer à Waf qu'il devrait faire optimisé
builds qui incluent les exemples et les tests, vous devrez exécuter ce qui suit
commandes:

$ ./waf propre
$ ./waf --build-profile=optimisé --enable-examples --enable-tests configure

Cela exécute Waf à partir du répertoire local (qui vous est fourni pour votre commodité).
La première commande pour nettoyer la version précédente n'est généralement pas strictement nécessaire mais
est une bonne pratique (mais voir Silhouette Profils, au dessous de); il supprimera le précédemment construit
bibliothèques et fichiers objets trouvés dans le répertoire construire/. Lorsque le projet est reconfiguré
et le système de construction vérifie diverses dépendances, vous devriez voir une sortie qui ressemble
semblable à ce qui suit :

Réglage du haut sur : .
Partir à : construire
Recherche de 'gcc' (compilateur c) : /usr/bin/gcc
Vérification de la version cc : 4.2.1
Recherche de 'g++' (compilateur c++) : /usr/bin/g++
La vérification du boost comprend : 1_46_1
Vérification des libs boost : ok
Vérification de la liaison boost : ok
Vérification de l'emplacement du clic : introuvable
Vérification du programme pkg-config : /sw/bin/pkg-config
Vérification de 'gtk+-2.0' >= 2.12 : oui
Vérification de 'libxml-2.0' >= 2.7 : oui
Vérification du type uint128_t : introuvable
Vérification du type __uint128_t : oui
Vérification de l'implémentation de haute précision : entier 128 bits (par défaut)
Vérification de l'en-tête stdint.h : oui
Vérification de l'en-tête inttypes.h : oui
Vérification de l'en-tête sys/inttypes.h : introuvable
Vérification de l'en-tête sys/types.h : oui
Vérification de l'en-tête sys/stat.h : oui
Vérification de l'en-tête dirent.h : oui
Vérification de l'en-tête stdlib.h : oui
Vérification du signal d'en-tête.h : oui
Vérification de l'en-tête pthread.h : oui
Vérification de l'en-tête stdint.h : oui
Vérification de l'en-tête inttypes.h : oui
Vérification de l'en-tête sys/inttypes.h : introuvable
Vérification de la bibliothèque rt : introuvable
Vérification de l'en-tête netpacket/packet.h : introuvable
Vérification de l'en-tête sys/ioctl.h : oui
Vérification de l'en-tête net/if.h : introuvable
Vérification de l'en-tête net/ethernet.h : oui
Vérification de l'en-tête linux/if_tun.h : introuvable
Vérification de l'en-tête netpacket/packet.h : introuvable
Recherche de l'emplacement NSC : introuvable
Vérification de 'mpic++' : oui
Vérification de 'sqlite3' : oui
Vérification de l'en-tête linux/if_tun.h : introuvable
Vérification du programme sudo : /usr/bin/sudo
Vérification du programme valgrind : /sw/bin/valgrind
Vérification de 'gsl' : oui
Vérification de l'indicateur de compilation -Wno-error=deprecated-d... support : ok
Vérification de l'indicateur de compilation -Wno-error=deprecated-d... support : ok
Vérification de l'indicateur de compilation -fstrict-aliasing... support : ok
Vérification de l'indicateur de compilation -fstrict-aliasing... support : ok
Vérification de l'indicateur de compilation -Wstrict-aliasing... support : ok
Vérification de l'indicateur de compilation -Wstrict-aliasing... support : ok
Vérification du programme doxygen : /usr/local/bin/doxygen
---- Résumé des fonctionnalités optionnelles du NS-3 :
Profil de construction : débogage
Répertoire de compilation : build
Liaisons Python : activées
Intégration BRITE : non activé (BRITE non activé (voir option --with-brite))
Intégration NS-3 Click : non activée (nsclick non activé (voir option --with-nsclick))
GtkConfigStore : activé
XmlIo : activé
Threading Primitives : activé
Simulateur temps réel : activé (librt n'est pas disponible)
Périphérique réseau émulé : activé ( inclure non détecté)
Descripteur de fichier NetDevice : activé
Appuyez sur FdNetDevice : non activé (nécessite linux/if_tun.h)
Emulation FdNetDevice : non activé (nécessite netpacket/packet.h)
PlanetLab FdNetDevice : non activé (système d'exploitation PlanetLab non détecté (voir option --force-planetlab))
Network Simulation Cradle : non activé (NSC introuvable (voir option --with-nsc))
Support MPI : activé
Intégration NS-3 OpenFlow : non activée (Bibliothèques boost requises introuvables, manquantes : système, signaux, système de fichiers)
Sortie des données statistiques SQlite : activée
Tap Bridge : non activé ( inclure non détecté)
Visualiseur PyViz : activé
Utilisez sudo pour définir le bit suid : non activé (option --enable-sudo non sélectionnée)
Tests de compilation : activé
Exemples de build : activé
Bibliothèque scientifique GNU (GSL) : activé
'configuration' terminé avec succès (1.944s)

Notez la dernière partie de la sortie ci-dessus. Certains ns-3 les options ne sont pas activées par défaut ou
nécessitent le soutien du système sous-jacent pour fonctionner correctement. Par exemple, pour activer
XmlTo, la bibliothèque libxml-2.0 doit être trouvée sur le système. Si cette bibliothèque n'était pas
trouvé, le correspondant ns-3 fonction ne serait pas activée et un message serait
affiché. Notez en outre qu'il existe une fonctionnalité pour utiliser le programme sudo mettre le suid
peu de certains programmes. Ceci n'est pas activé par défaut et donc cette fonctionnalité est signalée
comme "non activé".

Maintenant, continuez et revenez à la version de débogage qui inclut les exemples et les tests.

$ ./waf propre
$ ./waf --build-profile=debug --enable-examples --enable-tests configurer

Le système de build est maintenant configuré et vous pouvez construire les versions de débogage du ns-3
programmes en tapant simplement

$ ./waf

OK, désolé, je t'ai fait construire le ns-3 partie du système deux fois, mais maintenant vous savez comment
modifier la configuration et créer du code optimisé.

Le script build.py discuté ci-dessus prend également en charge le --enable-exemples et votre activer-tests
arguments, mais en général, ne prend pas directement en charge les autres options waf ; par exemple, ce
ne fonctionnera pas:

$ ./build.py --disable-python

aura pour résultat

build.py : erreur : aucune option de ce type : --disable-python

Cependant, l'opérateur spécial -- peut être utilisé pour transmettre des options supplémentaires à waf, donc
au lieu de ce qui précède, ce qui suit fonctionnera :

$ ./build.py -- --disable-python

car il génère la commande sous-jacente ./waff configurer --disable-python.

Voici quelques conseils d'introduction supplémentaires sur Waf.

Configurez vs. Silhouette
Certaines commandes Waf n'ont de sens que pendant la phase de configuration et certaines commandes sont
valable dans la phase de construction. Par exemple, si vous souhaitez utiliser les fonctionnalités d'émulation de
ns-3, vous souhaiterez peut-être activer la définition du bit suid à l'aide de sudo comme décrit ci-dessus. Cette
s'avère être une commande de configuration-time, et vous pouvez donc reconfigurer en utilisant le
commande suivante qui inclut également les exemples et les tests.

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

Si vous faites cela, Waf aura exécuté sudo pour modifier les programmes créateurs de sockets du
code d'émulation à exécuter en tant que root.

Il existe de nombreuses autres options de configuration et de temps de construction disponibles dans Waf. Pour explorer ces
options, tapez :

$ ./waf --aide

Nous utiliserons certaines des commandes liées aux tests dans la section suivante.

Silhouette Profils
Nous avons déjà vu comment configurer Waf pour déboguer or optimisé construit :

$ ./waf --build-profile=débogage

Il existe également un profil de construction intermédiaire, libérer. -d est synonyme de
--build-profil.

Par défaut, Waf place les artefacts de build dans le construire annuaire. Vous pouvez spécifier un
répertoire de sortie différent avec le --dehors option, par exemple

$ ./waf configurer --out=foo

La combinaison de cela avec des profils de construction vous permet de basculer entre les différentes options de compilation
d'une manière propre :

$ ./waf configurer --build-profile=debug --out=build/debug
$ ./waf construit

$ ./waf configure --build-profile=optimisé --out=build/optimisé
$ ./waf construit


Cela vous permet de travailler avec plusieurs versions plutôt que d'écraser toujours la dernière
construire. Lorsque vous changez, Waf ne compilera que ce qu'il doit, au lieu de recompiler
tout.

Lorsque vous changez de profil de construction comme celui-ci, vous devez faire attention à donner le même
paramètres de configuration à chaque fois. Il peut être pratique de définir un environnement
variables pour vous aider à éviter les erreurs :

$ export NS3CONFIG="--enable-examples --enable-tests"
$ export NS3DEBUG="--build-profile=debug --out=build/debug"
$ export NS3OPT=="--build-profile=optimized --out=build/optimized"

$ ./waf configurer $NS3CONFIG $NS3DEBUG
$ ./waf construit

$ ./waf configurer $NS3CONFIG $NS3OPT
$ ./waf construit

Compilateurs
Dans les exemples ci-dessus, Waf utilise le compilateur GCC C++, g ++, pour la construction ns-3. Toutefois,
il est possible de changer le compilateur C++ utilisé par Waf en définissant le CXX sûr, heureux et sain
variable. Par exemple, pour utiliser le compilateur Clang C++, cliquetis ++,

$ CXX="clang++" ./waf configurer
$ ./waf construit

On peut aussi configurer Waf pour faire de la compilation distribuée avec distcc d'une manière similaire:

$ CXX="distcc g++" ./waf configurer
$ ./waf construit

Plus d'infos sur distcc et la compilation distribuée peut être trouvée sur c'est Projet page sous
Rubrique documentation.

Installer
Waf peut être utilisé pour installer des bibliothèques à divers endroits sur le système. Le défaut
l'emplacement où les bibliothèques et les exécutables sont construits est dans le construire répertoire, et parce que
Waf connaît l'emplacement de ces bibliothèques et exécutables, il n'est pas nécessaire d'installer
les bibliothèques ailleurs.

Si les utilisateurs choisissent d'installer des éléments en dehors du répertoire de construction, les utilisateurs peuvent émettre le
./waff installer commander. Par défaut, le préfixe d'installation est / Usr / local, De sorte ./waff
installer installera des programmes dans / usr / local / bin, des bibliothèques dans / Usr / local / lib et
en-têtes dans /usr/local/inclure. Les privilèges de superutilisateur sont généralement nécessaires pour installer sur
le préfixe par défaut, donc la commande typique serait sudo ./waff installer. En courant
programmes avec Waf, Waf préférera d'abord utiliser des bibliothèques partagées dans le répertoire de construction,
puis recherchera les bibliothèques dans le chemin de bibliothèque configuré dans l'environnement local. Donc
lors de l'installation des bibliothèques sur le système, il est recommandé de vérifier que le
les bibliothèques sont utilisées.

Les utilisateurs peuvent choisir d'installer un préfixe différent en passant le --préfixe option à
configurer l'heure, comme :

./waf configure --prefix=/opt/local

Si plus tard après la construction, l'utilisateur émet le ./waff installer commande, le préfixe /opt/local
sera utilisé.

Notre ./waff espace extérieur plus propre, La commande doit être utilisée avant de reconfigurer le projet si Waf sera
utilisé pour installer des choses à un préfixe différent.

En résumé, il n'est pas nécessaire d'appeler ./waff installer à utiliser ns-3. La plupart des utilisateurs ne
besoin de cette commande car Waf récupérera les bibliothèques actuelles du construire annuaire,
mais certains utilisateurs peuvent le trouver utile si leur cas d'utilisation implique de travailler avec des programmes extérieurs
des ns-3 répertoire.

UN Waf
Il n'y a qu'un seul script Waf, au plus haut niveau du ns-3 arbre source. Pendant que vous travaillez, vous
vous pourriez passer beaucoup de temps dans rayure/, ou au fond src/..., et avoir besoin de
invoquer Waf. Vous pouvez simplement vous rappeler où vous êtes et invoquer Waf comme ceci :

$ ../../../waf...

mais cela devient fastidieux et sujet aux erreurs, et il existe de meilleures solutions.

Si vous avez le plein ns-3 référentiel ce petit bijou est un début:

$ cd $(hg root) && ./waf ...

Encore mieux, c'est de définir cela comme une fonction shell :

$ function waff { cd $(hg root) && ./waf $* ; }

$ waff construire

Si vous n'avez que l'archive tar, une variable d'environnement peut vous aider :

$ export NS3DIR="$PWD"
$ fonction waff { cd $NS3DIR && ./waf $* ; }

$ cd à gratter
$ waff construire

Il peut être tentant dans un répertoire de module d'ajouter un trivial waf script dans le sens de
exec ../../waf. S'il vous plaît, ne le faites pas. C'est déroutant pour les nouveaux arrivants, et quand c'est mal fait, ça
conduit à de subtiles erreurs de construction. Les solutions ci-dessus sont la voie à suivre.

Contrôle de qualité ns-3
Vous pouvez exécuter les tests unitaires du ns-3 distribution en exécutant le ./test.py -c core
script:

$ ./test.py -c noyau

Ces tests sont menés en parallèle par le Waf. Vous devriez éventuellement voir un rapport disant que

92 des 92 tests réussis (92 réussis, 0 échoué, 0 planté, 0 erreurs valgrind)

C'est le message important.

Vous verrez également la sortie récapitulative de Waf et le lanceur de test exécutant chaque test,
qui ressemblera en fait à quelque chose comme :

Waf : Saisie du répertoire `/path/to/workspace/ns-3-allinone/ns-3-dev/build'
Waf : quitter le répertoire `/chemin/vers/espace de travail/ns-3-allinone/ns-3-dev/build'
'build' terminé avec succès (1.799s)

Modules construits :
pont d'applications aodv
cliquez sur le noyau du magasin de configuration
csma csma-disposition dsdv
moniteur de flux d'énergie emu
maillage internet lte
mobilité mpi netanim
réseau nix-vector-routing ns3tcp
flux ouvert ns3wifi olsr
propagation de disposition point à point point à point
stats du spectre tap-bridge
outils de test de modèle
topologie-read uan virtual-net-device
visualiseur wifi wimax

PASS : TestSuite ns3-wifi-interférence
RÉUSSITE : histogramme TestSuite



PASS : objet TestSuite
PASS : générateurs de nombres aléatoires TestSuite
92 des 92 tests réussis (92 réussis, 0 échoué, 0 planté, 0 erreurs valgrind)

Cette commande est généralement exécutée par les utilisateurs pour vérifier rapidement qu'un ns-3 la distribution a
construit correctement. (Notez l'ordre des PASSE: les lignes peuvent varier, ce qui est bien. Qu'est-ce que
il est important que la ligne récapitulative à la fin signale que tous les tests ont réussi ; aucun n'a échoué ou
écrasé.)

Fonctionnement a scénario
Nous exécutons généralement des scripts sous le contrôle de Waf. Cela permet au système de construction de garantir
que les chemins des bibliothèques partagées sont définis correctement et que les bibliothèques sont disponibles à
Durée. Pour exécuter un programme, utilisez simplement le --Cours option en Waf. Exécutons le ns-3
l'équivalent du programme hello world omniprésent en tapant ce qui suit :

$ ./waf --run bonjour-simulateur

Waf vérifie d'abord que le programme est correctement construit et exécute une construction si
obligatoire. Waf exécute ensuite le programme, qui produit la sortie suivante.

Bonjour Simulateur

Toutes nos félicitations! Vous êtes maintenant un utilisateur ns-3 !

Ce que do I do if I ne le font pas sur le lien le production?

Si vous voyez des messages Waf indiquant que la construction s'est terminée avec succès, mais ne
voir la sortie "Hello Simulator", il est probable que vous ayez basculé votre mode de construction sur
optimisé dans le Développement avec Waf section, mais j'ai raté le changement de retour à déboguer mode.
Toute la sortie de la console utilisée dans ce didacticiel utilise un ns-3 composant de journalisation qui
est utile pour imprimer les messages utilisateur sur la console. La sortie de ce composant est
automatiquement désactivé lorsque vous compilez du code optimisé - il est "optimisé". Si tu
ne voyez pas la sortie "Hello Simulator", tapez ce qui suit :

$ ./waf configure --build-profile=debug --enable-examples --enable-tests

pour dire à Waf de construire les versions de débogage du ns-3 programmes qui incluent les exemples
et des essais. Vous devez toujours générer la version de débogage réelle du code en tapant

$ ./waf

Maintenant, si vous exécutez le bonjour-simulateur programme, vous devriez voir le résultat attendu.

Programme Arguments
Pour fournir des arguments de ligne de commande à un ns-3 programme utilise ce modèle:

$ ./waf --run --command-template="%s "

Remplacez le nom de votre programme par , et les arguments pour L’
--commande-modèle argument à Waf est fondamentalement une recette pour construire le réel
ligne de commande que Waf doit utiliser pour exécuter le programme. Waf vérifie que le build est
complete, définit les chemins de la bibliothèque partagée, puis appelle l'exécutable à l'aide du fichier fourni
modèle de ligne de commande, en insérant le nom du programme pour le %s espace réservé. (je l'admets
c'est un peu gênant, mais c'est comme ça. Les patchs sont les bienvenus !)

Un autre exemple particulièrement utile consiste à exécuter une suite de tests par elle-même. Supposons qu'un
mon test la suite de tests existe (ce n'est pas le cas). Ci-dessus, nous avons utilisé le ./test.py script pour exécuter un tout
une flopée de tests en parallèle, en invoquant à plusieurs reprises le vrai programme de test, testeur.
Invoquer testeur directement pour un seul test :

$ ./waf --run test-runner --command-template="%s --suite=mytest --verbose"

Cela transmet les arguments au testeur programme. Depuis mon test n'existe pas, un
un message d'erreur sera généré. Pour imprimer les disponibles testeur options:

$ ./waf --run test-runner --command-template="%s --help"

Débogage
Courir ns-3 programmes sous le contrôle d'un autre utilitaire, tel qu'un débogueur (par exemple gdb)
ou un vérificateur de mémoire (par exemple valgrind), vous utilisez un --command-template="..." formulaire.

Par exemple, pour exécuter votre ns-3 Programme bonjour-simulateur avec les arguments sous le
gdb débogueur :

$ ./waf --run=hello-simulator --command-template="gdb %s --args "

Notez que le ns-3 le nom du programme va avec le --Cours argument, et l'utilitaire de contrôle
(ici gdb) est le premier jeton dans le --commande-modèle argument. le --args raconte gdb
que le reste de la ligne de commande appartient au programme "inférieur". (Certains gdb's
ne comprends pas le --args caractéristique. Dans ce cas, omettez les arguments du programme du
--commande-modèle, et utilisez le gdb commander set args.)

On peut combiner cette recette et la précédente pour faire un test sous le débogueur :

$ ./waf --run test-runner --command-template="gdb %s --args --suite=mytest --verbose"

Working : un espace de travail commun Annuaire
Waf doit partir de son emplacement en haut du ns-3 arbre. Cela devient le travail
répertoire où les fichiers de sortie seront écrits. Mais que faire si vous voulez garder ces
le ns-3 arbre source? Utilisez le --cwd argument:

$ ./waf --cwd=...

Il peut être plus pratique de commencer par votre répertoire de travail où vous voulez la sortie
fichiers, auquel cas un peu d'indirection peut aider :

$ fonction waff {
CWD="$PWD"
cd $NS3DIR >/dev/null
./waf --cwd="$CWD" $*
cd - >/dev/null
}

Cet embellissement de la version précédente enregistre le répertoire de travail courant, cdest à
le répertoire Waf, puis demande à Waf de changer le répertoire de travail RETOUR aux sauvés
répertoire de travail courant avant d'exécuter le programme.

CONCEPTUEL APERÇU


La première chose que nous devons faire avant de commencer à regarder ou à écrire ns-3 le code est de
expliquer quelques concepts et abstractions de base du système. Une grande partie de cela peut apparaître
évident pour certains, mais nous vous recommandons de prendre le temps de lire ceci
section juste pour vous assurer que vous partez sur une base solide.

ACTIVITES Les abstractions
Dans cette section, nous passerons en revue certains termes couramment utilisés dans les réseaux, mais qui ont un
sens spécifique dans ns-3.

Nœud
Dans le jargon Internet, un appareil informatique qui se connecte à un réseau est appelé un hôte or
parfois un fin Système. Car ns-3 est une réseau simulateur, pas spécifiquement un
Internet simulateur, nous n'utilisons pas intentionnellement le terme hôte car il est étroitement
liés à Internet et à ses protocoles. Au lieu de cela, nous utilisons également un terme plus générique
utilisé par d'autres simulateurs issus de la théorie des graphes --- le nœud.

In ns-3 l'abstraction de base du dispositif informatique est appelée le nœud. Cette abstraction est
représenté en C++ par la classe NœudL’ Nœud La classe fournit des méthodes pour gérer le
représentations de dispositifs informatiques dans des simulations.

Vous devriez penser à un Nœud comme un ordinateur auquel vous ajouterez des fonctionnalités. on ajoute
des choses comme les applications, les piles de protocoles et les cartes périphériques avec leurs
pilotes pour permettre à l'ordinateur d'effectuer un travail utile. Nous utilisons le même modèle de base dans ns-3.

Application
En règle générale, les logiciels informatiques sont divisés en deux grandes classes. Système Software organise
diverses ressources informatiques telles que mémoire, cycles processeur, disque, réseau, etc.,
selon un modèle informatique. Le logiciel système n'utilise généralement pas ces ressources
pour accomplir des tâches qui profitent directement à un utilisateur. Un utilisateur exécuterait généralement un application
qui acquiert et utilise les ressources contrôlées par le logiciel système pour accomplir certaines
objectif.

Souvent, la ligne de séparation entre le système et le logiciel d'application se fait au
changement de niveau de privilège qui se produit dans les interruptions du système d'exploitation. Dans ns-3 il n'y a pas de réel
notion de système d'exploitation et surtout pas de notion de niveaux de privilèges ou d'appels système.
Nous avons cependant l'idée d'une application. Tout comme les applications logicielles s'exécutent sur
ordinateurs pour effectuer des tâches dans le « monde réel », ns-3 les applications s'exécutent sur ns-3 Nodes à
conduire des simulations dans le monde simulé.

In ns-3 l'abstraction de base d'un programme utilisateur qui génère une activité à
simulé est l'application. Cette abstraction est représentée en C++ par la classe
ApplicationL’ Application La classe fournit des méthodes pour gérer les représentations de
notre version des applications de niveau utilisateur dans les simulations. Les développeurs sont censés
spécialiser le Application classe au sens de la programmation orientée objet pour créer de nouveaux
applications. Dans ce tutoriel, nous utiliserons des spécialisations de classe Application appelé
UdpEchoClientApplicationUdpEchoClientApplication et votre UdpEchoServerApplicationUdpEchoServerApplication. Comme vous pouvez vous y attendre, ces
les applications composent un ensemble d'applications client/serveur utilisé pour générer et écho simulé
paquets réseau

Développement
Dans le monde réel, on peut connecter un ordinateur à un réseau. Souvent les médias sur lesquels
les flux de données dans ces réseaux sont appelés indirect. Lorsque vous connectez votre câble Ethernet à
la prise murale, vous connectez votre ordinateur à une communication Ethernet
canaliser. Dans le monde simulé de ns-3, on connecte un Nœud à un objet représentant un
canal de communication. Ici, l'abstraction de base du sous-réseau de communication est appelée
channel et est représenté en C++ par la classe Développement.

Notre Développement La classe fournit des méthodes pour gérer les objets de sous-réseau de communication et
en leur connectant des nœuds. Canaux peut aussi être spécialisé par les développeurs dans l'objet
sens de la programmation orienté. UNE Développement spécialisation peut modéliser quelque chose d'aussi simple qu'un
câble. Le spécialisé Développement peut également modéliser des choses aussi compliquées qu'un grand Ethernet
commutateur, ou un espace tridimensionnel plein d'obstructions dans le cas des réseaux sans fil.

Nous utiliserons des versions spécialisées du Développement appelé CsmaChannel, PointVersPointChannel
et votre WifiCanal dans ce tutoriel. Les CsmaChannel, par exemple, modélise une version d'un
sous-réseau de communication qui implémente un porteur sens plusieurs accès communication
moyen. Cela nous donne une fonctionnalité de type Ethernet.

Net Appareil
Autrefois, si vous vouliez connecter un ordinateur à un réseau, vous deviez
acheter un type spécifique de câble réseau et un périphérique matériel appelé (dans la terminologie PC) un
périphérique carte qui devait être installé sur votre ordinateur. Si la carte périphérique
mis en œuvre une fonction de mise en réseau, elles étaient appelées cartes d'interface réseau, ou NIC.
Aujourd'hui, la plupart des ordinateurs sont livrés avec le matériel d'interface réseau intégré et les utilisateurs ne voient pas
ces blocs de construction.

Une carte réseau ne fonctionnera pas sans un pilote logiciel pour contrôler le matériel. Sous Unix (ou
Linux), un élément matériel périphérique est classé comme un dispositif. Les appareils sont contrôlés
en utilisant dispositif conducteurs, et les périphériques réseau (NIC) sont contrôlés à l'aide réseau dispositif
conducteurs collectivement connus sous le nom de net dispositifs. Sous Unix et Linux, vous vous référez à ces réseaux
appareils par des noms tels que eth0.

In ns-3 le net dispositif l'abstraction couvre à la fois le pilote logiciel et la simulation
Matériel. Un périphérique réseau est « installé » dans un Nœud afin de permettre au Nœud à
communiquer avec d'autres Nodes dans la simulation via Canaux. Tout comme dans un vrai ordinateur,
a Nœud peut être connecté à plusieurs Développement via plusieurs NetDevices.

L'abstraction de périphérique net est représentée en C++ par la classe NetDeviceL’ NetDevice
La classe fournit des méthodes pour gérer les connexions à Nœud et votre Développement objets; et peut-être
spécialisée par les développeurs dans le sens de la programmation orientée objet. Nous utiliserons le
plusieurs versions spécialisées du NetDevice appelé Périphérique CsmaNet, PointVersPointNetDevice,
et votre WifiNetAppareil dans ce tutoriel. Tout comme une carte réseau Ethernet est conçue pour fonctionner avec un
réseau Ethernet, le Périphérique CsmaNet est conçu pour fonctionner avec un CsmaChannel; la
PointVersPointNetDevice est conçu pour fonctionner avec un PointVersPointChannel et WifiNetAppareil
est conçu pour fonctionner avec un WifiCanal.

topologie assistants
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 we
dirait que vous trouverez Nodes avec attaché NetDevices. Dans un grand réseau simulé
vous aurez besoin d'organiser de nombreuses connexions entre Nodes, NetDevices et votre Canaux.

Depuis la connexion NetDevices à Nodes, NetDevices à Canaux, l'attribution d'adresses IP,
etc., sont des tâches si courantes dans ns-3, nous fournissons ce que nous appelons topologie aides faire ça
aussi facile que possible. Par exemple, cela peut prendre plusieurs ns-3 opérations de base à
créer un NetDevice, ajouter une adresse MAC, installer ce périphérique net sur un Nœud, configurez le
pile de protocoles du nœud, puis connectez le NetDevice à Développement. Encore plus d'opérations
serait nécessaire de connecter plusieurs appareils sur des canaux multipoints, puis de se connecter
réseaux individuels ensemble en interréseaux. Nous fournissons des objets d'assistance de topologie qui
combinez ces nombreuses opérations distinctes dans un modèle facile à utiliser pour votre commodité.

A Prénom ns-3 scénario
Si vous avez téléchargé le système comme suggéré ci-dessus, vous aurez une version de ns-3 dans un
répertoire appelé repos sous votre répertoire personnel. Accédez à ce répertoire de version, et
vous devriez trouver une structure de répertoires comme celle-ci :

AUTEURS exemples scratch utils waf.bat*
liaisons LICENCE src utils.py waf-tools
construire ns3 test.py* utils.pyc wscript
CHANGES.html LISEZMOI testpy-sortie VERSION wutils.py
doc RELEASE_NOTES testpy.supp waf* wutils.pyc

Changer en exemples/tutoriel annuaire. Vous devriez voir un fichier nommé premier.cc situé
là. Il s'agit d'un script qui va créer un simple lien point à point entre deux nœuds
et faire écho à un seul paquet entre les nœuds. Jetons un coup d'œil à cette ligne de script en
ligne, alors allez-y et ouvrez premier.cc dans votre éditeur préféré.

Boilerplate
La première ligne du fichier est une ligne en mode emacs. Cela informe emacs sur le formatage
conventions (style de codage) que nous utilisons dans notre code source.

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

C'est toujours un sujet quelque peu controversé, alors autant le mettre de côté
immédiatement. le ns-3 projet, comme la plupart des grands projets, a adopté un style de codage pour
auquel tout le code contribué doit adhérer. Si vous voulez contribuer votre code au
projet, vous devrez éventuellement vous conformer aux ns-3 norme de codage telle que décrite dans
le fichier doc/codingstd.txt ou affiché sur la page Web du projet ici.

Nous vous recommandons, eh bien, de vous habituer à l'apparence de ns-3 coder et adopter
cette norme chaque fois que vous travaillez avec notre code. Toute l'équipe de développement et
les contributeurs l'ont fait avec diverses quantités de grognements. La ligne du mode emacs ci-dessus
facilite la mise en forme correcte si vous utilisez l'éditeur emacs.

Notre ns-3 simulateur est sous licence en utilisant la licence publique générale GNU. Vous verrez le
le jargon juridique GNU approprié en tête de chaque fichier du ns-3 Distribution. Souvent vous
verra un avis de droit d'auteur pour l'une des institutions impliquées dans le ns-3 projet ci-dessus
le texte GPL et un auteur répertorié ci-dessous.

/*
* Ce programme est un logiciel gratuit ; vous pouvez le redistribuer et/ou modifier
* sous les termes de la licence publique générale GNU version 2 comme
* publié par la Free Software Foundation ;
*
* Ce programme est distribué dans l'espoir qu'il vous sera utile,
* mais SANS AUCUNE GARANTIE ; sans même la garantie implicite de
* QUALITÉ MARCHANDE ou ADAPTATION À UN USAGE PARTICULIER. Voir le
* Licence publique générale GNU pour plus de détails.
*
* Vous devriez avoir reçu une copie de la licence publique générale GNU
* avec ce programme; sinon, écrivez au Logiciel Libre
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 États-Unis
*/

Module Inclus
Le code proprement dit commence par un certain nombre d'instructions d'inclusion.

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

Pour aider nos utilisateurs de script de haut niveau à gérer le grand nombre de fichiers d'inclusion présents dans
le système, nous le regroupons en fonction de modules relativement grands. Nous fournissons un seul
include qui chargera récursivement tous les fichiers include utilisés dans chaque module.
Plutôt que d'avoir à rechercher exactement de quel en-tête vous avez besoin, et éventuellement à obtenir un
nombre de dépendances correct, nous vous donnons la possibilité de charger un groupe de fichiers à grande échelle
granularité. Ce n'est pas l'approche la plus efficace mais elle rend certainement l'écriture
scripts beaucoup plus facile.

Chacun de la ns-3 inclure les fichiers est placé dans un répertoire appelé ns3 (sous la construction
répertoire) pendant le processus de génération pour éviter les collisions de nom de fichier d'inclusion. Les
ns3/core-module.h fichier correspond au module ns-3 que vous trouverez dans le répertoire
src/noyau dans votre distribution de version téléchargée. Si vous listez ce répertoire, vous
trouver un grand nombre de fichiers d'en-tête. Lorsque vous effectuez une génération, Waf place un en-tête public
fichiers dans un ns3 répertoire sous le construire/déboguer or construire/optimisé annuaire
selon votre configuration. Waf générera également automatiquement un module include
pour charger tous les fichiers d'en-tête publics.

Puisque vous suivez bien sûr ce tutoriel religieusement, vous l'aurez déjà fait
a

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

afin de configurer le projet pour effectuer des builds de débogage qui incluent des exemples et des tests.
Vous aurez également fait un

$ ./waf

pour construire le projet. Alors maintenant, si vous regardez dans le répertoire ../../build/debug/ns3 vous serez
trouvez les quatre fichiers d'inclusion de module indiqués ci-dessus. Vous pouvez consulter le contenu de
ces fichiers et constatez qu'ils incluent tout le public incluent des fichiers dans leur
modules respectifs.

NS3 Espace de noms
La ligne suivante dans le premier.cc script est une déclaration d'espace de noms.

en utilisant l'espace de noms ns3 ;

Notre ns-3 projet est implémenté dans un espace de noms C++ appelé ns3. Cela regroupe tous
ns-3-déclarations liées dans une portée en dehors de l'espace de noms global, ce qui, nous l'espérons, aidera
avec intégration avec un autre code. Le C++ en utilisant déclaration présente la ns-3 namespace
dans la région déclarative actuelle (globale). C'est une façon élégante de dire qu'après
cette déclaration, vous n'aurez pas à taper ns3 :: opérateur de résolution de portée avant tout
le ns-3 code pour pouvoir l'utiliser. Si vous n'êtes pas familier avec les espaces de noms, veuillez consulter
presque tous les tutoriels C++ et comparez les ns3 espace de noms et utilisation ici avec des instances de
std espace de noms et le en utilisant namespace std ; déclarations que vous trouverez souvent dans les discussions
of cout et des ruisseaux.

Journal
La ligne suivante du script est la suivante,

NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");

Nous utiliserons cette déclaration comme un endroit pratique pour parler de notre documentation Doxygen
système. Si vous consultez le site Web du projet, ns-3 Projet, vous trouverez un lien vers
"Documentation" dans la barre de navigation. Si vous sélectionnez ce lien, vous serez redirigé vers notre
page documentaire. Il y a un lien vers "Dernière version" qui vous mènera à la
documentation pour la dernière version stable de ns-3. Si vous sélectionnez "API
Documentation", vous serez redirigé vers le ns-3 Page de documentation de l'API.

Sur le côté gauche, vous trouverez une représentation graphique de la structure du
Documentation. Un bon point de départ est le NS-3 formation vidéo "livre" dans le ns-3 la navigation
arbre. Si vous développez formation vidéo vous verrez une liste de ns-3 documentation des modules. le
Le concept de module ici est directement lié aux fichiers d'inclusion de module décrits ci-dessus. le
ns-3 le sous-système de journalisation est abordé dans le C + + Construit Occasion by Tous formation vidéo section, donc
allez-y et développez ce nœud de documentation. Maintenant, développez le Débogage réserver et ensuite
sélectionnez le Journal .

Vous devriez maintenant consulter la documentation Doxygen du module Logging. Dans le
liste des #defineest en haut de la page, vous verrez l'entrée pour
NS_LOG_COMPONENT_DEFINE. Avant de se lancer, il serait probablement bon de chercher le
"Description détaillée" du module de journalisation pour avoir une idée du fonctionnement global. Toi
pouvez soit faire défiler vers le bas, soit sélectionner le lien "Plus..." sous le diagramme de collaboration pour faire
ce.

Une fois que vous avez une idée générale de ce qui se passe, allez-y et jetez un coup d'œil aux détails
NS_LOG_COMPONENT_DEFINE Documentation. Je ne vais pas dupliquer la documentation ici, mais pour
résumer, cette ligne déclare un composant de journalisation appelé ExemplePremierScript qui permet
vous permet d'activer et de désactiver la journalisation des messages de la console par référence au nom.

Entrée Fonction
Les prochaines lignes du script que vous trouverez sont,

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

Il s'agit simplement de la déclaration de la fonction principale de votre programme (script). Tout comme dans
n'importe quel programme C++, vous devez définir une fonction principale qui sera la première fonction exécutée.
Il n'y a rien de spécial ici. Ton ns-3 script est juste un programme C++.

La ligne suivante définit la résolution temporelle sur une nanoseconde, qui se trouve être la valeur par défaut
valeur:

Heure::SetResolution (Heure::NS);

La résolution est la plus petite valeur de temps pouvant être représentée (ainsi que la plus petite
différence représentable entre deux valeurs temporelles). Vous pouvez changer la résolution exactement
une fois que. Le mécanisme permettant cette flexibilité est quelque peu gourmand en mémoire, donc une fois que le
résolution a été définie explicitement, nous libérons la mémoire, empêchant 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 suivantes du script sont utilisées pour activer deux composants de journalisation construits
dans les applications Echo Client et Echo Server :

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

Si vous avez lu la documentation du composant Logging, vous aurez vu qu'il
existe un certain nombre de niveaux de verbosité/de détail de journalisation que vous pouvez activer sur chaque composant.
Ces deux lignes de code activent la journalisation de débogage au niveau INFO pour les clients echo et
les serveurs. Cela entraînera l'impression par l'application des messages au fur et à mesure que les paquets sont envoyés
et reçus pendant la simulation.

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

topologie assistants
Conteneur de nœud
Les deux prochaines lignes de code de notre script créeront en fait le ns-3 Nœud objets qui
représentera les ordinateurs dans la simulation.

nœuds NodeContainer ;
nœuds.Créer (2);

Trouvons la documentation pour le Conteneur de nœud cours avant de continuer. Autrement
accéder à la documentation d'une classe donnée se fait via le Cours onglet dans le Doxygen
pages. Si vous avez toujours le Doxygen à portée de main, faites simplement défiler vers le haut de la page et
sélectionnez le Cours languette. Vous devriez voir un nouvel ensemble d'onglets apparaître, dont l'un est Classe
Liste. Sous cet onglet, vous verrez une liste de tous les ns-3 Des classes. Défiler vers le bas,
à la recherche de ns3 :: NodeContainer. Lorsque vous trouvez la classe, continuez et sélectionnez-la pour accéder à
la documentation de la classe.

Vous vous souviendrez peut-être que l'une de nos principales abstractions est la Nœud. Cela représente un ordinateur
auquel nous allons ajouter des éléments tels que des piles de protocoles, des applications et des périphériques
cartes. le Conteneur de nœud topology helper fournit un moyen pratique de créer, gérer et
accéder à n'importe quel Nœud objets que nous créons afin d'exécuter une simulation. La première ligne ci-dessus
déclare juste un NodeContainer que nous appelons nœuds. La deuxième ligne appelle le Créez
méthode sur le nœuds objet et demande au conteneur de créer deux nœuds. Comme décrit dans
le Doxygen, le conteneur appelle dans le ns-3 système propre à créer deux Nœud
objets et stocke des pointeurs vers ces objets en interne.

Les nœuds tels qu'ils se présentent dans le script ne font rien. La prochaine étape dans la construction d'un
La topologie consiste à connecter nos nœuds ensemble dans un réseau. La forme la plus simple de réseau que nous
support est un lien point à point unique entre deux nœuds. Nous allons en construire un
liens ici.

PointÀPointHelper
Nous construisons un lien point à point, et, selon un modèle qui deviendra tout à fait
que vous connaissez bien, nous utilisons un objet d'assistance de topologie pour effectuer le travail de bas niveau requis pour mettre
le lien ensemble. Rappelons que deux de nos abstractions clés sont les NetDevice et la
Développement. Dans le monde réel, ces termes correspondent à peu près aux cartes périphériques et
câbles réseau. Typiquement, ces deux choses sont intimement liées et on ne peut
attendez-vous à échanger, par exemple, des périphériques Ethernet et des canaux sans fil. Notre Topologie
Les assistants suivent cet accouplement intime et vous utiliserez donc un seul
PointÀPointHelper pour configurer et connecter ns-3 PointVersPointNetDevice et votre
PointVersPointChannel objets dans ce script.

Les trois lignes suivantes du script sont,

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

La première ligne,

PointToPointHelper pointToPoint ;

instancie un PointÀPointHelper objet sur la pile. D'un point de vue de haut niveau, la
ligne suivante,

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

raconte l' PointÀPointHelper objet d'utiliser la valeur "5Mbps" (cinq mégabits par seconde) comme
le "DataRate" lorsqu'il crée un PointVersPointNetDevice objet.

D'un point de vue plus détaillé, la chaîne "DataRate" correspond à ce que nous appelons un
Attribut des PointVersPointNetDevice. Si vous regardez le Doxygen pour la classe
ns3 :: PointToPointNetDevice et retrouvez la documentation ObtenirTypeId méthode, vous allez
trouver une liste de Attributs défini pour l'appareil. Parmi ceux-ci se trouve le "DataRate"
Attribut. Le plus visible par l'utilisateur ns-3 les objets ont des listes similaires de Attributs. Nous utilisons ceci
mécanisme permettant de configurer facilement des simulations sans recompiler comme vous le verrez dans un
section suivante.

Similaire au "DataRate" sur le PointVersPointNetDevice vous trouverez un "Délai" Attribut
associé au PointVersPointChannel. La dernière ligne,

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

raconte l' PointÀPointHelper d'utiliser la valeur "2ms" (deux millisecondes) comme valeur du
délai de transmission de chaque canal point à point qu'il crée par la suite.

NetDeviceContainer
À ce stade du script, nous avons un Conteneur de nœud qui contient deux nœuds. Nous avons un
PointÀPointHelper qui est amorcé et prêt à faire PointToPointNetDevices et fil
PointVersPointChannel objets entre eux. Tout comme nous avons utilisé le Conteneur de nœud topologie
objet d'assistance pour créer le Nodes pour notre simulation, nous demanderons au PointÀPointHelper
pour effectuer le travail impliqué dans la création, la configuration et l'installation de nos appareils pour nous. Nous
aura besoin d'avoir une liste de tous les objets NetDevice qui sont créés, donc nous utilisons un
NetDeviceContainer pour les contenir tout comme nous avons utilisé un NodeContainer pour contenir les nœuds que nous
créé. Les deux lignes de code suivantes,

Périphériques NetDeviceContainer ;
devices = pointToPoint.Install (nœuds);

terminera la configuration des appareils et du canal. La première ligne déclare le périphérique
conteneur mentionné ci-dessus et le second fait le gros du travail. le Installer méthode de
le PointÀPointHelper prend un Conteneur de nœud comme paramètre. En interne, un
NetDeviceContainer est créé. Pour chaque nœud du Conteneur de nœud (il doit y avoir exactement
deux pour une liaison point à point) a PointVersPointNetDevice est créé et enregistré dans l'appareil
récipient. UNE PointVersPointChannel est créé et les deux PointToPointNetDevices are
ci-joint. Lorsque des objets sont créés par le PointÀPointHelper, Attributs précédemment
définis dans l'assistant sont utilisés pour initialiser les Attributs dans le créé
objets.

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

InternetStackHelper
Nous avons maintenant des nœuds et des appareils configurés, mais aucune pile de protocole n'est installée
sur nos nœuds. Les deux prochaines lignes de code s'en occuperont.

Pile InternetStackHelper ;
stack.Install (nœuds);

Notre InternetStackHelper est un assistant de topologie qui consiste à empiler Internet ce que le
PointÀPointHelper est aux appareils réseau point à point. le Installer la méthode prend un
Conteneur de nœud comme paramètre. Lorsqu'il est exécuté, il installe une pile Internet
(TCP, UDP, IP, etc.) sur chacun des nœuds du conteneur de nœuds.

Assistant d'adresse IPv4
Ensuite, nous devons associer les appareils sur nos nœuds avec 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 l'exécution de l'adresse réelle
allocation (qui se fait à un niveau inférieur à l'intérieur de l'assistant).

Les deux lignes de code suivantes dans notre exemple de script, premier.cc,

Adresse Ipv4AddressHelper ;
adresse.SetBase ("10.1.1.0", "255.255.255.0");

déclarer un objet d'assistance d'adresse et lui dire qu'il doit commencer à allouer des adresses IP
du réseau 10.1.1.0 en utilisant le masque 255.255.255.0 pour définir les bits allouables. Par
par défaut, les adresses allouées commenceront à un et augmenteront de manière monotone, donc la première
l'adresse attribuée à partir de cette base sera 10.1.1.1, suivi de 10.1.1.2, etc.
niveau ns-3 système se souvient en fait de toutes les adresses IP attribuées et générera un
erreur fatale si vous générez accidentellement la même adresse deux fois (ce qui est un
erreur très difficile à déboguer, soit dit en passant).

La ligne de code suivante,

Ipv4InterfaceContainer interfaces = address.Assign (dispositifs);

effectue l'attribution d'adresse proprement dite. Dans ns-3 nous faisons l'association entre une IP
adresse et un appareil utilisant un Interface IPv4 objet. Tout comme nous avons parfois besoin d'une liste de
périphériques nets créés par un assistant pour référence future, nous avons parfois besoin d'une liste de
Interface IPv4 objets. le Conteneur d'interface IPv4 fournit cette fonctionnalité.

Nous avons maintenant un réseau point à point construit, avec des piles installées et des adresses IP
attribué. Ce dont nous avons besoin à ce stade, ce sont des applications pour générer du trafic.

Applications
Une autre des abstractions fondamentales du système ns-3 est la Application. Dans ce
script nous utilisons deux spécialisations du noyau ns-3 classe Application appelé
UdpEchoServerApplicationUdpEchoServerApplication et votre UdpEchoClientApplicationUdpEchoClientApplication. Tout comme nous l'avons fait dans notre précédent
explications, nous utilisons des objets d'assistance pour aider à configurer et à gérer les objets sous-jacents.
Ici, nous utilisons UdpEchoServerHelper et votre UdpEchoClientHelperUdpEchoClientHelper objets pour nous faciliter la vie.

UdpEchoServerHelper
Les lignes de code suivantes dans notre exemple de script, premier.cc, permettent de créer un écho UDP
application serveur sur l'un des nœuds que nous avons précédemment créés.

UdpEchoServerHelper echoServer (9);

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

La première ligne de code dans l'extrait ci-dessus déclare le UdpEchoServerHelper. Comme d'habitude,
ce n'est pas l'application elle-même, c'est un objet utilisé pour nous aider à créer le véritable
applications. Une de nos conventions est de placer conditions Attributs dans l'aide
constructeur. Dans ce cas, l'assistant ne peut rien faire d'utile s'il ne dispose pas de
un numéro de port que le client connaît également. Plutôt que d'en choisir un et d'espérer
tout fonctionne, nous avons besoin du numéro de port comme paramètre du constructeur. le
constructeur, à son tour, fait simplement un Définir l'attribut avec la valeur transmise. Si tu veux, tu
peut définir le "Port" Attribut à une autre valeur plus tard en utilisant Définir l'attribut.

Semblable à de nombreux autres objets d'assistance, le UdpEchoServerHelper l'objet a un Installer
méthode. C'est l'exécution de cette méthode qui provoque réellement l'écho sous-jacent
application serveur à instancier et à rattacher à un nœud. Fait intéressant, le Installer
la méthode prend un NodeContainer comme paramètre au même titre que l'autre Installer méthodes que nous avons
vu. C'est en fait ce qui est passé à la méthode même si cela ne semble pas le cas dans
ce cas. Il existe un C++ implicitement Conversion au travail ici qui prend le résultat de
nœuds.Obtenir (1) (qui renvoie un pointeur intelligent vers un objet nœud --- Ptr) et l'utilise
dans un constructeur pour un sans nom Conteneur de nœud qui est ensuite transmis à Installer. Si vous êtes
jamais à court de trouver une signature de méthode particulière dans le code C++ qui compile et s'exécute
très bien, recherchez ces types de conversions implicites.

Nous voyons maintenant que echoServer.Installer va installer un UdpEchoServerApplicationUdpEchoServerApplication sur le
nœud trouvé à l'index numéro un des Conteneur de nœud nous utilisions pour gérer nos nœuds. Installer
renverra un conteneur contenant des pointeurs vers toutes les applications (une dans ce cas
depuis que nous avons passé un Conteneur de nœud contenant un nœud) créé par l'assistant.

Les applications ont besoin d'un temps pour "commencer" à générer du trafic et peuvent prendre un temps facultatif pour
"arrêter". Nous fournissons les deux. Ces temps sont réglés à l'aide de la ApplicationContainerApplicationContainer méthodes
Accueille et votre Arrêter. Ces méthodes prennent Heure paramètres. Dans ce cas, nous utilisons un explicite C + +
séquence de conversion pour prendre le double C++ 1.0 et le convertir en un ns-3 Heure objet utilisant
a Sec jeter. Sachez que les règles de conversion peuvent être contrôlées par l'auteur du modèle,
et C++ a ses propres règles, donc vous ne pouvez pas toujours supposer que les paramètres seront heureux
converti pour vous. Les deux lignes,

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

entraînera l'application du serveur d'écho à Accueille (s'activer) à une seconde dans le
simulation et à Arrêter (se désactiver) à dix secondes dans la simulation. En vertu de
le fait que nous ayons déclaré un événement de simulation (l'événement d'arrêt de l'application) comme étant
exécuté à dix secondes, la simulation durera at au dix secondes.

UdpEchoClientHelperUdpEchoClientHelper
L'application client d'écho est configurée selon une méthode sensiblement similaire à celle du
serveur. Il y a un sous-jacent UdpEchoClientApplicationUdpEchoClientApplication qui est géré par un
UdpEchoClientHelperUdpEchoClientHelper.

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

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

Pour le client d'écho, cependant, nous devons définir cinq paramètres différents Attributs. Les deux premiers
Attributs sont fixés lors de la construction du UdpEchoClientHelperUdpEchoClientHelper. Nous passons des paramètres
qui sont utilisés (en interne à l'assistant) pour définir "RemoteAddress" et "RemotePort"
Attributs conformément à notre convention de rendre nécessaire Attributs paramètres dans le
constructeurs auxiliaires.

Rappelons que nous avons utilisé un Conteneur d'interface IPv4 pour garder une trace des adresses IP que nous
affectés à nos appareils. L'interface zéro dans le interfaces le conteneur va
correspondent à l'adresse IP du nœud zéro dans le nœuds récipient. La première
interface dans le interfaces conteneur correspond à l'adresse IP du premier nœud dans
le nœuds récipient. Ainsi, dans la première ligne de code (ci-dessus), nous créons le
helper et en lui disant de définir l'adresse distante du client comme étant l'adresse IP
affecté au nœud sur lequel réside le serveur. Nous lui disons aussi de s'arranger pour envoyer
paquets au port neuf.

Les "MaxPackets" Attribut indique au client le nombre maximum de paquets que nous lui autorisons à
envoyer pendant la simulation. L'intervalle" Attribut indique au client combien de temps attendre
entre les paquets, et le "PacketSize" Attribut indique au client la taille de son paquet
les charges utiles devraient l'être. Avec cette combinaison particulière de Attributs, nous disons au
client pour envoyer un paquet de 1024 octets.

Tout comme dans le cas du serveur d'écho, nous disons au client d'écho de Accueille et votre Arrêter, mais
ici, nous démarrons le client une seconde après l'activation du serveur (à deux secondes dans le
simulation).

Simulateur
Ce que nous devons faire à ce stade, c'est exécuter la simulation. Cela se fait en utilisant
la fonction globale Simulateur :: Exécuter.

Simulateur::Exécuter ();

Lorsque nous avons précédemment appelé les méthodes,

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

clientApps.Start (secondes (2.0));
clientApps.Stop (Secondes (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. Lorsque Simulateur :: Exécuter est appelé, le système commencera à regarder à travers le
liste des événements planifiés et de les exécuter. D'abord, il exécutera l'événement à 1.0 seconde,
qui activera l'application du serveur d'écho (cet événement peut, à son tour, programmer de nombreux
Autres événements). Ensuite, il exécutera l'événement prévu pour t = 2.0 secondes qui commencera
l'application client d'écho. Encore une fois, cet événement peut programmer de nombreux autres événements. Le début
la mise en œuvre de l'événement dans l'application client d'écho commencera la phase de transfert de données de
la simulation en envoyant un paquet au serveur.

Le fait d'envoyer le paquet au serveur déclenchera une chaîne d'événements qui seront
programmé automatiquement dans les coulisses et qui effectuera la mécanique de la
écho de paquet en fonction des différents paramètres de synchronisation que nous avons définis dans le script.

Finalement, puisque nous n'envoyons qu'un seul paquet (rappelez-vous MaxPaquets Attribut a été mis à
un), la chaîne d'événements déclenchés par cette seule demande d'écho client diminuera et
la simulation deviendra inactive. Une fois que cela se produit, les événements restants seront les Arrêter
événements pour le serveur et le client. Lorsque ces événements sont exécutés, il n'y a pas
d'autres événements à traiter et Simulateur :: Exécuter Retour. La simulation est alors terminée.

Il ne reste plus qu'à nettoyer. Cela se fait en appelant la fonction globale
Simulateur :: Détruire. Comme les fonctions d'assistance (ou de bas niveau ns-3 code) exécutés, ils
l'a arrangé de manière à ce que des crochets soient insérés dans le simulateur pour détruire tous les objets
qui ont été créés. Vous n'avez pas eu à suivre vous-même l'un de ces objets ---
tout ce que tu avais à faire était d'appeler Simulateur :: Détruire et sortir. le ns-3 système a pris soin de
le plus dur pour toi. Les lignes restantes de notre premier ns-3 scénario, premier.cc, fais juste
que:

Simulateur :: Détruire ();
0 revenir;
}

Lorsque le simulateur sera Arrêtez?
ns-3 est un simulateur d'événements discrets (DE). Dans un tel simulateur, chaque événement est associé
avec son temps d'exécution, et la simulation procède en exécutant des événements dans le temps
ordre du temps de simulation. Des événements peuvent entraîner la planification d'événements futurs (par exemple, un
temporisateur peut se reprogrammer pour expirer au prochain intervalle).

Les événements initiaux sont généralement déclenchés par chaque objet, par exemple, IPv6 programmera le routeur
Annonces, sollicitations de voisins, etc., une application programme le premier paquet
envoi d'événement, etc.

Lorsqu'un événement est traité, il peut générer zéro, un ou plusieurs événements. En guise de simulation
s'exécute, les événements sont consommés, mais davantage d'événements peuvent (ou non) être générés. le
la simulation s'arrête automatiquement lorsqu'il n'y a plus d'événements dans la file d'attente d'événements ou lorsque
un événement Stop spécial est trouvé. L'événement Stop est créé via le Simulateur :: Arrêter
(temps d'arrêt); la fonction.

Il y a un cas typique où Simulateur :: Arrêter est absolument nécessaire d'arrêter le
simulation : lorsqu'il y a un événement auto-entretenu. Événements autonomes (ou récurrents)
sont des événements qui se reprogramment toujours. En conséquence, ils gardent toujours l'événement
file d'attente non vide.

Il existe de nombreux protocoles et modules contenant des événements récurrents, par exemple :

· FlowMonitor - vérification périodique des paquets perdus

· RIPng - diffusion périodique de la mise à jour des tables de routage

· etc.

Dans ces cas, Simulateur :: Arrêter est nécessaire pour arrêter proprement la simulation. Dans
en plus, quand ns-3 est en mode émulation, le Simulateur en temps réel est utilisé pour garder le
horloge de simulation alignée sur l'horloge de la machine, et Simulateur :: Arrêter est nécessaire d'arrêter
le processus.

De nombreux programmes de simulation du didacticiel n'appellent pas explicitement Simulateur :: Arrêter,
car la file d'attente d'événements manquera automatiquement d'événements. Cependant, ces programmes seront
accepter également un appel à Simulateur :: Arrêter. Par exemple, la déclaration supplémentaire suivante dans
le premier exemple de programme programmera un arrêt explicite à 11 secondes :

+ Simulateur ::Stop (Secondes (11.0));
Simulateur::Exécuter ();
Simulateur :: Détruire ();
0 revenir;
}

Ce qui précède ne changera pas réellement le comportement de ce programme, puisque ce
la simulation se termine naturellement au bout de 10 secondes. Mais si vous deviez modifier l'heure d'arrêt dans
la déclaration ci-dessus de 11 secondes à 1 seconde, vous remarquerez que la simulation
s'arrête avant qu'une sortie ne soit imprimée à l'écran (puisque la sortie se produit autour du temps 2
secondes de temps de simulation).

Il est important d'appeler Simulateur :: Arrêter avant appel Simulateur :: Exécuter; autrement,
Simulateur :: Exécuter ne peut jamais rendre le contrôle au programme principal pour exécuter l'arrêt !

Développement Votre scénario
Nous avons simplifié la création de vos scripts simples. Tout ce que vous avez à faire est de déposer votre
script dans le répertoire de travail et il sera automatiquement construit si vous exécutez Waf.
Essayons. Copie exemples/tutoriel/first.cc into the gratter répertoire après modification
dans le répertoire de niveau supérieur.

$cd../ ..
$ cp exemples/tutoriel/first.cc scratch/myfirst.cc

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

$ ./waf

Vous devriez voir des messages signalant que votre mon premier exemple a été construit avec succès.

Waf : Entrer dans le répertoire `/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 : quitter le répertoire `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' terminé avec succès (2.357s)

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

$ ./waf --run scratch/myfirst

Vous devriez voir une sortie :

Waf : Entrer dans le répertoire `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf : quitter le répertoire `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' terminé avec succès (0.418s)
Envoyé 1024 octets à 10.1.1.2
Reçu 1024 octets de 10.1.1.1
Reçu 1024 octets de 10.1.1.2

Ici, vous voyez que le système de construction vérifie que le fichier a été construit et
puis l'exécute. Vous voyez le composant de journalisation sur le client echo indiquer qu'il a envoyé
un paquet de 1024 octets au serveur Echo sur 10.1.1.2. Vous voyez également le composant de journalisation
sur le serveur d'écho dire qu'il a reçu les 1024 octets de 10.1.1.1. Le serveur d'écho
fait écho silencieusement au paquet et vous voyez le journal du client d'écho qu'il a reçu son paquet
retour du serveur.

Ns-3 Source Code
Maintenant que vous avez utilisé certains des ns-3 aides, vous voudrez peut-être jeter un œil à certains des
code source qui implémente cette fonctionnalité. Le code le plus récent peut être parcouru sur
notre serveur web au lien suivant : http://code.nsnam.org/ns-3-dev. Là, tu verras
la page de résumé Mercurial pour notre ns-3 arbre de développement.

En haut de la page, vous verrez un certain nombre de liens,

résumé | journal abrégé | journal des modifications | graphique | balises | des dossiers

Allez-y et sélectionnez le fichiers lien. C'est ce que le haut niveau de la plupart de nos
code source jettera un coup d'oeil:

drwxr-xr-x [haut]
fichiers python de liaisons drwxr-xr-x
fichiers doc drwxr-xr-x
fichiers d'exemples drwxr-xr-x
fichiers drwxr-xr-x ns3
fichiers de travail drwxr-xr-x
fichiers src drwxr-xr-x
fichiers utilitaires drwxr-xr-x
-rw-r--r-- 2009-07-01 12:47 +0200 560 .hgignore fichier | révisions | annoter
-rw-r--r-- 2009-07-01 12:47 +0200 1886 fichier .hgtags | révisions | annoter
-rw-r--r-- 2009-07-01 12:47 +0200 1276 Fichier AUTEURS | révisions | annoter
-rw-r--r-- 2009-07-01 12:47 +0200 30961 CHANGES.html fichier | révisions | annoter
-rw-r--r-- 2009-07-01 12:47 +0200 17987 Fichier de LICENCE | révisions | annoter
-rw-r--r-- 2009-07-01 12:47 +0200 3742 Fichier LISEZMOI | révisions | annoter
-rw-r--r-- 2009-07-01 12:47 +0200 16171 RELEASE_NOTES fichier | révisions | annoter
-rw-r--r-- 2009-07-01 12:47 +0200 6 VERSION fichier | révisions | annoter
-rwxr-xr-x 2009-07-01 12:47 +0200 88110 fichier waf | révisions | annoter
-rwxr-xr-x 2009/07/01 12:47 +0200 28 fichier waf.bat | révisions | annoter
-rw-r--r-- 2009/07/01 12:47 +0200 35395 fichier wscript | révisions | annoter
-rw-r--r-- 2009-07-01 12:47 +0200 7673 fichier wutils.py | révisions | annoter

Nos exemples de scripts se trouvent dans le exemples annuaire. Si vous cliquez sur exemples vous verrez
une liste de sous-répertoires. L'un des fichiers de tutoriel le sous-répertoire est premier.cc. Si vous
cliquez sur premier.cc vous trouverez le code que vous venez de parcourir.

Le code source se trouve principalement dans le src annuaire. Vous pouvez afficher le code source soit en
en cliquant sur le nom du répertoire ou en cliquant sur le fichiers lien à droite du
nom du répertoire. Si vous cliquez sur le src répertoire, vous serez redirigé vers la liste des
le src sous-répertoires. Si vous cliquez ensuite sur core sous-répertoire, vous trouverez une liste de
des dossiers. Le premier fichier que vous trouverez (à ce jour) est abandonner.h. Si vous cliquez sur le
abandonner.h lien, 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 assistants que nous avons utilisés dans ce chapitre se trouve dans le
src/applications/aide annuaire. N'hésitez pas à fouiller dans l'arborescence des répertoires pour obtenir
une sensation pour ce qui est là et le style de ns-3 programmes.

AJUSTER


En utilisant le Journal Module
Nous avons déjà jeté un bref coup d'œil sur ns-3 module de journalisation tout en parcourant le
premier.cc scénario. Nous allons maintenant regarder de plus près et voir quels types de cas d'utilisation le
sous-système de journalisation a été conçu pour couvrir.

Journal Aperçu
De nombreux grands systèmes prennent en charge une sorte de fonction de journalisation des messages, et ns-3 n'est pas un
exception. Dans certains cas, seuls les messages d'erreur sont consignés dans la "console opérateur" (qui
est typiquement stderr dans les systèmes basés sur Unix). Dans d'autres systèmes, des messages d'avertissement peuvent être
sortie ainsi que des messages d'information plus détaillés. Dans certains cas, les installations d'exploitation forestière
sont utilisés pour générer des messages de débogage qui peuvent rapidement transformer la sortie en flou.

ns-3 est d'avis que tous ces niveaux de verbosité sont utiles et nous fournissons une
approche sélectionnable à plusieurs niveaux de la journalisation des messages. La journalisation peut être complètement désactivée,
activé composant par composant ou activé globalement ; et il fournit sélectionnable
niveaux de verbosité. le ns-3 log module fournit un outil simple et relativement facile à utiliser
moyen d'obtenir des informations utiles de votre simulation.

Vous devez comprendre que nous fournissons un mécanisme à usage général --- traçage --- pour
obtenir des données de vos modèles qui devraient être préférées pour la sortie de simulation (voir le
section tutoriel Utilisation du système de traçage pour plus de détails sur notre système de traçage).
La journalisation doit être préférée pour les informations de débogage, les avertissements, les messages d'erreur ou tout autre
moment où vous souhaitez obtenir facilement un message rapide de vos scripts ou modèles.

Il existe actuellement sept niveaux de messages de journal de verbosité croissante définis dans le
système.

· LOG_ERROR --- Journaliser les messages d'erreur (macro associée : NS_LOG_ERROR) ;

· LOG_WARN --- Journaliser les messages d'avertissement (macro associée : NS_LOG_WARN) ;

· LOG_DEBUG --- Journaliser des messages de débogage ad hoc relativement rares (macro associée :
NS_LOG_DEBUG);

· LOG_INFO --- Enregistrer les messages d'information sur la progression du programme (macro associée :
NS_LOG_INFO);

· LOG_FUNCTION --- Enregistre un message décrivant chaque fonction appelée (deux macros associées :
NS_LOG_FUNCTION, utilisé pour les fonctions membres, et NS_LOG_FUNCTION_NOARGS, utilisé pour les fonctions statiques
les fonctions);

· LOG_LOGIC -- Messages du journal décrivant le flux logique au sein d'une fonction (macro associée :
NS_LOG_LOGIC );

· LOG_ALL --- Enregistrez tout ce qui est mentionné ci-dessus (pas de macro associée).

Pour chaque LOG_TYPE, il existe également LOG_LEVEL_TYPE qui, s'il est utilisé, permet la journalisation de tous les
niveaux au-dessus en plus de son niveau. (En conséquence, LOG_ERROR et
LOG_LEVEL_ERROR ainsi que LOG_ALL et LOG_LEVEL_ALL sont fonctionnellement équivalents.) Pour
Par exemple, l'activation de LOG_INFO n'activera que les messages fournis par la macro NS_LOG_INFO, tandis que
l'activation de LOG_LEVEL_INFO activera également les messages fournis par NS_LOG_DEBUG, NS_LOG_WARN
et les macros NS_LOG_ERROR.

Nous fournissons également une macro de journalisation inconditionnelle qui est toujours affichée, quel que soit
les niveaux de journalisation ou la sélection des composants.

· NS_LOG_UNCOND -- Enregistre le message associé sans condition (aucun niveau de journal associé).

Chaque niveau peut être demandé individuellement ou cumulativement ; et la journalisation peut être configurée à l'aide d'un
variable d'environnement shell (NS_LOG) ou en enregistrant l'appel de la fonction système. Comme on l'a vu
plus tôt dans le tutoriel, le système de journalisation a une documentation Doxygen et serait maintenant un
bon moment pour consulter la documentation du module de journalisation si vous ne l'avez pas encore fait.

Maintenant que vous avez lu la documentation en détail, utilisons une partie de ces connaissances
pour obtenir des informations intéressantes scratch/monpremier.cc exemple de script que vous avez
déjà construit.

Activation Journal
Utilisons la variable d'environnement NS_LOG pour activer un peu plus de journalisation, mais d'abord, juste pour
prenez nos repères, allez-y et exécutez le dernier script comme vous l'avez fait précédemment,

$ ./waf --run scratch/myfirst

Vous devriez voir la sortie maintenant familière du premier ns-3 exemple de programme

$ Waf : Entrer dans le répertoire `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf : quitter le répertoire `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' terminé avec succès (0.413s)
Envoyé 1024 octets à 10.1.1.2
Reçu 1024 octets de 10.1.1.1
Reçu 1024 octets de 10.1.1.2

Il s'avère que les messages "Envoyé" et "Reçu" que vous voyez ci-dessus sont en fait enregistrés
messages de la UdpEchoClientApplicationUdpEchoClientApplication et votre UdpEchoServerApplicationUdpEchoServerApplication. Nous pouvons demander au
application client, par exemple, pour imprimer plus d'informations en définissant son niveau de journalisation
via la variable d'environnement NS_LOG.

Je vais supposer à partir de maintenant que vous utilisez un shell de type sh qui utilise
la syntaxe "VARIABLE=valeur". Si vous utilisez un shell de type csh, vous devrez
convertir mes exemples en syntaxe "setenv VARIABLE value" requise par ces shells.

À l'heure actuelle, l'application cliente d'écho UDP répond à la ligne de code suivante dans
scratch/monpremier.cc,

LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);

Cette ligne de code permet au LOG_LEVEL_INFO niveau de journalisation. Quand on passe un logging
indicateur de niveau, nous activons en fait le niveau donné et tous les niveaux inférieurs. Dans ce cas,
nous avons activé NS_LOG_INFO, NS_LOG_DEBUG, NS_LOG_WARN et votre NS_LOG_ERROR. Nous pouvons augmenter
le niveau de journalisation et obtenir plus d'informations sans modifier le script et recompiler en
définir la variable d'environnement NS_LOG comme ceci :

$ export NS_LOG=UdpEchoClientApplication=level_all

Cela définit la variable d'environnement du shell NS_LOG à la chaîne,

UdpEchoClientApplication=level_all

Le côté gauche de l'affectation est le nom du composant de journalisation que nous voulons définir,
et le côté droit est le drapeau que nous voulons utiliser. Dans ce cas, nous allons activer
tous les niveaux de débogage de l'application. Si vous exécutez le script avec NS_LOG défini
de cette façon, le ns-3 le système de journalisation captera le changement et vous devriez voir ce qui suit
sortie:

Waf : Entrer dans le répertoire `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf : quitter le répertoire `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' terminé avec succès (0.404s)
UdpEchoClientApplication : UdpEchoClient()
UdpEchoClientApplication :Définir la taille des données(1024)
UdpEchoClientApplication:StartApplication()
UdpEchoClientApplication:ScheduleTransmit()
UdpEchoApplicationClient :Envoyer()
Envoyé 1024 octets à 10.1.1.2
Reçu 1024 octets de 10.1.1.1
UdpEchoClientApplication:HandleRead(0x6241e0, 0x624a20)
Reçu 1024 octets de 10.1.1.2
UdpEchoApplicationClient : ArrêterApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoClientApplication :~UdpEchoClient()

Les informations de débogage supplémentaires fournies par l'application proviennent de NS_LOG_FUNCTION
niveau. Cela montre chaque fois qu'une fonction dans l'application est appelée pendant le script
exécution. Généralement, l'utilisation de (au moins) NS_LOG_FUNCTION(this) dans les fonctions membres est
préféré. Utilisez NS_LOG_FUNCTION_NOARGS() uniquement dans les fonctions statiques. Notez cependant que
il n'y a pas d'exigences dans le ns-3 système que les modèles doivent prendre en charge
fonctionnalité de journalisation. La décision concernant la quantité d'informations enregistrées est laissée à
le développeur de modèle individuel. Dans le cas des applications d'écho, une bonne partie du journal
sortie est disponible.

Vous pouvez maintenant voir un journal des appels de fonction qui ont été faits à l'application. Si vous
regardez attentivement, vous remarquerez un seul deux-points entre la chaîne UdpEchoClientApplicationUdpEchoClientApplication
et le nom de la méthode où vous auriez pu vous attendre à un opérateur de portée C++ (::). C'est
intentionnel.

Le nom n'est pas réellement un nom de classe, c'est un nom de composant de journalisation. Quand il y a un
correspondance biunivoque entre un fichier source et une classe, ce sera généralement la
nom de classe, mais vous devez comprendre qu'il ne s'agit pas réellement d'un nom de classe et qu'il existe un
deux-points simples au lieu de deux-points doubles pour vous rappeler de manière relativement subtile de
séparez conceptuellement le nom du composant de journalisation du nom de la classe.

Il s'avère que dans certains cas, il peut être difficile de déterminer quelle méthode
génère un message de journal. Si vous regardez dans le texte ci-dessus, vous vous demandez peut-être où se trouve la chaîne
"Reçu 1024 octets de 10.1.1.2" vient. Vous pouvez résoudre ce problème en faisant un OU
préfixe_fonc niveau dans le NS_LOG variables d'environnement. Essayez de faire ce qui suit,

$ export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func'

Notez que les guillemets sont obligatoires puisque la barre verticale que nous utilisons pour indiquer un OU
opération est également un connecteur de tuyau Unix.

Maintenant, si vous exécutez le script, vous verrez que le système de journalisation s'assure que chaque
Le message du composant de journal donné est précédé du nom du composant.

Waf : Entrer dans le répertoire `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf : quitter le répertoire `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' terminé avec succès (0.417s)
UdpEchoClientApplication : UdpEchoClient()
UdpEchoClientApplication :Définir la taille des données(1024)
UdpEchoClientApplication:StartApplication()
UdpEchoClientApplication:ScheduleTransmit()
UdpEchoApplicationClient :Envoyer()
UdpEchoClientApplication:Send() : Envoyé 1024 octets à 10.1.1.2
Reçu 1024 octets de 10.1.1.1
UdpEchoClientApplication:HandleRead(0x6241e0, 0x624a20)
UdpEchoClientApplication:HandleRead() : 1024 octets reçus de 10.1.1.2
UdpEchoApplicationClient : ArrêterApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoClientApplication :~UdpEchoClient()

Vous pouvez maintenant voir tous les messages provenant de l'application client d'écho UDP sont
identifié comme tel. Le message "Received 1024 bytes from 10.1.1.2" est maintenant clairement
identifié comme provenant de l'application client d'écho. Le message restant doit être
provenant de l'application serveur d'écho UDP. Nous pouvons activer ce composant en entrant un
liste de composants séparés par deux-points dans la variable d'environnement NS_LOG.

$ export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func :
UdpEchoServerApplication=level_all|prefix_func'

Avertissement : Vous devrez supprimer la nouvelle ligne après le : dans l'exemple de texte ci-dessus qui
n'est là qu'à des fins de formatage de document.

Maintenant, si vous exécutez le script, vous verrez tous les messages de journal du client echo
et les applications serveur. Vous pouvez voir que cela peut être très utile dans le débogage des problèmes.

Waf : Entrer dans le répertoire `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf : quitter le répertoire `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' terminé avec succès (0.406s)
UdpEchoServerApplication : UdpEchoServer()
UdpEchoClientApplication : UdpEchoClient()
UdpEchoClientApplication :Définir la taille des données(1024)
UdpEchoServerApplication:StartApplication()
UdpEchoClientApplication:StartApplication()
UdpEchoClientApplication:ScheduleTransmit()
UdpEchoApplicationClient :Envoyer()
UdpEchoClientApplication:Send() : Envoyé 1024 octets à 10.1.1.2
UdpEchoServerApplication:HandleRead() : 1024 octets reçus de 10.1.1.1
UdpEchoServerApplication:HandleRead() : Paquet en écho
UdpEchoClientApplication : HandleRead (0x624920, 0x625160)
UdpEchoClientApplication:HandleRead() : 1024 octets reçus de 10.1.1.2
UdpEchoServerApplication : StopApplication()
UdpEchoApplicationClient : ArrêterApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoServerApplication:DoDispose()
UdpEchoClientApplication :~UdpEchoClient()
UdpEchoServerApplication :~UdpEchoServer()

Il est aussi parfois utile de pouvoir voir le temps de simulation auquel un message de log
est généré. Vous pouvez le faire en faisant un OR dans le bit prefix_time.

$ export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func|prefix_time :
UdpEchoServerApplication=level_all|prefix_func|prefix_time'

Encore une fois, vous devrez supprimer la nouvelle ligne ci-dessus. Si vous exécutez le script maintenant, vous devriez
voir la sortie suivante :

Waf : Entrer dans le répertoire `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf : quitter le répertoire `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' terminé avec succès (0.418s)
0s UdpEchoServerApplication : UdpEchoServer()
0s UdpEchoClientApplication : UdpEchoClient()
0s UdpEchoClientApplication :Définir la taille des données(1024)
1s UdpEchoServerApplication:StartApplication()
2s UdpEchoClientApplication:StartApplication()
2s UdpEchoClientApplication:ScheduleTransmit()
2s UdpEchoApplicationClient:Envoyer()
2s UdpEchoClientApplication:Send() : Envoyé 1024 octets à 10.1.1.2
2.00369s UdpEchoServerApplication:HandleRead() : 1024 octets reçus de 10.1.1.1
2.00369s UdpEchoServerApplication:HandleRead() : Paquet en écho
2.00737s UdpEchoClientApplication:HandleRead(0x624290, 0x624ad0)
2.00737s UdpEchoClientApplication:HandleRead() : 1024 octets reçus de 10.1.1.2
10s UdpEchoServerApplication : StopApplication()
10s UdpEchoClientApplication : StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoServerApplication:DoDispose()
UdpEchoClientApplication :~UdpEchoClient()
UdpEchoServerApplication :~UdpEchoServer()

Vous pouvez voir que le constructeur de UdpEchoServer a été appelé à un moment de simulation de
0 secondes. Cela se produit en fait avant le début de la simulation, mais le temps est
affiché comme zéro seconde. Il en va de même pour le message du constructeur UdpEchoClient.

Rappelons que le scratch/premier.cc le script a démarré l'application du serveur d'écho à une seconde
dans la simulation. Vous pouvez maintenant voir que le Lancer l'application méthode du serveur est,
en fait, appelé à une seconde. Vous pouvez également voir que l'application client d'écho est
commencé à un temps de simulation de deux secondes comme nous l'avons demandé dans le script.

Vous pouvez maintenant suivre la progression de la simulation à partir du ProgrammerTransmettre appeler le
client qui appelle Envoyer à la PoignéeLire rappel dans l'application du serveur d'écho. Noter
que le temps écoulé pour que le paquet soit envoyé sur la liaison point à point est de 3.69
millisecondes. Vous voyez le serveur d'écho enregistrer un message vous indiquant qu'il a fait écho
le paquet, puis, après un autre délai de canal, vous voyez le client d'écho recevoir le
paquet en écho dans son PoignéeLire méthode.

Il y a beaucoup de choses qui se passent sous les couvertures dans cette simulation que vous n'êtes pas
voir aussi. Vous pouvez très facilement suivre l'ensemble du processus en activant tous les
journalisation des composants du système. Essayez de régler le NS_LOG variable comme suit,

$ export 'NS_LOG=*=level_all|prefix_func|prefix_time'

L'astérisque ci-dessus est le caractère générique du composant de journalisation. Cela activera tous les
enregistrement de tous les composants utilisés dans la simulation. Je ne reproduirai pas la sortie
ici (au moment d'écrire ces lignes, il produit 1265 lignes de sortie pour l'écho de paquet unique) mais
vous pouvez rediriger ces informations dans un fichier et le parcourir avec votre favori
éditeur si vous le souhaitez,

$ ./waf --run scratch/myfirst > déconnexion 2>&1

Personnellement, j'utilise cette version extrêmement détaillée de la journalisation lorsqu'on me présente un
problème et je n'ai aucune idée où les choses vont mal. Je peux suivre l'évolution du
coder assez facilement sans avoir à définir de points d'arrêt et à parcourir le code dans un débogueur.
Je peux simplement éditer la sortie dans mon éditeur préféré et rechercher les choses que j'attends,
et voir des choses se produire auxquelles je ne m'attends pas. Quand j'ai une idée générale de ce qui est
se passe mal, je passe à un débogueur pour un examen approfondi du problème.
Ce type de sortie peut être particulièrement utile lorsque votre script fait quelque chose de complètement
inattendu. Si vous utilisez un débogueur, vous risquez de manquer une excursion inattendue
complètement. L'enregistrement de l'excursion la rend rapidement visible.

L'ajout de Journal à votre Code
Vous pouvez ajouter une nouvelle journalisation à vos simulations en faisant des appels au composant de journal via
plusieurs macros. Faisons-le dans le mapremière.cc script que nous avons dans le gratter répertoire.

Rappelez-vous que nous avons défini un composant de journalisation dans ce script :

NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");

Vous savez maintenant que vous pouvez activer toute la journalisation pour ce composant en définissant le paramètre
NS_LOG environnement variable aux différents niveaux. Allons-y et ajoutons un peu de journalisation à
le scénario. La macro utilisée pour ajouter un message de journal de niveau informationnel est NS_LOG_INFO. Aller
devant et ajoutez-en un (juste avant de commencer à créer les nœuds) qui vous indique que le script
est "Création d'une topologie". Cela se fait comme dans cet extrait de code,

Ouvert scratch/monpremier.cc dans votre éditeur préféré et ajoutez la ligne,

NS_LOG_INFO ("Création de la topologie");

juste avant les lignes,

nœuds NodeContainer ;
nœuds.Créer (2);

Maintenant, construisez le script en utilisant waf et effacez le NS_LOG variable pour désactiver le torrent de
journalisation que nous avons précédemment activée :

$ ./waf
$ exporter NS_LOG=

Maintenant, si vous exécutez le script,

$ ./waf --run scratch/myfirst

vous serez pas voir votre nouveau message depuis son composant de journalisation associé
(ExemplePremierScript) n'a pas été activé. Pour voir votre message, vous devrez
activer le ExemplePremierScript composant de journalisation avec un niveau supérieur ou égal à
NS_LOG_INFO. Si vous voulez juste voir ce niveau particulier de journalisation, vous pouvez l'activer
par,

$ export NS_LOG=FirstScriptExample=info

Si vous exécutez maintenant le script, vous verrez votre nouveau message de journal "Creating Topology",

Waf : Entrer dans le répertoire `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf : quitter le répertoire `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' terminé avec succès (0.404s)
Création d'une topologie
Envoyé 1024 octets à 10.1.1.2
Reçu 1024 octets de 10.1.1.1
Reçu 1024 octets de 10.1.1.2

En utilisant Command Gamme Arguments
Primordial Réglage par défaut Attributs
Une autre façon de changer la façon dont ns-3 les scripts se comportent sans modification et la construction se fait via
commander en ligne arguments. Nous fournissons un mécanisme pour analyser les arguments de la ligne de commande et
définit automatiquement les variables locales et globales en fonction de ces arguments.

La première étape de l'utilisation du système d'arguments de la ligne de commande consiste à déclarer la ligne de commande
analyseur. Cela se fait assez simplement (dans votre programme principal) comme dans le code suivant,

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


cmd de ligne de commande ;
cmd.Parse (argc, argv);


}

Ce simple extrait de deux lignes est en fait très utile en soi. Il ouvre la porte à la
ns-3 variable globale et Attribut systèmes. Allez-y et ajoutez ces deux lignes de code à
le scratch/monpremier.cc script au début de principal. Allez-y, créez le script et exécutez
mais demandez de l'aide au script de la manière suivante,

$ ./waf --run "scratch/myfirst --PrintHelp"

Cela demandera à Waf d'exécuter le gratter/ma première script et passez l'argument de la ligne de commande
--ImprimerAide au scénario. Les guillemets sont nécessaires pour déterminer quel programme obtient quel
argument. L'analyseur de ligne de commande verra maintenant le --ImprimerAide argumenter et répondre avec,

Waf : Entrer dans le répertoire `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf : quitter le répertoire `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' terminé avec succès (0.413s)
TcpL4Protocol : TcpStateMachine()
CommandLine:HandleArgument() : nom de l'argument du handle=valeur PrintHelp=
--PrintHelp : imprime ce message d'aide.
--PrintGroups : imprime la liste des groupes.
--PrintTypeIds : imprime tous les TypeIds.
--PrintGroup=[groupe] : Imprime tous les TypeIds du groupe.
--PrintAttributes=[typeid] : affiche tous les attributs de typeid.
--PrintGlobals : imprime la liste des variables globales.

Concentrons-nous sur le --PrintAttributes option. Nous avons déjà fait allusion à la ns-3 Attribut
système tout en parcourant le premier.cc scénario. Nous avons examiné les lignes suivantes de
code,

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

et a mentionné que Débit de données était en fait un Attribut des PointVersPointNetDevice. Allons
utilisez l'analyseur d'arguments de la ligne de commande pour examiner le Attributs des
PointToPointNetDevice. La liste d'aide indique que nous devrions fournir un ID de type. Ce
correspond au nom de classe de la classe à laquelle le Attributs appartiennent. Dans ce cas
ce sera ns3 :: PointToPointNetDevice. Allons-y et tapons,

$ ./waf --run "scratch/myfirst --PrintAttributes=ns3::PointToPointNetDevice"

Le système imprimera tous les Attributs de ce type de dispositif net. Parmi les
Attributs vous verrez la liste est,

--ns3::PointToPointNetDevice::DataRate=[32768bps] :
Le débit de données par défaut pour les liaisons point à point

Il s'agit de la valeur par défaut qui sera utilisée lorsqu'un PointVersPointNetDevice est créé dans le
système. Nous avons remplacé cette valeur par défaut par la Attribut mise dans le PointÀPointHelper
au dessus. Utilisons les valeurs par défaut pour les appareils point à point et les canaux en
suppression du DéfinirDeviceAttribute appel et le DéfinirChannelAttribute appel du mapremière.cc
nous avons dans le répertoire scratch.

Votre script devrait maintenant simplement déclarer le PointÀPointHelper et ne rien faire set
comme dans l'exemple suivant,



nœuds NodeContainer ;
nœuds.Créer (2);

PointToPointHelper pointToPoint ;

Périphériques NetDeviceContainer ;
devices = pointToPoint.Install (nœuds);



Allez-y et construisez le nouveau script avec Waf (./waff) et revenons en arrière et activons certains
journalisation à partir de l'application du serveur d'écho UDP et activez le préfixe horaire.

$ export 'NS_LOG=UdpEchoServerApplication=level_all|prefix_time'

Si vous exécutez le script, vous devriez maintenant voir la sortie suivante,

Waf : Entrer dans le répertoire `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf : quitter le répertoire `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' terminé avec succès (0.405s)
0s UdpEchoServerApplication : UdpEchoServer()
1s UdpEchoServerApplication:StartApplication()
Envoyé 1024 octets à 10.1.1.2
2.25732s Reçu 1024 octets de 10.1.1.1
2.25732s Paquet en écho
Reçu 1024 octets de 10.1.1.2
10s UdpEchoServerApplication : StopApplication()
UdpEchoServerApplication:DoDispose()
UdpEchoServerApplication :~UdpEchoServer()

Rappelez-vous que la dernière fois que nous avons regardé l'heure de simulation à laquelle le paquet a été
reçu par le serveur d'écho, il était à 2.00369 secondes.

2.00369s UdpEchoServerApplication:HandleRead() : 1024 octets reçus de 10.1.1.1

Maintenant, il reçoit le paquet à 2.25732 secondes. C'est parce que nous venons de laisser tomber le
débit de données du PointVersPointNetDevice jusqu'à sa valeur par défaut de 32768 bits par seconde à partir de
cinq mégabits par seconde.

Si nous devions fournir un nouveau Débit de données en utilisant la ligne de commande, nous pourrions accélérer notre simulation
à nouveau. Nous le faisons de la manière suivante, selon la formule impliquée par l'aide
article:

$ ./waf --run "scratch/myfirst --ns3::PointToPointNetDevice::DataRate=5Mbps"

Cela définira la valeur par défaut du Débit de données Attribut retour à cinq mégabits par
seconde. Êtes-vous surpris du résultat ? Il s'avère que pour obtenir l'original
comportement du script, nous devrons définir le délai de vitesse de la lumière du canal
ainsi que. Nous pouvons demander au système de ligne de commande d'imprimer le Attributs de la chaîne
tout comme nous l'avons fait pour le périphérique net :

$ ./waf --run "scratch/myfirst --PrintAttributes=ns3::PointToPointChannel"

On découvre le Retard Attribut du canal est défini de la manière suivante :

--ns3::PointToPointChannel::Delay=[0ns] :
Délai de transmission à travers le canal

Nous pouvons ensuite définir ces deux valeurs par défaut via le système de ligne de commande,

$ ./waf --run "scratch/monpremier
--ns3 ::PointToPointNetDevice ::DataRate=5Mbps
--ns3::PointToPointChannel::Delay=2ms"

auquel cas nous récupérons le timing que nous avions lorsque nous avons défini explicitement le Débit de données et votre Retard
dans le script:

Waf : Entrer dans le répertoire `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf : quitter le répertoire `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' terminé avec succès (0.417s)
0s UdpEchoServerApplication : UdpEchoServer()
1s UdpEchoServerApplication:StartApplication()
Envoyé 1024 octets à 10.1.1.2
2.00369s Reçu 1024 octets de 10.1.1.1
2.00369s Paquet en écho
Reçu 1024 octets de 10.1.1.2
10s UdpEchoServerApplication : StopApplication()
UdpEchoServerApplication:DoDispose()
UdpEchoServerApplication :~UdpEchoServer()

Notez que le paquet est à nouveau reçu par le serveur à 2.00369 secondes. Nous pourrions
définir réellement l'un des Attributs utilisé dans le script de cette manière. On pourrait notamment
définir la UdpEchoClient Attribut MaxPaquets à une autre valeur que un.

Comment vous y prendriez-vous ? Essaie. N'oubliez pas que vous devez commenter l'endroit
nous remplaçons la valeur par défaut Attribut et définir explicitement MaxPaquets dans le scénario. Alors vous
avoir à reconstruire le script. Vous devrez également trouver la syntaxe pour définir réellement
la nouvelle valeur d'attribut par défaut à l'aide de la fonction d'aide de la ligne de commande. Une fois que vous avez ceci
compris que vous devriez être en mesure de contrôler le nombre de paquets renvoyés par la commande
ligne. Puisque nous sommes des gens sympas, nous vous dirons que votre ligne de commande devrait finir par ressembler à
quelque chose comme,

$ ./waf --run "scratch/monpremier
--ns3 ::PointToPointNetDevice ::DataRate=5Mbps
--ns3 ::PointToPointChannel ::Délai=2 ms
--ns3::UdpEchoClient::MaxPackets=2"

Crochet Votre Propre VALEURS
Vous pouvez également ajouter vos propres crochets au système de ligne de commande. Cela se fait tout simplement en
en utilisant l' AddValue méthode à l'analyseur de ligne de commande.

Utilisons cette fonction pour spécifier le nombre de paquets à renvoyer dans un tout autre
façon. Ajoutons une variable locale appelée nPaquets à la principal une fonction. Nous allons initialiser
à un pour correspondre à notre comportement par défaut précédent. Pour permettre à l'analyseur de ligne de commande de
changez cette valeur, nous devons accrocher la valeur dans l'analyseur. Nous le faisons en ajoutant un appel
à AddValue. Allez-y et changez le scratch/monpremier.cc script pour commencer par le
code suivant,

int
principal (int argc, char *argv[])
{
uint32_t nPaquets = 1 ;

cmd de ligne de commande ;
cmd.AddValue("nPackets", "Nombre de paquets à renvoyer", nPackets);
cmd.Parse (argc, argv);



Faites défiler jusqu'au point du script où nous définissons le MaxPaquets Attribut et le changer
de sorte qu'il est défini sur la variable nPaquets au lieu de la constante 1 comme indiqué ci-dessous.

echoClient.SetAttribute ("MaxPackets", UintegerValue (nPackets));

Maintenant, si vous exécutez le script et fournissez le --ImprimerAide argument, vous devriez voir votre nouveau
Utilisateur Argument répertoriés dans l'écran d'aide.

Essayer,

$ ./waf --run "scratch/myfirst --PrintHelp"

Waf : Entrer dans le répertoire `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf : quitter le répertoire `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' terminé avec succès (0.403s)
--PrintHelp : imprime ce message d'aide.
--PrintGroups : imprime la liste des groupes.
--PrintTypeIds : imprime tous les TypeIds.
--PrintGroup=[groupe] : Imprime tous les TypeIds du groupe.
--PrintAttributes=[typeid] : affiche tous les attributs de typeid.
--PrintGlobals : imprime la liste des variables globales.
Argumentation de l'utilisateur :
--nPackets : nombre de paquets à renvoyer

Si vous souhaitez spécifier le nombre de paquets à envoyer en écho, vous pouvez maintenant le faire en définissant le paramètre
--nPaquets argument dans la ligne de commande,

$ ./waf --run "scratch/myfirst --nPackets=2"

Vous devriez maintenant voir

Waf : Entrer dans le répertoire `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf : quitter le répertoire `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' terminé avec succès (0.404s)
0s UdpEchoServerApplication : UdpEchoServer()
1s UdpEchoServerApplication:StartApplication()
Envoyé 1024 octets à 10.1.1.2
2.25732s Reçu 1024 octets de 10.1.1.1
2.25732s Paquet en écho
Reçu 1024 octets de 10.1.1.2
Envoyé 1024 octets à 10.1.1.2
3.25732s Reçu 1024 octets de 10.1.1.1
3.25732s Paquet en écho
Reçu 1024 octets de 10.1.1.2
10s UdpEchoServerApplication : StopApplication()
UdpEchoServerApplication:DoDispose()
UdpEchoServerApplication :~UdpEchoServer()

Vous avez maintenant renvoyé en écho deux paquets. Assez facile, n'est-ce pas ?

Vous pouvez voir que si vous êtes un ns-3 utilisateur, vous pouvez utiliser le système d'arguments de la ligne de commande pour
contrôler les valeurs globales et Attributs. Si vous êtes un auteur de modèle, vous pouvez ajouter de nouveaux
Attributs à ta Objets et ils seront automatiquement disponibles pour le réglage par votre
utilisateurs via le système de ligne de commande. Si vous êtes un auteur de script, vous pouvez ajouter de nouveaux
variables à vos scripts et connectez-les au système de ligne de commande sans douleur.

En utilisant le Traçant Système
L'intérêt de la simulation est de générer une sortie pour une étude plus approfondie, et le ns-3
le système de traçage est un mécanisme principal pour cela. Depuis ns-3 est un programme C++, standard
des installations pour générer une sortie à partir de programmes C++ pourraient être utilisées :

#inclure

int main ()
{

std::cout << "La valeur de x est " << x << std::endl;

}

Vous pouvez même utiliser le module de journalisation pour ajouter une petite structure à votre solution. Là
de nombreux problèmes bien connus générés par de telles approches et nous avons donc fourni une
sous-système générique de suivi des événements pour résoudre les problèmes que nous estimions importants.

Les objectifs fondamentaux de la ns-3 système de traçage sont :

· Pour les tâches de base, le système de traçage doit permettre à l'utilisateur de générer un traçage standard
pour les sources de traçage courantes et pour personnaliser les objets qui génèrent le traçage ;

· Les utilisateurs intermédiaires doivent pouvoir étendre le système de traçage pour modifier le format de sortie
générés, ou d'insérer de nouvelles sources de traçage, sans modifier le cœur du
simulateur;

· Les utilisateurs avancés peuvent modifier le noyau du simulateur pour ajouter de nouvelles sources et puits de traçage.

Notre ns-3 système de traçage repose sur les concepts de sources de traçage indépendantes et
tracer les puits et un mécanisme uniforme pour connecter les sources aux puits. Les sources de traces sont
entités qui peuvent signaler des événements qui se produisent dans une simulation et donner accès à
données sous-jacentes intéressantes. Par exemple, une source de trace peut indiquer quand un paquet est
reçu par un dispositif réseau et fournir un accès au contenu du paquet pour une trace intéressée
les puits.

Les sources de trace ne sont pas utiles en elles-mêmes, elles doivent être "connectées" à d'autres éléments de
code qui fait réellement quelque chose d'utile avec les informations fournies par le récepteur. Trace
les puits sont des consommateurs des événements et des données fournis par les sources de trace. Par exemple,
on pourrait créer un puits de trace qui (lorsqu'il est connecté à la source de trace du
exemple précédent) imprime les parties intéressantes du paquet reçu.

La raison d'être de cette division explicite est de permettre aux utilisateurs d'attacher de nouveaux types d'éviers à
sources de traçage existantes, sans nécessiter d'édition et de recompilation du cœur du
simulateur. Ainsi, dans l'exemple ci-dessus, un utilisateur pourrait définir un nouveau puits de traçage dans son
script et attachez-le à une source de traçage existante définie dans le noyau de simulation par
modifier uniquement le script utilisateur.

Dans ce didacticiel, nous allons parcourir certaines sources et puits prédéfinis et montrer comment
ils peuvent être personnalisés avec peu d'effort de la part de l'utilisateur. Voir le manuel du ns-3 ou les sections pratiques
pour plus d'informations sur la configuration de traçage avancé, y compris l'extension du traçage
espace de noms et création de nouvelles sources de traçage.

ASCII Traçant
ns-3 fournit une fonctionnalité d'assistance qui enveloppe le système de traçage de bas niveau pour vous aider
avec les détails impliqués dans la configuration de certaines traces de paquets facilement compréhensibles. Si vous
activez cette fonctionnalité, vous verrez la sortie dans un fichier ASCII --- d'où le nom. Pour
ceux qui connaissent ns-2 sortie, ce type de trace est analogue à la out.tr généré
par de nombreux scripts.

Allons-y et ajoutons une sortie de traçage ASCII à notre scratch/monpremier.cc
scénario. Juste avant l'appel à Simulateur :: Exécuter (), ajoutez les lignes de code suivantes :

AsciiTraceHelper ascii ;
pointToPoint.EnableAsciiAll (ascii.CreateFileStream ("myfirst.tr"));

Comme dans beaucoup d'autres ns-3 idiomes, ce code utilise un objet d'assistance pour aider à créer ASCII
traces. La deuxième ligne contient deux appels de méthode imbriqués. La méthode "dedans",
CréerFileStream() utilise un idiome d'objet sans nom pour créer un objet de flux de fichiers sur le
pile (sans nom d'objet) et transmettez-le à la méthode appelée. Nous allons entrer dans cela
plus à l'avenir, mais tout ce que vous devez savoir à ce stade est que vous créez un
objet représentant un fichier nommé "myfirst.tr" et le passant dans ns-3. vous dites
ns-3 pour traiter les problèmes de durée de vie de l'objet créé et également pour traiter les problèmes
causé par une limitation peu connue (intentionnelle) des objets C++ ofstream relatifs à la copie
constructeurs.

L'appel extérieur, à ActiverAsciiAll(), indique à l'assistant que vous souhaitez activer l'ASCII
traçage sur tous les appareils point à point de votre simulation ; et vous voulez le (fourni)
les récepteurs de trace pour écrire des informations sur le mouvement des paquets au format ASCII.

Pour ceux qui connaissent ns-2, les événements tracés sont équivalents aux points de trace populaires
qui enregistrent les événements "+", "-", "d" et "r".

Vous pouvez maintenant créer le script et l'exécuter à partir de la ligne de commande :

$ ./waf --run scratch/myfirst

Comme vous l'avez vu plusieurs fois auparavant, vous verrez des messages de Waf, puis
"'build' s'est terminé avec succès" avec un certain nombre de messages du programme en cours d'exécution.

Lors de son exécution, le programme aura créé un fichier nommé mapremière.tr. À cause de la manière
que Waf fonctionne, le fichier n'est pas créé dans le répertoire local, il est créé au
répertoire de niveau supérieur du référentiel par défaut. Si vous voulez contrôler où les traces
sont enregistrés, vous pouvez utiliser le --cwd option de Waf pour le spécifier. Nous ne l'avons pas fait, donc
nous devons changer dans le répertoire de niveau supérieur de notre référentiel et jeter un œil à l'ASCII
fichier de trace mapremière.tr dans votre éditeur préféré.

Analyse ASCII Traces
Il y a beaucoup d'informations sous une forme assez dense, mais la première chose à remarquer
est qu'il y a un certain nombre de lignes distinctes dans ce fichier. Il peut être difficile de voir
ceci clairement à moins que vous n'élargissiez considérablement votre fenêtre.

Chaque ligne du fichier correspond à un tracer event. Dans ce cas, nous traçons des événements sur
le transmettre file présent dans chaque périphérique réseau point à point de la simulation. le
file d'attente de transmission est une file d'attente à travers laquelle chaque paquet destiné à un canal point à point
doit passer. Notez que chaque ligne du fichier de trace commence par un seul caractère (a un
espace après). Ce caractère aura la signification suivante :

· +: Une opération de mise en file d'attente s'est produite sur la file d'attente du périphérique ;

· -: Une opération de retrait de la file d'attente s'est produite sur la file d'attente du périphérique ;

· d: Un paquet a été abandonné, généralement parce que la file d'attente était pleine ;

· r: Un paquet a été reçu par le périphérique réseau.

Examinons plus en détail la première ligne du fichier de trace. je vais le décomposer
en sections (indentées pour plus de clarté) avec un numéro de référence sur le côté gauche :

+
2
/NodeList/0/DeviceList/0/$ns3::PointToPointNetDevice/TxQueue/Enqueue
ns3::PppEn-tête (
Protocole point à point : IP (0x0021))
ns3::Ipv4En-tête (
tos 0x0 ttl 64 id 0 protocole 17 décalage 0 drapeaux [aucun]
longueur : 1052 10.1.1.1 > 10.1.1.2)
ns3::EntêteUdp (
longueur : 1032 49153 > 9)
Charge utile (taille=1024)

La première section de cet événement de trace étendu (numéro de référence 0) est l'opération. Nous
avoir un + caractère, cela correspond donc à un Enqueue opération sur la file d'attente de transmission.
La deuxième section (référence 1) est le temps de simulation exprimé en secondes. Vous pouvez
rappelons que nous avons demandé au UdpEchoClientApplicationUdpEchoClientApplication pour commencer à envoyer des paquets à deux secondes.
Ici, nous voyons la confirmation que cela se produit effectivement.

La section suivante de l'exemple de trace (référence 2) nous indique de quelle source de trace provient
cet événement (exprimé dans l'espace de noms de traçage). Vous pouvez penser à l'espace de noms de traçage
un peu comme vous le feriez pour un espace de noms de système de fichiers. La racine de l'espace de noms est le
Liste de nœuds. Cela correspond à un conteneur géré dans le ns-3 code de base qui contient tous
des nœuds créés dans un script. Tout comme un système de fichiers peut avoir des répertoires
sous la racine, nous pouvons avoir des numéros de nœud dans le Liste de nœuds. La chaîne /Liste de nœuds/0
fait donc référence au nœud zéro de la Liste de nœuds que nous considérons généralement comme "nœud
0". Dans chaque nœud, il y a une liste des appareils qui ont été installés. Cette liste apparaît
suivant dans l'espace de noms. Vous pouvez voir que cet événement de trace provient de Liste des appareils/0 lequel est
le zéroième périphérique installé dans le nœud.

La chaîne suivante, $ns3 ::PointToPointNetDevice vous indique quel type d'appareil se trouve dans
position zéro de la liste des appareils pour le nœud zéro. Rappelons que l'opération + trouvé à
la référence 00 signifiait qu'une opération de mise en file d'attente s'était produite sur la file d'attente de transmission du périphérique.
Cela se reflète dans les segments finaux du "chemin de trace" qui sont TxQueue/Mise en file d'attente.

Les sections restantes de la trace devraient être assez intuitives. Les références 3-4 indiquent
que le paquet est encapsulé dans le protocole point à point. Les références 5 à 7 montrent que
le paquet a un en-tête IP version quatre et provient de l'adresse IP 10.1.1.1 et
est destiné à 10.1.1.2. Les références 8-9 montrent que ce paquet a un en-tête UDP et,
enfin, la référence 10 montre que la charge utile est les 1024 octets attendus.

La ligne suivante du fichier de suivi montre que le même paquet est retiré de la file d'attente de transmission.
file d'attente sur le même nœud.

La troisième ligne du fichier de suivi indique le paquet reçu par le périphérique réseau sur le
nœud avec le serveur d'écho. J'ai reproduit cet événement ci-dessous.

r
2.25732
/NodeList/1/DeviceList/0/$ns3::PointToPointNetDevice/MacRx
ns3::Ipv4En-tête (
tos 0x0 ttl 64 id 0 protocole 17 décalage 0 drapeaux [aucun]
longueur : 1052 10.1.1.1 > 10.1.1.2)
ns3::EntêteUdp (
longueur : 1032 49153 > 9)
Charge utile (taille=1024)

Notez que l'opération de trace est maintenant r et le temps de simulation est passé à 2.25732
secondes. Si vous avez suivi attentivement les étapes du didacticiel, cela signifie que vous avez
a quitté le Débit de données des dispositifs nets et du canal Retard mis à leurs valeurs par défaut.
Cette heure devrait être familière comme vous l'avez déjà vue dans une section précédente.

L'entrée d'espace de noms de la source de trace (référence 02) a été modifiée pour indiquer que cet événement est
provenant du nœud 1 (/Liste de nœuds/1) et la source de trace de réception de paquet (/MacRx). Il
devrait être assez facile pour vous de suivre la progression du paquet à travers la topologie en
en regardant le reste des traces dans le fichier.

PPCE Traçant
Notre ns-3 les assistants de périphérique peuvent également être utilisés pour créer des fichiers de trace dans le .pcap format. le
acronyme pcap (généralement écrit en minuscules) signifie capture de paquets, et est en fait un
API qui inclut la définition d'un .pcap format de fichier. Le programme le plus populaire qui
peut lire et afficher ce format est Wireshark (anciennement appelé Ethereal). Cependant, il y a
De nombreux analyseurs de trace de trafic utilisent ce format de paquet. Nous encourageons les utilisateurs à
exploiter les nombreux outils disponibles pour analyser les traces pcap. Dans ce tutoriel, nous
concentrez-vous sur la visualisation des traces pcap avec tcpdump.

Le code utilisé pour activer le traçage pcap est un one-liner.

pointToPoint.EnablePcapAll ("monpremier");

Allez-y et insérez cette ligne de code après le code de traçage ASCII que nous venons d'ajouter à
scratch/monpremier.cc. Notez que nous avons seulement passé la chaîne "myfirst", et non
"myfirst.pcap" ou quelque chose de similaire. C'est parce que le paramètre est un préfixe, pas un
nom complet du fichier. L'assistant créera en fait un fichier de trace pour chaque point à point
dispositif dans la simulation. Les noms de fichiers seront construits en utilisant le préfixe, le numéro de nœud,
le numéro d'appareil et un suffixe ".pcap".

Dans notre exemple de script, nous verrons éventuellement des fichiers nommés "myfirst-0-0.pcap" et
"myfirst-1-0.pcap" qui sont les traces pcap pour node 0-device 0 et node 1-device 0,
respectivement.

Une fois que vous avez ajouté la ligne de code pour activer le traçage pcap, vous pouvez exécuter le script dans le
Manière habituelle:

$ ./waf --run scratch/myfirst

Si vous regardez le répertoire de niveau supérieur de votre distribution, vous devriez maintenant voir trois log
fichiers: mapremière.tr est le fichier de trace ASCII que nous avons examiné précédemment. monpremier-0-0.pcap
et votre monpremier-1-0.pcap sont les nouveaux fichiers pcap que nous venons de générer.

en cours sortie avec tcpdump
La chose la plus simple à faire à ce stade sera d'utiliser tcpdump de regarder le pcap fichiers.

$ tcpdump -nn -tt -r monpremier-0-0.pcap
lecture du fichier myfirst-0-0.pcap, PPP de type lien (PPP)
2.000000 IP 10.1.1.1.49153 > 10.1.1.2.9 : UDP, longueur 1024
2.514648 IP 10.1.1.2.9 > 10.1.1.1.49153 : UDP, longueur 1024

tcpdump -nn -tt -r monpremier-1-0.pcap
lecture du fichier myfirst-1-0.pcap, PPP de type lien (PPP)
2.257324 IP 10.1.1.1.49153 > 10.1.1.2.9 : UDP, longueur 1024
2.257324 IP 10.1.1.2.9 > 10.1.1.1.49153 : UDP, longueur 1024

Vous pouvez voir dans la décharge de monpremier-0-0.pcap (le périphérique client) que le paquet d'écho est
envoyé à 2 secondes dans la simulation. Si vous regardez le deuxième vidage (monpremier-1-0.pcap)
vous pouvez voir ce paquet reçu à 2.257324 secondes. Vous voyez le paquet être
renvoyé à 2.257324 secondes dans le deuxième vidage, et enfin, vous voyez le paquet être
reçu au client dans le premier vidage à 2.514648 secondes.

en cours sortie avec Wireshark
Si vous n'êtes pas familier avec Wireshark, il existe un site Web à partir duquel vous pouvez
télécharger des programmes et de la documentation : http://www.wireshark.org/.

Wireshark est une interface utilisateur graphique qui peut être utilisée pour afficher ces traces
des dossiers. Si Wireshark est disponible, vous pouvez ouvrir chacun des fichiers de suivi et afficher
le contenu comme si vous aviez capturé les paquets à l'aide d'un paquet renifleur.

IMMEUBLE TOPOLOGIES


Développement a Autobus Réseau topologie
Dans cette section, nous allons approfondir notre maîtrise de ns-3 périphériques réseau et canaux à
couvrir un exemple de réseau de bus. ns-3 fournit un périphérique réseau et un canal que nous appelons CSMA
(Accès multiple avec détection de porteuse).

Notre ns-3 Le dispositif CSMA modélise un réseau simple dans l'esprit d'Ethernet. Un vrai Ethernet
utilise le schéma CSMA/CD (Carrier Sense Multiple Access with Collision Detection) avec
backoff augmentant de manière exponentielle pour lutter pour le support de transmission partagé. La ns-3
Les modèles d'appareils et de canaux CSMA n'en sont qu'un sous-ensemble.

Tout comme nous avons vu des objets d'assistance de topologie point à point lors de la construction
topologies point à point, nous verrons des assistants de topologie CSMA équivalents dans cette section.
L'apparence et le fonctionnement de ces assistants devraient vous sembler assez familiers.

Nous fournissons un exemple de script dans notre répertoire examples/tutorial}. Ce script s'appuie sur
le premier.cc script et ajoute un réseau CSMA à la simulation point à point que nous avons déjà
considéré. Allez-y et ouvrez exemples/tutoriel/second.cc dans votre éditeur préféré. Tu
en aura déjà assez vu ns-3 code pour comprendre la plupart de ce qui se passe dans ce
exemple, mais nous allons passer en revue l'intégralité du script et examiner une partie de la sortie.

Tout comme dans le premier.cc exemple (et dans tous les exemples ns-3) le fichier commence par un emacs
ligne de mode et certains passe-partout GPL.

Le code proprement dit commence par charger les fichiers d'inclusion du module comme cela a été fait dans le premier.cc
Exemple.

#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/csma-module.h"
#include "ns3/internet-module.h"
#include "ns3/point-à-point-module.h"
#include "ns3/applications-module.h"
#include "ns3/ipv4-global-routing-helper.h"

Une chose qui peut être étonnamment utile est un petit morceau d'art ASCII qui montre un dessin animé
de la topologie de réseau construite dans l'exemple. Vous trouverez un "dessin" similaire dans
la plupart de nos exemples.

Dans ce cas, vous pouvez voir que nous allons étendre notre exemple point à point (le lien
entre les nœuds n0 et n1 ci-dessous) en accrochant un réseau de bus du côté droit. Remarquer
qu'il s'agit de la topologie de réseau par défaut puisque vous pouvez en fait faire varier le nombre de nœuds
créé sur le LAN. Si vous définissez nCsma sur un, il y aura un total de deux nœuds sur le
LAN (canal CSMA) --- un nœud requis et un nœud "supplémentaire". Par défaut, il y a trois
nœuds "supplémentaires" comme indiqué ci-dessous :

// Topologie de réseau par défaut
//
// 10.1.1.0
// n0 -------------- n1 n2 n3 n4
// point à point | | | |
// =================
// Réseau local 10.1.2.0

Alors l'espace de noms ns-3 est d'utiliser et un composant de journalisation est défini. Tout cela est tout aussi
c'était en premier.cc, il n'y a donc rien de nouveau pour le moment.

en utilisant l'espace de noms ns3 ;

NS_LOG_COMPONENT_DEFINE ("SecondScriptExample");

Le programme principal commence par une tournure légèrement différente. Nous utilisons un drapeau verbeux pour
déterminer si oui ou non la UdpEchoClientApplicationUdpEchoClientApplication et votre UdpEchoServerApplicationUdpEchoServerApplication enregistrement
composants sont activés. Cet indicateur est défini par défaut sur true (les composants de journalisation sont activés)
mais nous permet de désactiver la journalisation lors des tests de régression de cet exemple.

Vous verrez un code familier qui vous permettra de modifier le nombre d'appareils sur le
Réseau CSMA via un argument de ligne de commande. Nous avons fait quelque chose de similaire lorsque nous avons autorisé le
nombre de paquets envoyés à modifier dans la section sur les arguments de la ligne de commande. Le dernier
s'assure que vous avez au moins un nœud "supplémentaire".

Le code se compose de variantes de l'API précédemment couverte, vous devez donc être entièrement
à l'aise avec le code suivant à ce stade du didacticiel.

bool verbeux = vrai ;
uint32_t nCsma = 3 ;

cmd de ligne de commande ;
cmd.AddValue ("nCsma", "Nombre de nœuds/périphériques CSMA \"supplémentaires\"", nCsma) ;
cmd.AddValue ("verbeux", "Dites aux applications d'écho de se connecter si vrai", verbeux);

cmd.Parse (argc, argv);

si (verbeux)
{
LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);
LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO);
}

nCsma = nCsma == 0 ? 1 : nCsma ;

L'étape suivante consiste à créer deux nœuds que nous connecterons via le lien point à point.
Notre Conteneur de nœud est utilisé pour le faire comme cela a été fait dans premier.cc.

NodeContainer p2pNodes ;
p2pNodes.Create (2);

Ensuite, nous déclarons un autre Conteneur de nœud pour contenir les nœuds qui feront partie du bus
(CSMA). Tout d'abord, nous instancions simplement l'objet conteneur lui-même.

NodeContainer csmaNodes ;
csmaNodes.Add (p2pNodes.Get (1));
csmaNodes.Create (nCsma);

La prochaine ligne de code Obtient le premier nœud (comme pour avoir un index de un) à partir du
conteneur de nœuds point à point et l'ajoute au conteneur de nœuds qui obtiendra CSMA
dispositifs. Le nœud en question va se retrouver avec un appareil point à point et votre un CSMA
dispositif. Nous créons ensuite un certain nombre de nœuds "supplémentaires" qui composent le reste du CSMA
réseau. Puisque nous avons déjà un nœud dans le réseau CSMA -- celui qui aura
à la fois un périphérique réseau point à point et CSMA, le nombre de nœuds "supplémentaires" signifie le nombre
nœuds que vous désirez dans la section CSMA moins un.

Le prochain morceau de code devrait être assez familier maintenant. Nous instancions un PointÀPointHelper
et définissez la valeur par défaut associée Attributs de sorte que nous créons cinq mégabits par seconde
émetteur sur les appareils créés à l'aide de l'assistant et un délai de deux millisecondes sur les canaux
créé par l'assistant.

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

NetDeviceContainer p2pDevices ;
p2pDevices = pointToPoint.Install (p2pNodes);

Nous instancions alors un NetDeviceContainer pour garder une trace des périphériques réseau point à point
et nous Installer périphériques sur les nœuds point à point.

Nous avons mentionné ci-dessus que vous alliez voir un assistant pour les appareils et les canaux CSMA, et
les lignes suivantes les présentent. La CsmaHelperComment fonctionne comme un PointÀPointHelper, mais
il crée et connecte des appareils et des canaux CSMA. Dans le cas d'un appareil CSMA et
paire de canaux, notez que le débit de données est spécifié par un indirect Attribut au lieu d'une
dispositif Attribut. En effet, un vrai réseau CSMA ne permet pas de mélanger, par
exemple, les appareils 10Base-T et 100Base-T sur un canal donné. Nous fixons d'abord le débit de données à
100 mégabits par seconde, puis réglez le délai de vitesse de la lumière du canal sur 6560
nanosecondes (choisi arbitrairement comme 1 nanoseconde par pied sur un segment de 100 mètres).
Notez que vous pouvez définir un Attribut en utilisant son type de données natif.

CsmaHelper csma ;
csma.SetChannelAttribute ("DataRate", StringValue ("100Mbps"));
csma.SetChannelAttribute ("Retard", TimeValue (NanoSeconds (6560)));

NetDeviceContainer csmaDevices ;
csmaDevices = csma.Install (csmaNodes);

Tout comme nous avons créé un NetDeviceContainer pour contenir les appareils créés par le
PointÀPointHelper nous créons un NetDeviceContainer pour contenir les appareils créés par nos
CsmaHelperComment. Nous appelons le Installer méthode de CsmaHelperComment pour installer les appareils dans
nœuds du csmaNodes Conteneur de nœud.

Nous avons maintenant créé nos nœuds, appareils et canaux, mais nous n'avons pas de piles de protocoles
cadeau. Tout comme dans le premier.cc script, nous utiliserons le InternetStackHelper à installer
ces piles.

Pile InternetStackHelper ;
stack.Install (p2pNodes.Get (0));
stack.Install (csmaNodes);

Rappelons que nous avons pris l'un des nœuds du p2pNoeuds récipient et l'a ajouté au
csmaNodes récipient. Ainsi, nous n'avons qu'à installer les piles sur le reste p2pNoeuds
nœud, et tous les nœuds du csmaNodes conteneur pour couvrir tous les nœuds du
simulation.

Tout comme dans le premier.cc exemple de script, nous allons utiliser le Assistant d'adresse IPv4 à
attribuer des adresses IP à nos interfaces d'appareils. Nous utilisons d'abord le réseau 10.1.1.0 pour créer
les deux adresses nécessaires pour nos deux appareils point à point.

Adresse Ipv4AddressHelper ;
adresse.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer p2pInterfaces ;
p2pInterfaces = adresse.Assign (p2pDevices);

Rappelez-vous que nous sauvegardons les interfaces créées dans un conteneur pour faciliter leur extraction
informations d'adressage ultérieures à utiliser lors de la configuration des applications.

Nous devons maintenant attribuer des adresses IP à nos interfaces d'appareils CSMA. L'opération fonctionne
tout comme il l'a fait pour le cas point à point, sauf que nous effectuons maintenant l'opération sur
un conteneur qui a un nombre variable d'appareils CSMA --- rappelez-vous que nous avons fait le nombre de
Périphériques CSMA modifiables par argument de ligne de commande. Les appareils CSMA seront associés
avec les adresses IP du numéro de réseau 10.1.2.0 dans ce cas, comme indiqué ci-dessous.

adresse.SetBase ("10.1.2.0", "255.255.255.0");
Ipv4InterfaceContainer csmaInterfaces ;
csmaInterfaces = adresse.Assign (csmaDevices);

Nous avons maintenant une topologie construite, mais nous avons besoin d'applications. Cette section va être
fondamentalement similaire à la section des applications de premier.cc mais nous allons
instancier le serveur sur l'un des nœuds disposant d'un périphérique CSMA et le client sur le
nœud n'ayant qu'un dispositif point à point.

Tout d'abord, nous avons configuré le serveur d'écho. Nous créons un UdpEchoServerHelper et fournir un requis
Attribut valeur au constructeur qui est le numéro de port du serveur. Rappelons que ce port
peut être modifié ultérieurement à l'aide de Définir l'attribut méthode si vous le souhaitez, mais nous exigeons qu'elle soit
fourni au constructeur.

UdpEchoServerHelper echoServer (9);

ApplicationContainer serverApps = echoServer.Install (csmaNodes.Get (nCsma));
serverApps.Start (secondes (1.0));
serverApps.Stop (secondes (10.0));

Rappelons que le csmaNodes Conteneur de nœud contient l'un des nœuds créés pour le
réseau point à point et nCsma nœuds "supplémentaires". Ce que nous voulons aborder, c'est le dernier des
nœuds "supplémentaires". La zéroième entrée du csmaNodes conteneur sera le point à point
nœud. La façon la plus simple d'y penser est donc que si nous créons un nœud CSMA "supplémentaire", alors il
sera à l'indice un des csmaNodes récipient. Par induction, si on crée nCsma "supplémentaire"
nœuds le dernier sera à l'index nCsma. Vous voyez cela exposé dans le Obtenez de la première
ligne de code.

L'application client est configurée exactement comme nous l'avons fait dans le premier.cc exemple de scénario. Encore,
nous fournissons requis Attributs à la UdpEchoClientHelperUdpEchoClientHelper dans le constructeur (dans ce cas
l'adresse et le port distants). Nous disons au client d'envoyer des paquets au serveur que nous venons de
installé sur le dernier des nœuds CSMA "supplémentaires". Nous installons le client à l'extrême gauche
nœud point à point vu dans l'illustration de la topologie.

UdpEchoClientHelper echoClient (csmaInterfaces.GetAddress (nCsma), 9);
echoClient.SetAttribute ("MaxPackets", UintegerValue (1));
echoClient.SetAttribute ("Interval", TimeValue (Secondes (1.0)));
echoClient.SetAttribute ("PacketSize", UintegerValue (1024));

ApplicationContainer clientApps = echoClient.Install (p2pNodes.Get (0));
clientApps.Start (secondes (2.0));
clientApps.Stop (Secondes (10.0));

Puisque nous avons en fait construit un interréseau ici, nous avons besoin d'une certaine forme d'interréseau
routage ns-3 fournit ce que nous appelons le routage global pour vous aider. Le routage global prend
avantage du fait que tout l'interréseau est accessible dans la simulation et
parcourt tous les nœuds créés pour la simulation --- il fait le travail acharné de
configurer le routage pour vous sans avoir à configurer les routeurs.

Fondamentalement, ce qui se passe, c'est que chaque nœud se comporte comme s'il s'agissait d'un routeur OSPF qui
communique instantanément et comme par magie avec tous les autres routeurs en coulisses. Chaque nœud
génère des annonces de lien et les communique directement à un gestionnaire de route global
qui utilise ces informations globales pour construire les tables de routage pour chaque nœud. Paramètre
cette forme de routage est un one-liner :

Ipv4GlobalRoutingHelper ::PopulateRoutingTables ();

Ensuite, nous activons le traçage pcap. La première ligne de code pour activer le traçage pcap dans le
l'assistant point à point devrait vous être familier maintenant. La deuxième ligne active pcap
traçage dans l'assistant CSMA et il y a un paramètre supplémentaire que vous n'avez pas encore rencontré.

pointToPoint.EnablePcapAll ("seconde");
csma.EnablePcap ("deuxième", csmaDevices.Get (1), vrai);

Le réseau CSMA est un réseau multipoint à point. Cela signifie qu'il peut (et existe dans
ce cas) plusieurs terminaux sur un support partagé. Chacun de ces points de terminaison a un réseau
appareil qui lui est associé. Il existe deux alternatives de base à la collecte de traces
informations d'un tel réseau. Une façon consiste à créer un fichier de trace pour chaque périphérique réseau
et stocker uniquement les paquets qui sont émis ou consommés par ce périphérique réseau. Autrement
est de choisir l'un des appareils et de le placer en mode promiscuité. Ce seul appareil alors
"sniffe" le réseau pour tous les paquets et les stocke dans un seul fichier pcap. C'est ainsi
tcpdump, par exemple, fonctionne. Ce paramètre final indique à l'assistant CSMA s'il doit ou non
s'arrange pour capturer les paquets en mode promiscuité.

Dans cet exemple, nous allons sélectionner un des appareils du réseau CSMA et lui demander
pour effectuer un sniff de promiscuité du réseau, imitant ainsi ce que tcpdump ferait.
Si vous étiez sur une machine Linux, vous pourriez faire quelque chose comme tcpdump -i eth0 pour obtenir le
trace. Dans ce cas, nous spécifions l'appareil en utilisant csmaDevices.Get(1), qui sélectionne le
premier appareil dans le conteneur. Définir le paramètre final sur true active la promiscuité
capture.

La dernière section de code s'exécute et nettoie la simulation, tout comme le premier.cc
Exemple.

Simulateur::Exécuter ();
Simulateur :: Détruire ();
0 revenir;
}

Pour exécuter cet exemple, copiez le seconde.cc exemple de script dans le répertoire de travail
et utilisez waf pour construire comme vous l'avez fait avec le premier.cc Exemple. Si vous êtes dans le
répertoire de niveau supérieur du référentiel que vous venez de taper,

$ cp exemples/tutorial/second.cc scratch/mysecond.cc
$ ./waf

Attention : Nous utilisons le fichier seconde.cc comme l'un de nos tests de régression pour vérifier que cela fonctionne
exactement comme nous pensons qu'il devrait le faire afin de rendre votre expérience de tutoriel positive.
Cela signifie qu'un exécutable nommé seconde existe déjà dans le projet. Pour éviter tout
confusion sur ce que vous exécutez, veuillez renommer maseconde.cc suggéré
au dessus.

Si vous suivez le tutoriel religieusement (vous l'êtes, n'est-ce pas), vous aurez toujours
la variable NS_LOG définie, alors allez-y, effacez cette variable et exécutez le programme.

$ exporter NS_LOG=
$ ./waf --run scratch/maseconde

Puisque nous avons configuré les applications d'écho UDP pour qu'elles se connectent comme nous l'avons fait dans premier.cc, vous devrez
voir une sortie similaire lorsque vous exécutez le script.

Waf : Entrer dans le répertoire `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf : quitter le répertoire `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' terminé avec succès (0.415s)
Envoyé 1024 octets à 10.1.2.4
Reçu 1024 octets de 10.1.1.1
Reçu 1024 octets de 10.1.2.4

Rappelons que le premier message, "Envoyés 1024 octets à 10.1.2.4," est le client d'écho UDP
envoyer un paquet au serveur. Dans ce cas, le serveur est sur un autre réseau
(10.1.2.0). Le deuxième message, "Reçu 1024 octets de 10.1.1.1," provient de l'écho UDP
serveur, généré lorsqu'il reçoit le paquet d'écho. Le message final, "Reçu 1024
octets de 10.1.2.4," provient du client echo, indiquant qu'il a reçu son echo
retour du serveur.

Si vous allez maintenant chercher dans le répertoire de niveau supérieur, vous trouverez trois fichiers de trace :

second-0-0.pcap second-1-0.pcap second-2-0.pcap

Prenons un moment pour regarder la dénomination de ces fichiers. Ils ont tous la même forme,
- - .pcap. Par exemple, le premier fichier de la liste est
seconde-0-0.pcap qui est la trace pcap du nœud zéro, périphérique zéro. C'est le
périphérique réseau point à point sur le nœud zéro. Le fichier seconde-1-0.pcap est la trace pcap pour
périphérique zéro sur le nœud un, également un périphérique réseau point à point ; et le dossier seconde-2-0.pcap is
la trace pcap pour le périphérique zéro sur le nœud deux.

Si vous vous référez à l'illustration de la topologie au début de la section, vous verrez
ce nœud zéro est le nœud le plus à gauche de la liaison point à point et le nœud un est le nœud
qui possède à la fois un périphérique point à point et un périphérique CSMA. Vous verrez que le nœud deux est
le premier nœud "supplémentaire" sur le réseau CSMA et son périphérique zéro a été sélectionné comme périphérique
pour capturer la trace en mode promiscuité.

Suivons maintenant le paquet d'écho à travers l'interréseau. Tout d'abord, effectuez un tcpdump du
fichier de trace pour le nœud point à point le plus à gauche --- nœud zéro.

$ tcpdump -nn -tt -r seconde-0-0.pcap

Vous devriez voir le contenu du fichier pcap affiché :

lecture du fichier second-0-0.pcap, PPP de type lien (PPP)
2.000000 IP 10.1.1.1.49153 > 10.1.2.4.9 : UDP, longueur 1024
2.017607 IP 10.1.2.4.9 > 10.1.1.1.49153 : UDP, longueur 1024

La première ligne du dump indique que le type de lien est PPP (point à point) que nous
attendre. Vous voyez alors le paquet d'écho quitter le noeud zéro via l'appareil associé à l'IP
l'adresse 10.1.1.1 dirigée vers l'adresse IP 10.1.2.4 (le nœud CSMA le plus à droite). Ce paquet
se déplacera sur la liaison point à point et sera reçu par le dispositif réseau point à point sur
nœud un. Nous allons jeter un coup d'oeil:

$ tcpdump -nn -tt -r seconde-1-0.pcap

Vous devriez maintenant voir la sortie de trace pcap de l'autre côté de la liaison point à point :

lecture du fichier second-1-0.pcap, PPP de type lien (PPP)
2.003686 IP 10.1.1.1.49153 > 10.1.2.4.9 : UDP, longueur 1024
2.013921 IP 10.1.2.4.9 > 10.1.1.1.49153 : UDP, longueur 1024

Ici, nous voyons que le type de lien est également PPP, comme on pouvait s'y attendre. Vous voyez le paquet de l'IP
adresse 10.1.1.1 (qui a été envoyée à 2.000000 secondes) dirigée vers l'adresse IP 10.1.2.4
apparaissent sur cette interface. Maintenant, en interne à ce nœud, le paquet sera transmis à
l'interface CSMA et nous devrions la voir apparaître sur cet appareil en direction de son ultime
destination.

N'oubliez pas que nous avons sélectionné le nœud 2 comme nœud renifleur de promiscuité pour le réseau CSMA.
regardons ensuite second-2-0.pcap et voyons s'il est là.

$ tcpdump -nn -tt -r seconde-2-0.pcap

Vous devriez maintenant voir le vidage promiscuité du nœud deux, périphérique zéro :

lecture à partir du fichier second-2-0.pcap, type de lien EN10MB (Ethernet)
2.007698 ARP, Request who-has 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1, longueur 50
2.007710 ARP, la réponse 10.1.2.4 est à 00:00:00:00:00:06, longueur 50
2.007803 IP 10.1.1.1.49153 > 10.1.2.4.9 : UDP, longueur 1024
2.013815 ARP, Request who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4, longueur 50
2.013828 ARP, la réponse 10.1.2.1 est à 00:00:00:00:00:03, longueur 50
2.013921 IP 10.1.2.4.9 > 10.1.1.1.49153 : UDP, longueur 1024

Comme vous pouvez le voir, le type de lien est désormais "Ethernet". Quelque chose de nouveau est cependant apparu. La
besoins du réseau de bus ARP, le protocole de résolution d'adresse. Le nœud un sait qu'il doit envoyer
le paquet à l'adresse IP 10.1.2.4, mais il ne connaît pas l'adresse MAC du
nœud correspondant. Il diffuse sur le réseau CSMA (ff:ff:ff:ff:ff:ff) demandant le
dispositif qui a l'adresse IP 10.1.2.4. Dans ce cas, le nœud le plus à droite répond en disant qu'il
est à l'adresse MAC 00:00:00:00:00:06. Notez que le nœud deux n'est pas directement impliqué dans ce
Exchange, mais renifle le réseau et signale tout le trafic qu'il voit.

Cet échange se voit dans les lignes suivantes,

2.007698 ARP, Request who-has 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1, longueur 50
2.007710 ARP, la réponse 10.1.2.4 est à 00:00:00:00:00:06, longueur 50

Ensuite, le nœud un, le périphérique un continue et envoie le paquet d'écho au serveur d'écho UDP à
Adresse IP 10.1.2.4.

2.007803 IP 10.1.1.1.49153 > 10.1.2.4.9 : UDP, longueur 1024

Le serveur reçoit la requête d'écho et retourne le paquet en essayant de le renvoyer à
la source. Le serveur sait que cette adresse se trouve sur un autre réseau auquel il accède via
Adresse IP 10.1.2.1. C'est parce que nous avons initialisé le routage global et qu'il a tout compris
de cela pour nous. Mais, le nœud du serveur d'écho ne connaît pas l'adresse MAC du premier
Nœud CSMA, il doit donc ARP pour cela, tout comme le premier nœud CSMA devait le faire.

2.013815 ARP, Request who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4, longueur 50
2.013828 ARP, la réponse 10.1.2.1 est à 00:00:00:00:00:03, longueur 50

Le serveur renvoie ensuite l'écho au nœud de transfert.

2.013921 IP 10.1.2.4.9 > 10.1.1.1.49153 : UDP, longueur 1024

En regardant le nœud le plus à droite de la liaison point à point,

$ tcpdump -nn -tt -r seconde-1-0.pcap

Vous pouvez maintenant voir le paquet en écho revenir sur la liaison point à point en tant que dernier
ligne du vidage de trace.

lecture du fichier second-1-0.pcap, PPP de type lien (PPP)
2.003686 IP 10.1.1.1.49153 > 10.1.2.4.9 : UDP, longueur 1024
2.013921 IP 10.1.2.4.9 > 10.1.1.1.49153 : UDP, longueur 1024

Enfin, vous pouvez revenir sur le nœud à l'origine de l'écho

$ tcpdump -nn -tt -r seconde-0-0.pcap

et voir que le paquet en écho revient à la source à 2.007602 secondes,

lecture du fichier second-0-0.pcap, PPP de type lien (PPP)
2.000000 IP 10.1.1.1.49153 > 10.1.2.4.9 : UDP, longueur 1024
2.017607 IP 10.1.2.4.9 > 10.1.1.1.49153 : UDP, longueur 1024

Enfin, rappelons que nous avons ajouté la possibilité de contrôler le nombre d'appareils CSMA dans le
simulation par argument de ligne de commande. Vous pouvez modifier cet argument de la même manière que lorsque
nous avons envisagé de modifier le nombre de paquets renvoyés en écho dans le premier.cc Exemple. Essayez de courir
le programme avec le nombre d'appareils "supplémentaires" fixé à quatre :

$ ./waf --run "scratch/maseconde --nCsma=4"

Vous devriez maintenant voir,

Waf : Entrer dans le répertoire `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf : quitter le répertoire `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' terminé avec succès (0.405s)
Au moment 2s, le client a envoyé 1024 octets au port 10.1.2.5 9
Au moment 2.0118s, le serveur a reçu 1024 octets du port 10.1.1.1 49153
Au moment 2.0118s, le serveur a envoyé 1024 octets au port 10.1.1.1 49153
Au moment 2.02461s, le client a reçu 1024 octets du port 10.1.2.5 9

Notez que le serveur d'écho a maintenant été déplacé vers le dernier des nœuds CSMA, qui est
10.1.2.5 au lieu du cas par défaut, 10.1.2.4.

Il est possible que vous ne soyez pas satisfait d'un fichier de trace généré par un spectateur dans
le réseau CSMA. Vous voudrez peut-être vraiment obtenir une trace à partir d'un seul appareil et vous ne pouvez pas
être intéressé par tout autre trafic sur le réseau. Vous pouvez le faire assez facilement.

Jetons un coup d'oeil à scratch/maseconde.cc et ajouter ce code nous permettant d'être plus
spécifique. ns-3 les aides fournissent des méthodes qui prennent un numéro de nœud et un numéro de périphérique comme
paramètres. Allez-y et remplacez le ActiverPcap appels avec les appels ci-dessous.

pointToPoint.EnablePcap ("deuxième", p2pNodes.Get (0)->GetId (), 0);
csma.EnablePcap ("deuxième", csmaNodes.Get (nCsma)->GetId (), 0, faux);
csma.EnablePcap ("deuxième", csmaNodes.Get (nCsma-1)->GetId (), 0, faux);

Nous savons que nous voulons créer un fichier pcap avec le nom de base "second" et nous savons aussi
que l'appareil d'intérêt dans les deux cas va être zéro, donc ces paramètres ne sont pas
vraiment intéressant.

Pour obtenir le numéro de nœud, vous avez deux choix : d'abord, les nœuds sont numérotés dans un
mode croissante monotone à partir de zéro dans l'ordre dans lequel vous avez créé
leur. Une façon d'obtenir un numéro de nœud est de déterminer ce numéro "manuellement" en
compte tenu de l'ordre de création des nœuds. Si vous regardez la topologie du réseau
illustration au début du fichier, nous l'avons fait pour vous et vous pouvez voir que le
le dernier nœud CSMA sera le numéro de nœud nCsma + 1. Cette approche peut devenir ennuyeuse
difficile dans les grandes simulations.

Une autre façon, que nous utilisons ici, est de réaliser que le NodeContainersNodeContainers contiennent
pointeurs vers ns-3 Nœud Objets. La Nœud L'objet a une méthode appelée Obtenir l'ID Qui va
renvoie l'ID de ce nœud, qui est le numéro de nœud que nous recherchons. Allons jeter un oeil au
Doxygen pour le Nœud et localisez cette méthode, qui se trouve plus bas dans le ns-3 code de base
que nous avons vu jusqu'à présent ; mais parfois il faut chercher assidûment des choses utiles.

Accédez à la documentation Doxygen de votre version (rappelez-vous que vous pouvez la trouver sur le
site internet du projet). Vous pouvez accéder au Nœud documentation en parcourant le
onglet "Classes" et faites défiler la "Liste des classes" jusqu'à ce que vous trouviez ns3::Noeud. Sélectionner
ns3::Noeud et vous serez redirigé vers la documentation pour le Nœud classer. Si vous maintenant
faites défiler jusqu'à Obtenir l'ID méthode et sélectionnez-la, vous serez redirigé vers le détail
documentation de la méthode. En utilisant le Obtenir l'ID le procédé peut permettre de déterminer les numéros de nœud
beaucoup plus facile dans les topologies complexes.

Effacons les anciens fichiers de trace du répertoire de niveau supérieur pour éviter toute confusion à propos de
que se passe-t-il,

$rm *.pcap
$rm *.tr

Si vous créez le nouveau script et exécutez le paramètre de simulation nCsma à 100,

$ ./waf --run "scratch/maseconde --nCsma=100"

vous verrez la sortie suivante :

Waf : Entrer dans le répertoire `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf : quitter le répertoire `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' terminé avec succès (0.407s)
Au moment 2s, le client a envoyé 1024 octets au port 10.1.2.101 9
Au moment 2.0068s, le serveur a reçu 1024 octets du port 10.1.1.1 49153
Au moment 2.0068s, le serveur a envoyé 1024 octets au port 10.1.1.1 49153
Au moment 2.01761s, le client a reçu 1024 octets du port 10.1.2.101 9

Notez que le serveur d'écho est maintenant situé à 10.1.2.101 ce qui correspond à avoir 100
nœuds CSMA "supplémentaires" avec le serveur d'écho sur le dernier. Si vous répertoriez les fichiers pcap dans
le répertoire de niveau supérieur que vous verrez,

second-0-0.pcap second-100-0.pcap second-101-0.pcap

Le fichier de trace seconde-0-0.pcap est le périphérique point à point "le plus à gauche" qui est l'écho
source de paquets. Le fichier seconde-101-0.pcap correspond à l'appareil CSMA le plus à droite qui
est l'endroit où réside le serveur d'écho. Vous avez peut-être remarqué que le paramètre final sur le
l'appel pour activer le traçage pcap sur le nœud du serveur d'écho était faux. Cela signifie que la trace
recueillies sur ce nœud était en mode non promiscuité.

Pour illustrer la différence entre les traces promiscuous et non promiscuous, nous avons également
a demandé une trace non promiscuité pour l'avant-dernier nœud. Allez-y et jetez un oeil à
le tcpdump pour seconde-100-0.pcap.

$ tcpdump -nn -tt -r seconde-100-0.pcap

Vous pouvez maintenant voir que le nœud 100 est vraiment un spectateur dans l'échange d'écho. Le seul
les paquets qu'il reçoit sont les requêtes ARP qui sont diffusées à l'ensemble du CSMA
réseau.

lecture à partir du fichier second-100-0.pcap, type de lien EN10MB (Ethernet)
2.006698 ARP, Request who-has 10.1.2.101 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1, longueur 50
2.013815 ARP, Request who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.101, longueur 50

Maintenant, jetez un oeil à la tcpdump pour seconde-101-0.pcap.

$ tcpdump -nn -tt -r seconde-101-0.pcap

Vous pouvez maintenant voir que le nœud 101 est vraiment le participant à l'échange d'écho.

lecture à partir du fichier second-101-0.pcap, type de lien EN10MB (Ethernet)
2.006698 ARP, Request who-has 10.1.2.101 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1, longueur 50
2.006698 ARP, la réponse 10.1.2.101 est à 00:00:00:00:00:67, longueur 50
2.006803 IP 10.1.1.1.49153 > 10.1.2.101.9 : UDP, longueur 1024
2.013803 ARP, Request who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.101, longueur 50
2.013828 ARP, la réponse 10.1.2.1 est à 00:00:00:00:00:03, longueur 50
2.013828 IP 10.1.2.101.9 > 10.1.1.1.49153 : UDP, longueur 1024

Des modèles, Attributs et votre Réalité
C'est un endroit pratique pour faire une petite excursion et faire un point important. Cela pourrait
ou peut ne pas être évident pour vous, mais chaque fois que l'on utilise une simulation, il est important de
comprendre exactement ce qui est modélisé et ce qui ne l'est pas. Il est tentant, par exemple, de
pensez aux appareils et aux canaux CSMA utilisés dans la section précédente comme s'ils étaient réels
périphériques Ethernet ; et s'attendre à ce qu'un résultat de simulation reflète directement ce qui se passera
dans un véritable Ethernet. Ce n'est pas le cas.

Un modèle est, par définition, une abstraction de la réalité. C'est finalement la responsabilité
de l'auteur du script de simulation pour déterminer ce que l'on appelle la "gamme de précision" et le "domaine
d'applicabilité" de la simulation dans son ensemble, et donc de ses éléments constitutifs.

Dans certains cas, comme CSMA, il peut être assez facile de déterminer ce qui est pas modélisé. Par
lire la description du modèle (csma.h) vous pouvez constater qu'il n'y a pas de détection de collision
dans le modèle CSMA et décidez dans quelle mesure son utilisation sera applicable dans votre simulation ou ce
mises en garde que vous voudrez peut-être inclure dans vos résultats. Dans d'autres cas, il peut être assez facile
pour configurer des comportements qui pourraient ne pas correspondre à toute réalité que vous pouvez sortir et acheter. Ce
s'avérera utile de passer du temps à enquêter sur quelques cas de ce genre, et comment
vous pouvez facilement sortir des limites de la réalité dans vos simulations.

Comme vous l'avez vu, ns-3 fournit Attributs qu'un utilisateur peut facilement configurer pour changer de modèle
comportement. Considérez deux des Attributs des Périphérique CsmaNet: Mtu et votre
EncapsulationModeEncapsulationModeL’ Mtu L'attribut indique l'unité de transmission maximale au
dispositif. Il s'agit de la taille de la plus grande unité de données de protocole (PDU) que l'appareil peut
envoyer.

Le MTU est par défaut de 1500 octets dans le Périphérique CsmaNet. Ce défaut correspond à un nombre
trouvé dans RFC 894, "Une norme pour la transmission de datagrammes IP sur Ethernet
Réseaux." Le nombre est en fait dérivé de la taille de paquet maximale pour 10Base5
(réseaux Ethernet complets) -- 1518 octets. Si vous soustrayez l'encapsulation DIX
surcharge pour les paquets Ethernet (18 octets), vous vous retrouverez avec une taille de données maximale possible
(MTU) de 1500 octets. On peut également constater que le MTU pour les réseaux IEEE 802.3 est 1492
octets. En effet, l'encapsulation LLC/SNAP ajoute huit octets supplémentaires de surcharge à
Le Colis. Dans les deux cas, le matériel sous-jacent ne peut envoyer que 1518 octets, mais les données
la taille est différente.

Afin de définir le mode d'encapsulation, le Périphérique CsmaNet fournit un Attribut appelé
EncapsulationModeEncapsulationMode qui peut prendre les valeurs Dix or SARL. Ceux-ci correspondent à Ethernet
et le cadrage LLC/SNAP respectivement.

Si l'on quitte le Mtu à 1500 octets et change le mode d'encapsulation en SARL, le résultat
sera un réseau qui encapsule des PDU de 1500 octets avec une trame LLC/SNAP résultant en
paquets de 1526 octets, ce qui serait illégal dans de nombreux réseaux, car ils peuvent transmettre un
maximum de 1518 octets par paquet. Cela se traduirait très probablement par une simulation qui
ne reflète pas assez subtilement la réalité à laquelle vous pourriez vous attendre.

Juste pour compliquer l'image, il existe des trames jumbo (1500 < MTU <= 9000 octets) et
les trames super-jumbo (MTU > 9000 octets) qui ne sont pas officiellement sanctionnées par l'IEEE mais
disponible dans certains réseaux et cartes réseau à haut débit (Gigabit). On pourrait laisser le
mode d'encapsulation défini sur Dixet définissez le Mtu Attribut sur un Périphérique CsmaNet à 64000 octets
-- même si un associé CsmaChannel Débit de données a été fixé à 10 mégabits par seconde. Cette
modéliserait essentiellement un commutateur Ethernet fabriqué à partir de 1980Base10 de style années 5
réseaux prenant en charge les datagrammes super-jumbo. Ce n'est certainement pas quelque chose qui a été
jamais fait, et il est peu probable qu'il soit jamais fait, mais il est assez facile à configurer pour vous.

Dans l'exemple précédent, vous avez utilisé la ligne de commande pour créer une simulation contenant 100
CSMA nœuds. Vous auriez tout aussi bien pu créer une simulation avec 500 nœuds. Si vous
modélisaient en fait ce réseau vampire-tap 10Base5, la longueur maximale d'une spécification complète
Le câble Ethernet mesure 500 mètres, avec un espacement minimum des prises de 2.5 mètres. Cela veut dire là
ne pouvait être que de 200 taps sur un vrai réseau. Vous auriez pu facilement construire un site illégal
réseau de cette façon aussi. Cela peut ou non aboutir à une simulation significative
selon ce que vous essayez de modéliser.

Des situations similaires peuvent se produire dans de nombreux endroits ns-3 et dans n'importe quel simulateur. Par exemple,
vous pourrez peut-être positionner les nœuds de manière à ce qu'ils occupent le même espace au
en même temps, ou vous pouvez être en mesure de configurer des amplificateurs ou des niveaux de bruit qui violent le
lois fondamentales de la physique.

ns-3 favorise généralement la flexibilité, et de nombreux modèles permettent de régler librement Attributs
sans essayer d'appliquer une cohérence arbitraire ou une spécification sous-jacente particulière.

La chose à retenir de cela est que ns-3 va fournir une base super flexible
à vous d'expérimenter. C'est à vous de comprendre ce que vous demandez au système
faire et s'assurer que les simulations que vous créez ont un sens et
connexion avec une réalité définie par vous.

Développement a Sans-fil Réseau topologie
Dans cette section, nous allons approfondir nos connaissances sur ns-3 périphériques réseau et
canaux pour couvrir un exemple de réseau sans fil. ns-3 fournit un ensemble de modèles 802.11
qui tentent de fournir une implémentation précise au niveau MAC de la spécification 802.11
et un modèle de niveau PHY "pas si lent" de la spécification 802.11a.

Tout comme nous avons vu les objets d'assistance de topologie point à point et CSMA lorsque
construire des topologies point à point, nous verrons des équivalents Wifi assistants de topologie dans
cette section. L'apparence et le fonctionnement de ces aides devraient sembler assez familiers pour
vous.

Nous fournissons un exemple de script dans notre exemples/tutoriel annuaire. Ce script s'appuie sur
le seconde.cc script et ajoute un réseau Wifi. Allez-y et ouvrez
exemples/tutoriel/troisième.cc dans votre éditeur préféré. Vous en aurez déjà assez vu
ns-3 code pour comprendre la plupart de ce qui se passe dans cet exemple, mais il y a quelques nouveaux
choses, nous allons donc passer en revue l'intégralité du script et examiner une partie de la sortie.

Tout comme dans le seconde.cc exemple (et en tout ns-3 exemples) le fichier commence par un emacs
ligne de mode et certains passe-partout GPL.

Jetez un œil à l'art ASCII (reproduit ci-dessous) qui montre la topologie du réseau par défaut
construit dans l'exemple. Vous pouvez voir que nous allons encore étendre notre exemple
en accrochant un réseau sans fil sur le côté gauche. Notez qu'il s'agit d'un réseau par défaut
topologie puisque vous pouvez réellement faire varier le nombre de nœuds créés sur le filaire et sans fil
réseaux. Tout comme dans le seconde.cc cas de script, si vous modifiez nCsma, cela vous donnera un
nombre de nœuds CSMA "supplémentaires". De même, vous pouvez définir nWifi pour contrôler combien STA
Les nœuds (station) sont créés dans la simulation. Il y en aura toujours un AP (point d'accès)
nœud sur le réseau sans fil. Par défaut, il y a trois nœuds CSMA "supplémentaires" et trois
sans fil STA nœuds.

Le code commence par charger les fichiers d'inclusion du module comme cela a été fait dans le seconde.cc Exemple.
Il y a quelques nouveautés correspondant au module Wifi et à la mobilité
module dont nous parlerons ci-dessous.

#include "ns3/core-module.h"
#include "ns3/point-à-point-module.h"
#include "ns3/network-module.h"
#include "ns3/applications-module.h"
#include "ns3/wifi-module.h"
#include "ns3/mobility-module.h"
#include "ns3/csma-module.h"
#include "ns3/internet-module.h"

L'illustration de la topologie du réseau est la suivante :

// Topologie de réseau par défaut
//
// Wi-Fi 10.1.3.0
// PA
// * * * *
// | | | | 10.1.1.0
// n5 n6 n7 n0 -------------- n1 n2 n3 n4
// point à point | | | |
// =================
// Réseau local 10.1.2.0

Vous pouvez voir que nous ajoutons un nouveau périphérique réseau au nœud sur le côté gauche du
liaison point à point qui devient le point d'accès au réseau sans fil. Un nombre de
des nœuds STA sans fil sont créés pour remplir le nouveau réseau 10.1.3.0, comme indiqué à gauche
côté de l'illustration.

Après l'illustration, le ns-3 l'espace de noms est d'utiliser et un composant de journalisation est défini.
Tout cela devrait être assez familier maintenant.

en utilisant l'espace de noms ns3 ;

NS_LOG_COMPONENT_DEFINE ("ThirdScriptExample");

Le programme principal commence comme seconde.cc en ajoutant des paramètres de ligne de commande pour
activer ou désactiver les composants de journalisation et modifier le nombre d'appareils créés.

bool verbeux = vrai ;
uint32_t nCsma = 3 ;
uint32_t nWifi = 3 ;

cmd de ligne de commande ;
cmd.AddValue ("nCsma", "Nombre de nœuds/périphériques CSMA \"supplémentaires\"", nCsma) ;
cmd.AddValue ("nWifi", "Nombre d'appareils wifi STA", nWifi);
cmd.AddValue ("verbeux", "Dites aux applications d'écho de se connecter si vrai", verbeux);

cmd.Parse (argc,argv);

si (verbeux)
{
LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);
LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO);
}

Comme dans tous les exemples précédents, l'étape suivante consiste à créer deux nœuds que nous allons
connecter via la liaison point à point.

NodeContainer p2pNodes ;
p2pNodes.Create (2);

Ensuite, nous voyons un vieil ami. Nous instancions un PointÀPointHelper et définir les associés
défaut Attributs de sorte que nous créons un émetteur de cinq mégabits par seconde sur les appareils
créé à l'aide de l'assistant et un délai de deux millisecondes sur les canaux créés par l'assistant.
Nous avons ensuite Installer les périphériques sur les nœuds et le canal entre eux.

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

NetDeviceContainer p2pDevices ;
p2pDevices = pointToPoint.Install (p2pNodes);

Ensuite, nous déclarons un autre Conteneur de nœud pour contenir les nœuds qui feront partie du bus
(CSMA).

NodeContainer csmaNodes ;
csmaNodes.Add (p2pNodes.Get (1));
csmaNodes.Create (nCsma);

La prochaine ligne de code Obtient le premier nœud (comme pour avoir un index de un) à partir du
conteneur de nœuds point à point et l'ajoute au conteneur de nœuds qui obtiendra CSMA
dispositifs. Le nœud en question va se retrouver avec un appareil point à point et un CSMA
dispositif. Nous créons ensuite un certain nombre de nœuds "supplémentaires" qui composent le reste du CSMA
réseau.

Nous instancions alors un CsmaHelperComment et définissez son Attributs comme nous l'avons fait dans l'exemple précédent.
Nous créons un NetDeviceContainer pour garder une trace des appareils réseau CSMA créés, puis nous
Installer Appareils CSMA sur les nœuds sélectionnés.

CsmaHelper csma ;
csma.SetChannelAttribute ("DataRate", StringValue ("100Mbps"));
csma.SetChannelAttribute ("Retard", TimeValue (NanoSeconds (6560)));

NetDeviceContainer csmaDevices ;
csmaDevices = csma.Install (csmaNodes);

Ensuite, nous allons créer les nœuds qui feront partie du réseau Wifi. Nous sommes
va créer un certain nombre de nœuds "station" comme spécifié par l'argument de ligne de commande, et
nous allons utiliser le nœud "le plus à gauche" du lien point à point comme nœud pour le
point d'accès.

NodeContainer wifiStaNodes ;
wifiStaNodes.Créer (nWifi);
NodeContainer wifiApNode = p2pNodes.Get (0);

Le morceau de code suivant construit les appareils wifi et le canal d'interconnexion entre
ces nœuds wifi. Tout d'abord, nous configurons le PHY et les assistants de canal :

Canal YansWifiChannelHelper = YansWifiChannelHelper::Default ();
YansWifiPhyHelper phy = YansWifiPhyHelper::Default ();

Pour plus de simplicité, ce code utilise la configuration de la couche PHY par défaut et les modèles de canal
qui sont documentés dans la documentation API doxygen pour le
YansWifiChannelHelper :: Par défaut et votre YansWifiPhyHelper :: Par défaut méthodes. Une fois ces objets
sont créés, nous créons un objet de canal et l'associons à notre gestionnaire d'objets de couche PHY
pour s'assurer que tous les objets de la couche PHY créés par le YansWifiPhyHelper part l'
même canal sous-jacent, c'est-à-dire qu'ils partagent le même support sans fil et peuvent
communication et interférence :

phy.SetChannel (channel.Create());

Une fois l'assistant PHY configuré, nous pouvons nous concentrer sur la couche MAC. Ici, nous choisissons de travailler
avec des MAC non Qos, nous utilisons donc un objet NqosWifiMacHelper pour définir les paramètres MAC.

WifiHelper wifi = WifiHelper::Par défaut ();
wifi.SetRemoteStationManager ("ns3::AarfWifiManager");

NqosWifiMacHelpermac = NqosWifiMacHelper::Default ();

Notre SetRemoteStationManager indique à l'assistant le type d'algorithme de contrôle de débit à
utilisation. Ici, il demande à l'assistant d'utiliser l'algorithme AARF --- les détails sont, bien sûr,
disponible en Doxygen.

Ensuite, nous configurons le type de MAC, le SSID du réseau d'infrastructure que nous voulons
configurer et assurez-vous que nos stations n'effectuent pas de sondage actif :

Ssid ssid = Ssid ("ns-3-ssid");
mac.SetType ("ns3::StaWifiMac",
"Ssid", SsidValue (ssid),
"ActiveProbing", BooleanValue (faux) );

Ce code crée d'abord un objet SSID (Service Set Identifier) ​​802.11 qui sera utilisé
pour définir la valeur du "Ssid" Attribut de l'implémentation de la couche MAC. Le particulier
le type de couche MAC qui sera créé par l'assistant est spécifié par Attribut comme étant de
le type "ns3::StaWifiMac". L'utilisation de NqosWifiMacHelper s'assurera que le
« Qos pris en charge » Attribut pour les objets MAC créés est défini sur faux. La combinaison de ces
deux configurations signifie que la prochaine instance MAC créée sera une non-QoS non-AP
(STA) dans un BSS d'infrastructure (c'est-à-dire un BSS avec un AP). Finalement, le
"ActiveProbing" Attribut est défini sur faux. Cela signifie que les demandes de sondage ne seront pas
envoyé par les MAC créés par cet assistant.

Une fois que tous les paramètres spécifiques à la station sont entièrement configurés, à la fois au niveau MAC et PHY
couches, nous pouvons invoquer notre désormais familier Installer méthode pour créer les appareils wifi de ces
gares :

staDevices NetDeviceContainer ;
staDevices = wifi.Install (phy, mac, wifiStaNodes);

Nous avons configuré le Wifi pour tous nos nœuds STA, et maintenant nous devons configurer l'AP
nœud (point d'accès). Nous commençons ce processus en modifiant la valeur par défaut Attributs des
NqosWifiMacHelper pour refléter les exigences de l'AP.

mac.SetType ("ns3::ApWifiMac",
"Ssid", SsidValue (ssid));

Dans ce cas, le NqosWifiMacHelper va créer des couches MAC du "ns3::ApWifiMac",
ce dernier spécifiant qu'une instance MAC configurée en AP doit être créée, avec le
type d'assistance impliquant que le "QosSupported" Attribut doit être défini sur false - désactivation
Prise en charge de la qualité de service de style 802.11e/WMM sur les points d'accès créés.

Les lignes suivantes créent le point d'accès unique qui partage le même ensemble de niveaux PHY Attributs (Et
canal) que les stations :

NetDeviceContainer apDevices ;
apDevices = wifi.Install (phy, mac, wifiApNode);

Maintenant, nous allons ajouter des modèles de mobilité. Nous voulons que les nœuds STA soient mobiles, errants
autour à l'intérieur d'une boîte englobante, et nous voulons rendre le nœud AP stationnaire. Nous utilisons le
Aide à la mobilité pour nous faciliter la tâche. Dans un premier temps, nous instancions un Aide à la mobilité objet
et mettre quelques Attributs contrôler la fonctionnalité « attribueur de position ».

MobilityAide à la mobilité ;

mobilité.SetPositionAllocator ("ns3::GridPositionAllocator",
"MinX", DoubleValeur (0.0),
"MinY", DoubleValeur (0.0),
"DeltaX", DoubleValue (5.0),
"DeltaY", DoubleValue (10.0),
"GridWidth", UintegerValue (3),
"LayoutType", StringValue ("RowFirst"));

Ce code indique à l'aide à la mobilité d'utiliser une grille à deux dimensions pour placer initialement le
nœuds STA. N'hésitez pas à explorer le Doxygen pour la classe ns3 :: GridPositionAllocator pour voir
exactement ce qui est fait.

Nous avons disposé nos nœuds sur une grille initiale, mais nous devons maintenant leur dire comment se déplacer.
Nous choisissons le RandomWalk2dMobilityModèle qui a les nœuds se déplacent dans une direction aléatoire à
une vitesse aléatoire à l'intérieur d'une boîte englobante.

mobilité.SetMobilityModel ("ns3::RandomWalk2dMobilityModel",
"Bounds", RectangleValue (Rectangle (-50, 50, -50, 50)) );

Nous disons maintenant au Aide à la mobilité pour installer les modèles de mobilité sur les nœuds STA.

mobilité.Install (wifiStaNodes);

Nous voulons que le point d'accès reste dans une position fixe pendant la simulation. Nous
accomplissez cela en définissant le modèle de mobilité pour ce nœud comme étant le
ns3 :: ConstantPositionMobilityModel:

Mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
mobilité.Install (wifiApNode);

Nous avons maintenant nos nœuds, appareils et canaux créés, et les modèles de mobilité choisis pour le
Nœuds Wifi, mais nous n'avons pas de piles de protocoles présentes. Tout comme nous l'avons fait auparavant de nombreux
fois, nous utiliserons le InternetStackHelper pour installer ces piles.

Pile InternetStackHelper ;
stack.Install (csmaNodes);
stack.Install (wifiApNode);
stack.Install (wifiStaNodes);

Tout comme dans le seconde.cc exemple de script, nous allons utiliser le Assistant d'adresse IPv4 à
attribuer des adresses IP à nos interfaces d'appareils. Nous utilisons d'abord le réseau 10.1.1.0 pour créer
les deux adresses nécessaires pour nos deux appareils point à point. Ensuite, nous utilisons le réseau 10.1.2.0
pour attribuer des adresses au réseau CSMA, puis nous attribuons des adresses à partir du réseau 10.1.3.0
aux appareils STA et au point d'accès sur le réseau sans fil.

Adresse Ipv4AddressHelper ;

adresse.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer p2pInterfaces ;
p2pInterfaces = adresse.Assign (p2pDevices);

adresse.SetBase ("10.1.2.0", "255.255.255.0");
Ipv4InterfaceContainer csmaInterfaces ;
csmaInterfaces = adresse.Assign (csmaDevices);

adresse.SetBase ("10.1.3.0", "255.255.255.0");
adresse.Assign (staDevices);
adresse.Assign (apDevices);

Nous plaçons le serveur d'écho sur le nœud "le plus à droite" dans l'illustration au début du
dossier. Nous l'avons déjà fait.

UdpEchoServerHelper echoServer (9);

ApplicationContainer serverApps = echoServer.Install (csmaNodes.Get (nCsma));
serverApps.Start (secondes (1.0));
serverApps.Stop (secondes (10.0));

Et nous plaçons le client echo sur le dernier nœud STA que nous avons créé, en le pointant vers le serveur sur
le réseau CSMA. Nous avons également vu des opérations similaires auparavant.

UdpEchoClientHelper echoClient (csmaInterfaces.GetAddress (nCsma), 9);
echoClient.SetAttribute ("MaxPackets", UintegerValue (1));
echoClient.SetAttribute ("Interval", TimeValue (Secondes (1.0)));
echoClient.SetAttribute ("PacketSize", UintegerValue (1024));

ApplicationContainer clientApps =
echoClient.Install (wifiStaNodes.Get (nWifi - 1));
clientApps.Start (secondes (2.0));
clientApps.Stop (Secondes (10.0));

Puisque nous avons construit un interréseau ici, nous devons activer le routage interréseau tout comme
nous avons fait dans le seconde.cc exemple de scénario.

Ipv4GlobalRoutingHelper ::PopulateRoutingTables ();

Une chose qui peut surprendre certains utilisateurs est le fait que la simulation que nous venons de créer
ne s'arrêtera jamais "naturellement". C'est parce que nous avons demandé au point d'accès sans fil de
générer des balises. Il générera des balises pour toujours, et cela se traduira par un simulateur
les événements étant programmés dans le futur indéfiniment, nous devons donc dire au simulateur de s'arrêter
même s'il peut avoir des événements de génération de balises programmés. La ligne de code suivante
dit au simulateur de s'arrêter pour que nous ne simulions pas les balises pour toujours et d'entrer ce qui est
essentiellement une boucle sans fin.

Simulator::Stop (Secondes (10.0));

Nous créons juste assez de traçage pour couvrir les trois réseaux :

pointToPoint.EnablePcapAll ("troisième");
phy.EnablePcap ("troisième", apDevices.Get (0));
csma.EnablePcap ("troisième", csmaDevices.Get (0), vrai);

Ces trois lignes de code lanceront le traçage pcap sur les deux nœuds point à point qui
sert de colonne vertébrale, lancera une trace en mode promiscuité (moniteur) sur le réseau Wifi,
et lancera une trace de promiscuité sur le réseau CSMA. Cela nous permettra de voir tous les
trafic avec un nombre minimum de fichiers de trace.

Enfin, nous exécutons la simulation, nettoyons puis quittons le programme.

Simulateur::Exécuter ();
Simulateur :: Détruire ();
0 revenir;
}

Pour exécuter cet exemple, vous devez copier le troisième.cc exemple de script dans le
répertoire de travail et utilisez Waf pour construire comme vous l'avez fait avec le seconde.cc Exemple. Si tu
sont dans le répertoire de niveau supérieur du référentiel que vous saisiriez,

$ cp exemples/tutoriel/third.cc scratch/mythird.cc
$ ./waf
$ ./waf --run scratch/montroisième

Encore une fois, puisque nous avons configuré les applications d'écho UDP comme nous l'avons fait dans le seconde.cc
script, vous verrez une sortie similaire.

Waf : Entrer dans le répertoire `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf : quitter le répertoire `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' terminé avec succès (0.407s)
Au moment 2s, le client a envoyé 1024 octets au port 10.1.2.4 9
Au moment 2.01796s, le serveur a reçu 1024 octets du port 10.1.3.3 49153
Au moment 2.01796s, le serveur a envoyé 1024 octets au port 10.1.3.3 49153
Au moment 2.03364s, le client a reçu 1024 octets du port 10.1.2.4 9

Rappelons que le premier message, Envoyés 1024 octets à 10.1.2.4," est le client d'écho UDP
envoyer un paquet au serveur. Dans ce cas, le client est sur le réseau sans fil
(10.1.3.0). Le deuxième message, "Reçu 1024 octets de 10.1.3.3," provient de l'écho UDP
serveur, généré lorsqu'il reçoit le paquet d'écho. Le message final, "Reçu 1024
octets de 10.1.2.4," provient du client echo, indiquant qu'il a reçu son echo
retour du serveur.

Si vous allez maintenant chercher dans le répertoire de niveau supérieur, vous trouverez quatre fichiers de trace de
cette simulation, deux du nœud zéro et deux du nœud un :

third-0-0.pcap third-0-1.pcap third-1-0.pcap third-1-1.pcap

Le fichier « third-0-0.pcap » correspond au périphérique point à point sur le nœud zéro -- le
côté gauche de la "colonne vertébrale". Le fichier "third-1-0.pcap" correspond au point à point
périphérique sur le nœud un - le côté droit de la "colonne vertébrale". Le fichier « third-0-1.pcap » sera
la trace promiscuité (mode moniteur) du réseau Wifi et le fichier "third-1-1.pcap"
sera la trace de la promiscuité du réseau CSMA. Pouvez-vous le vérifier en inspectant
le code?

Puisque le client echo est sur le réseau Wifi, commençons par là. Jetons un coup d'oeil au
trace de promiscuité (mode moniteur) que nous avons capturée sur ce réseau.

$ tcpdump -nn -tt -r troisième-0-1.pcap

Vous devriez voir des contenus d'apparence Wi-Fi que vous n'avez jamais vus ici :

lecture du fichier third-0-1.pcap, type de lien IEEE802_11 (802.11)
0.000025 Balise (ns-3-ssid) [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS
0.000308 Requête d'association (ns-3-ssid) [6.0 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit]
0.000324 Acknowledgment RA:00:00:00:00:00:08
0.000402 Réponse associée AIDE(0) :: Réussi
0.000546 Acknowledgment RA:00:00:00:00:00:0a
0.000721 Requête d'association (ns-3-ssid) [6.0 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit]
0.000737 Acknowledgment RA:00:00:00:00:00:07
0.000824 Réponse associée AIDE(0) :: Réussi
0.000968 Acknowledgment RA:00:00:00:00:00:0a
0.001134 Requête d'association (ns-3-ssid) [6.0 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit]
0.001150 Acknowledgment RA:00:00:00:00:00:09
0.001273 Réponse associée AIDE(0) :: Réussi
0.001417 Acknowledgment RA:00:00:00:00:00:0a
0.102400 Balise (ns-3-ssid) [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS
0.204800 Balise (ns-3-ssid) [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS
0.307200 Balise (ns-3-ssid) [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS

Vous pouvez voir que le type de lien est maintenant 802.11 comme vous vous en doutez. Vous pouvez probablement
comprendre ce qui se passe et trouver les paquets de demande et de réponse d'écho IP dans ce
trace. Nous le laissons comme un exercice pour analyser complètement le vidage de trace.

Maintenant, regardez le fichier pcap du côté droit du lien point à point,

$ tcpdump -nn -tt -r troisième-0-0.pcap

Encore une fois, vous devriez voir des contenus familiers :

lecture du fichier third-0-0.pcap, PPP de type lien (PPP)
2.008151 IP 10.1.3.3.49153 > 10.1.2.4.9 : UDP, longueur 1024
2.026758 IP 10.1.2.4.9 > 10.1.3.3.49153 : UDP, longueur 1024

C'est le paquet d'écho allant de gauche à droite (de Wifi à CSMA) et retour à travers
la liaison point à point.

Maintenant, regardez le fichier pcap du côté droit du lien point à point,

$ tcpdump -nn -tt -r troisième-1-0.pcap

Encore une fois, vous devriez voir des contenus familiers :

lecture du fichier third-1-0.pcap, PPP de type lien (PPP)
2.011837 IP 10.1.3.3.49153 > 10.1.2.4.9 : UDP, longueur 1024
2.023072 IP 10.1.2.4.9 > 10.1.3.3.49153 : UDP, longueur 1024

C'est aussi le paquet d'écho allant de gauche à droite (de Wifi à CSMA) et retour
sur la liaison point à point avec des horaires légèrement différents, comme vous pouvez vous y attendre.

Le serveur d'écho est sur le réseau CSMA, regardons la trace de promiscuité ici :

$ tcpdump -nn -tt -r troisième-1-1.pcap

Vous devriez voir des contenus familiers :

lecture à partir du fichier third-1-1.pcap, type de lien EN10MB (Ethernet)
2.017837 ARP, Request who-has 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1, longueur 50
2.017861 ARP, la réponse 10.1.2.4 est à 00:00:00:00:00:06, longueur 50
2.017861 IP 10.1.3.3.49153 > 10.1.2.4.9 : UDP, longueur 1024
2.022966 ARP, Request who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4, longueur 50
2.022966 ARP, la réponse 10.1.2.1 est à 00:00:00:00:00:03, longueur 50
2.023072 IP 10.1.2.4.9 > 10.1.3.3.49153 : UDP, longueur 1024

Cela devrait être facile à comprendre. Si vous avez oublié, revenez en arrière et regardez la discussion
in seconde.cc. C'est la même séquence.

Maintenant, nous avons passé beaucoup de temps à mettre en place des modèles de mobilité pour le réseau sans fil et il
serait dommage de finir sans même montrer que les nœuds STA bougent réellement
autour pendant la simulation. Faisons cela en nous connectant au MobilitéModèle cours
modifier la source de suivi. Ceci est juste un aperçu de la section de traçage détaillée qui est
à venir, mais cela semble un très bon endroit pour obtenir un exemple.

Comme mentionné dans la section "Tweaking ns-3", le ns-3 le système de traçage est divisé en trace
sources et puits de trace, et nous fournissons des fonctions pour connecter les deux. Nous utiliserons le
source de trace de changement de parcours prédéfini du modèle de mobilité pour générer les événements de trace. Nous
devra écrire un récepteur de trace pour se connecter à cette source qui affichera de jolis
informations pour nous. Malgré sa réputation de difficile, c'est vraiment très simple.
Juste avant le programme principal de la scratch/montiers.cc script (c'est-à-dire juste après le
NS_LOG_COMPONENT_DEFINE instruction), ajoutez la fonction suivante :

annuler
CourseChange (std :: contexte de chaîne, Ptr maquette)
{
Position du vecteur = modèle->GetPosition ();
NS_LOG_UNCOND (contexte <
" x = " << position.x << ", y = " << position.y);
}

Ce code extrait simplement les informations de position du modèle de mobilité et inconditionnellement
enregistre la position x et y du nœud. Nous allons faire en sorte que cette fonction soit
appelé chaque fois que le nœud sans fil avec le client écho change de position. Nous faisons cela
en utilisant l' Config :: Connecter fonction. Ajoutez les lignes de code suivantes au script juste
avant la Simulateur :: Exécuter appel.

std :: ostringstream oss;
oss <
"/NodeList/" << wifiStaNodes.Get (nWifi - 1)->GetId () <
"/$ns3::MobilityModel/CourseChange" ;

Config ::Connect (oss.str (), MakeCallback (&CourseChange));

Ce que nous faisons ici est de créer une chaîne contenant le chemin de l'espace de noms de suivi de l'événement
auquel nous voulons nous connecter. Tout d'abord, nous devons déterminer quel nœud nous voulons utiliser
le Obtenir l'ID méthode telle que décrite précédemment. Dans le cas du numéro par défaut de CSMA et
nœuds sans fil, cela s'avère être le nœud sept et le chemin de l'espace de noms de suivi vers le
modèle de mobilité ressemblerait,

/NodeList/7/$ns3::MobilityModel/CourseChange

Sur la base de la discussion dans la section de traçage, vous pouvez en déduire que ce chemin de trace
fait référence au septième nœud dans la NodeList globale. Il précise ce qu'on appelle un
objet agrégé de type ns3::MobilityModèle. Le préfixe du signe dollar implique que le
MobilityModel est agrégé au nœud sept. La dernière composante du chemin signifie que nous
se connectent à l'événement "CourseChange" de ce modèle.

Nous établissons une connexion entre la source de trace dans le nœud sept avec notre puits de trace en appelant
Config :: Connecter et en passant ce chemin d'espace de noms. Une fois cela fait, chaque changement de cap
événement sur le nœud sept sera accroché à notre récepteur de trace, qui imprimera à son tour le
nouvelle position.

Si vous exécutez maintenant la simulation, vous verrez les changements de parcours affichés au fur et à mesure qu'ils se produisent.

'build' terminé avec succès (5.989s)
/NodeList/7/$ns3::MobilityModel/CourseChange x = 10, y = 0
/NodeList/7/$ns3::MobilityModel/CourseChange x = 10.3841, y = 0.923277
/NodeList/7/$ns3::MobilityModel/CourseChange x = 10.2049, y = 1.90708
/NodeList/7/$ns3::MobilityModel/CourseChange x = 10.8136, y = 1.11368
/NodeList/7/$ns3::MobilityModel/CourseChange x = 10.8452, y = 2.11318
/NodeList/7/$ns3::MobilityModel/CourseChange x = 10.9797, y = 3.10409
Au moment 2s, le client a envoyé 1024 octets au port 10.1.2.4 9
Au moment 2.01796s, le serveur a reçu 1024 octets du port 10.1.3.3 49153
Au moment 2.01796s, le serveur a envoyé 1024 octets au port 10.1.3.3 49153
Au moment 2.03364s, le client a reçu 1024 octets du port 10.1.2.4 9
/NodeList/7/$ns3::MobilityModel/CourseChange x = 11.3273, y = 4.04175
/NodeList/7/$ns3::MobilityModel/CourseChange x = 12.013, y = 4.76955
/NodeList/7/$ns3::MobilityModel/CourseChange x = 12.4317, y = 5.67771
/NodeList/7/$ns3::MobilityModel/CourseChange x = 11.4607, y = 5.91681
/NodeList/7/$ns3::MobilityModel/CourseChange x = 12.0155, y = 6.74878
/NodeList/7/$ns3::MobilityModel/CourseChange x = 13.0076, y = 6.62336
/NodeList/7/$ns3::MobilityModel/CourseChange x = 12.6285, y = 5.698
/NodeList/7/$ns3::MobilityModel/CourseChange x = 13.32, y = 4.97559
/NodeList/7/$ns3::MobilityModel/CourseChange x = 13.1134, y = 3.99715
/NodeList/7/$ns3::MobilityModel/CourseChange x = 13.8359, y = 4.68851
/NodeList/7/$ns3::MobilityModel/CourseChange x = 13.5953, y = 3.71789
/NodeList/7/$ns3::MobilityModel/CourseChange x = 12.7595, y = 4.26688
/NodeList/7/$ns3::MobilityModel/CourseChange x = 11.7629, y = 4.34913
/NodeList/7/$ns3::MobilityModel/CourseChange x = 11.2292, y = 5.19485
/NodeList/7/$ns3::MobilityModel/CourseChange x = 10.2344, y = 5.09394
/NodeList/7/$ns3::MobilityModel/CourseChange x = 9.3601, y = 4.60846
/NodeList/7/$ns3::MobilityModel/CourseChange x = 8.40025, y = 4.32795
/NodeList/7/$ns3::MobilityModel/CourseChange x = 9.14292, y = 4.99761
/NodeList/7/$ns3::MobilityModel/CourseChange x = 9.08299, y = 5.99581
/NodeList/7/$ns3::MobilityModel/CourseChange x = 8.26068, y = 5.42677
/NodeList/7/$ns3::MobilityModel/CourseChange x = 8.35917, y = 6.42191
/NodeList/7/$ns3::MobilityModel/CourseChange x = 7.66805, y = 7.14466
/NodeList/7/$ns3::MobilityModel/CourseChange x = 6.71414, y = 6.84456
/NodeList/7/$ns3::MobilityModel/CourseChange x = 6.42489, y = 7.80181

TRACÉ


Biographie
Comme mentionné dans UsingTracingSystem, tout l'intérêt d'exécuter un ns-3 la simulation consiste à
générer des résultats pour l'étude. Vous avez deux stratégies de base pour obtenir la sortie de ns-3:
en utilisant des mécanismes génériques de sortie en bloc prédéfinis et en analysant leur contenu pour extraire
Une information intéressante; ou développer d'une manière ou d'une autre un mécanisme de sortie qui transmet exactement
(et peut-être seulement) les informations recherchées.

L'utilisation de mécanismes de sortie en bloc prédéfinis présente l'avantage de ne nécessiter aucune modification de
ns-3, mais cela peut nécessiter l'écriture de scripts pour analyser et filtrer les données d'intérêt. Souvent,
PPCE ou NS_LOG les messages de sortie sont rassemblés pendant les simulations et exécutés séparément
à travers des scripts qui utilisent grep, sed or awk pour analyser les messages et réduire et transformer
les données sous une forme gérable. Les programmes doivent être écrits pour effectuer la transformation, donc ceci
ne vient pas gratuitement. NS_LOG la sortie n'est pas considérée comme faisant partie du ns-3 API, et peut
changer sans avertissement entre les versions. En outre, NS_LOG la sortie n'est disponible que dans
debug construit, donc s'appuyer dessus impose une pénalité de performance. Bien sûr, si le
informations d'intérêt n'existent dans aucun des mécanismes de sortie prédéfinis, cela
approche échoue.

Si vous avez besoin d'ajouter quelques informations aux mécanismes de masse prédéfinis, cela peut
certainement être fait ; et si vous utilisez l'un des ns-3 mécanismes, vous pouvez obtenir votre code ajouté
à titre d'apport.

ns-3 fournit un autre mécanisme, appelé Tracing, qui évite certains des problèmes inhérents
dans les mécanismes de sortie en masse. Il présente plusieurs avantages importants. Tout d'abord, vous pouvez
réduisez la quantité de données que vous avez à gérer en ne traçant que les événements qui vous intéressent
(pour les grandes simulations, le vidage de tout sur disque pour le post-traitement peut créer des E/S
goulots d'étranglement). Deuxièmement, si vous utilisez cette méthode, vous pouvez contrôler le format de la sortie
directement afin d'éviter l'étape de post-traitement avec sed, awk, perl or python scripts. Si
que vous désirez, votre sortie peut être formatée directement dans une forme acceptable par gnuplot, par
exemple (voir aussi GnuplotHelper). Vous pouvez ajouter des crochets dans le noyau qui peuvent ensuite être
accessible par d'autres utilisateurs, mais qui ne produira aucune information à moins qu'il ne soit explicitement demandé de
faites-le. Pour ces raisons, nous croyons que le ns-3 système de traçage est le meilleur moyen d'obtenir
informations d'une simulation et est donc également l'un des mécanismes les plus importants
comprendre dans ns-3.

Émoussé Instruments
Il existe de nombreuses façons d'extraire des informations d'un programme. Le moyen le plus direct est
pour simplement imprimer les informations directement sur la sortie standard, comme dans :

#inclure

annuler
SomeFunction (vide)
{
uint32_t x = SOME_INTERESTING_VALUE ;

std::cout << "La valeur de x est " << x << std::endl;

}

Personne ne vous empêchera d'aller au cœur de ns-3 et ajout d'impression
déclarations. C'est incroyablement facile à faire et, après tout, vous avez le contrôle total de votre
propre ns-3 bifurquer. Cela ne s'avérera probablement pas très satisfaisant à long terme.
terme, cependant.

Au fur et à mesure que le nombre d'instructions imprimées augmente dans vos programmes, la tâche de traiter les
grand nombre de sorties deviendra de plus en plus compliqué. Finalement, vous pourriez vous sentir
la nécessité de contrôler quelles informations sont imprimées d'une manière ou d'une autre, peut-être en activant
et de certaines catégories d'impressions, ou en augmentant ou en diminuant la quantité de
informations que vous souhaitez. Si vous continuez sur cette voie, vous découvrirez peut-être que vous avez
a remis en place le NS_LOG mécanisme (voir Utilisation de Logging). Pour éviter cela, l'un des
la première chose que vous pourriez envisager est d'utiliser NS_LOG elle-même.

Nous avons mentionné ci-dessus qu'une façon d'extraire des informations de ns-3 est d'analyser l'existant NS_LOG
sortie pour des informations intéressantes. Si vous découvrez qu'une bribe d'information vous
besoin n'est pas présent dans la sortie de journal existante, vous pouvez modifier le noyau de ns-3 et ajoutez simplement
vos informations intéressantes au flux de sortie. Maintenant, c'est certainement mieux que
ajouter vos propres déclarations d'impression car il suit ns-3 conventions de codage et pourrait
être potentiellement utile à d'autres personnes en tant que patch pour le noyau existant.

Prenons un exemple au hasard. Si vous vouliez ajouter plus de journalisation au ns-3 socket TCP
(tcp-socket-base.cc), vous pouvez simplement ajouter un nouveau message dans l'implémentation. Remarquer
en ce que TcpSocketBase ::ReceivedAck() il n'y a pas de message de journal pour le cas no ACK. Tu
pourrait simplement en ajouter un, en changeant le code. Voici l'original :

/** Traiter l'ACK nouvellement reçu */
annuler
TcpSocketBase::ReceivedAck (Ptr paquet, const TcpHeader & tcpHeader)
{
NS_LOG_FUNCTION (this << tcpHeader);

// Reçu ACK. Comparez le numéro ACK avec le numéro de séquence non acquitté le plus élevé
si (0 == (tcpHeader.GetFlags () & TcpHeader::ACK))
{ // Ignorer si aucun drapeau ACK
}


Pour enregistrer le cas sans ACK, vous pouvez ajouter un nouveau NS_LOG_LOGIC dans le if corps de l'instruction :

/** Traiter l'ACK nouvellement reçu */
annuler
TcpSocketBase::ReceivedAck (Ptr paquet, const TcpHeader & tcpHeader)
{
NS_LOG_FUNCTION (this << tcpHeader);

// Reçu ACK. Comparez le numéro ACK avec le numéro de séquence non acquitté le plus élevé
si (0 == (tcpHeader.GetFlags () & TcpHeader::ACK))
{ // Ignorer si aucun drapeau ACK
NS_LOG_LOGIC ("TcpSocketBase " << this << " aucun drapeau ACK ");
}


Cela peut sembler assez simple et satisfaisant à première vue, mais quelque chose à considérer est
que vous allez écrire du code pour ajouter NS_LOG déclarations et vous devrez également écrire
code (comme dans grep, sed or awk scripts) pour analyser la sortie du journal afin d'isoler votre
informations. C'est parce que même si vous avez un certain contrôle sur ce qui est produit par le
système de journalisation, vous n'avez le contrôle que jusqu'au niveau du composant de journalisation, qui est généralement
un fichier de code source entier.

Si vous ajoutez du code à un module existant, vous devrez également vivre avec la sortie
que tous les autres développeurs ont trouvé intéressant. Vous pouvez constater que pour obtenir le
petite quantité d'informations dont vous avez besoin, vous devrez peut-être parcourir d'énormes quantités de
messages superflus qui ne vous intéressent pas. Vous pouvez être obligé d'enregistrer un énorme journal
fichiers sur le disque et traitez-les en quelques lignes chaque fois que vous voulez faire quelque chose.

Puisqu'il n'y a aucune garantie dans ns-3 sur la stabilité de NS_LOG sortie, vous pouvez également
découvrez que des éléments de sortie de journal dont vous dépendez disparaissent ou changent entre
versions. Si vous dépendez de la structure de la sortie, vous pouvez trouver d'autres messages
ajoutés ou supprimés qui peuvent affecter votre code d'analyse.

Enfin, NS_LOG la sortie n'est disponible que dans les versions de débogage, vous ne pouvez pas obtenir de sortie de journal à partir de
des builds optimisés, qui s'exécutent environ deux fois plus vite. Reposant sur NS_LOG impose une performance
peine.

Pour ces raisons, nous considérons les impressions comme std :: cout et votre NS_LOG les messages soient rapides et
façons sales d'obtenir plus d'informations ns-3, mais ne convient pas aux travaux sérieux.

Il est souhaitable d'avoir une installation stable utilisant des API stables qui permettent d'accéder à
le système central et obtenir uniquement les informations requises. Il est souhaitable de pouvoir faire
ceci sans avoir à modifier et recompiler le système central. Encore mieux serait un
système qui avertit le code utilisateur lorsqu'un élément d'intérêt a changé ou un événement intéressant
s'est produit afin que l'utilisateur n'ait pas à fouiller activement dans le système à la recherche
des choses.

Notre ns-3 Le système de traçage est conçu pour fonctionner dans ce sens et est bien intégré avec
l'attribut et Config sous-systèmes permettant des scénarios d'utilisation relativement simples.

Aperçu
Notre ns-3 système de traçage repose sur les concepts de sources de traçage indépendantes et
tracer les puits, ainsi qu'un mécanisme uniforme pour connecter les sources aux puits.

Les sources de trace sont des entités qui peuvent signaler des événements qui se produisent dans une simulation et fournir
accès à des données sous-jacentes intéressantes. Par exemple, une source de trace peut indiquer quand un
le paquet est reçu par un dispositif réseau et fournit un accès au contenu du paquet pour
les puits de trace intéressés. Une source de trace peut également indiquer quand un état intéressant
le changement se produit dans un modèle. Par exemple, la fenêtre de congestion d'un modèle TCP est un nombre premier
candidat pour une source de trace. Chaque fois que la fenêtre de congestion change de trace connectée
les puits sont notifiés avec l'ancienne et la nouvelle valeur.

Les sources de traces ne sont pas utiles en elles-mêmes ; ils doivent être connectés à d'autres morceaux de code
qui font réellement quelque chose d'utile avec les informations fournies par la source. le
les entités qui consomment des informations de trace sont appelées puits de trace. Les sources de traces sont
les générateurs de données et les puits de traces sont des consommateurs. Cette division explicite permet de grands
nombre de sources de traces à disperser dans le système à des endroits qui modélisent les auteurs
pense que cela pourrait être utile. L'insertion de sources de trace introduit une très petite exécution
aérien.

Il peut y avoir zéro ou plusieurs consommateurs d'événements de trace générés par une source de trace. On peut
considérez une source de trace comme une sorte de lien d'information point à multipoint. Votre code
la recherche d'événements de trace à partir d'un morceau particulier de code de base pourrait coexister avec bonheur avec
autre code faisant quelque chose de complètement différent de la même information.

À moins qu'un utilisateur ne connecte un récepteur de trace à l'une de ces sources, rien n'est généré. En utilisant
le système de traçage, vous et d'autres personnes accrochées à la même source de traçage obtenez
exactement ce qu'ils veulent et seulement ce qu'ils veulent du système. Aucun de vous n'est
avoir un impact sur tout autre utilisateur en modifiant les informations fournies par le système. Si vous
s'il arrive d'ajouter une source de trace, votre travail en tant que bon citoyen open source peut permettre à d'autres
utilisateurs de fournir de nouveaux utilitaires peut-être très utiles dans l'ensemble, sans rien faire
changements à la ns-3 au coeur.

Simple Exemple
Prenons quelques minutes et passons en revue un exemple de traçage simple. Nous allons avoir besoin
un peu de contexte sur les rappels pour comprendre ce qui se passe dans l'exemple, donc nous
il faut faire un petit détour tout de suite.

Rappels
L'objectif du système Callback dans ns-3 est de permettre à un morceau de code d'appeler une fonction
(ou méthode en C++) sans aucune dépendance inter-module spécifique. Cela signifie finalement
vous avez besoin d'une sorte d'indirection - vous traitez l'adresse de la fonction appelée comme un
variable. Cette variable est appelée variable pointeur vers fonction. La relation
entre la fonction et le pointeur vers la fonction n'est vraiment pas différent de celui de l'objet et
pointeur sur objet.

En C, l'exemple canonique d'un pointeur vers une fonction est un
pointeur vers un entier de retour de fonction (PFI). Pour un PFI en prenant un int paramètre, ce
pourrait être déclaré comme,

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

(Mais lisez le FAQ C++ Blog 33 avant d'écrire un code comme celui-ci !) Ce que vous obtenez de ceci
est une variable nommée simplement Pfi qui est initialisé à la valeur 0. Si vous voulez
initialiser ce pointeur à quelque chose de significatif, vous devez avoir une fonction avec un
signature correspondante. Dans ce cas, vous pouvez fournir une fonction qui ressemble à :

int MaFonction (int arg) {}

Si vous avez cette cible, vous pouvez initialiser la variable pour qu'elle pointe vers votre fonction :

pfi = MaFonction;

Vous pouvez alors appeler MyFunction indirectement en utilisant la forme plus suggestive de l'appel :

résultat int = (*pfi) (1234);

Ceci est suggestif car il semble que vous déréférencez simplement le pointeur de fonction
comme si vous déréférencez n'importe quel pointeur. En règle générale, cependant, les gens profitent de la
le fait que le compilateur sait ce qui se passe et utilisera simplement une forme plus courte :

résultat int = pfi (1234);

Il semble que vous appeliez une fonction nommée Pfi, mais le compilateur est assez intelligent pour
savoir appeler via la variable Pfi indirectement à la fonction MaFonction.

Conceptuellement, c'est presque exactement ainsi que fonctionne le système de traçage. En gros, une trace
lavabo is un rappel. Lorsqu'un puits de trace exprime son intérêt à recevoir des événements de trace, il
s'ajoute en tant que rappel à une liste de rappels détenus en interne par la source de trace.
Lorsqu'un événement intéressant se produit, la source de trace invoque son opérateur(...) aportando
zéro ou plusieurs arguments. La opérateur(...) finit par errer dans le système et
fait quelque chose de remarquable comme l'appel indirect que vous venez de voir, fournissant zéro ou plus
paramètres, tout comme l'appel à Pfi ci-dessus a passé un paramètre à la fonction cible
MaFonction.

La différence importante ajoutée par le système de traçage est que pour chaque source de traçage,
est une liste interne de rappels. Au lieu de faire un seul appel indirect, une trace
source peut invoquer plusieurs Callbacks. Lorsqu'un puits de trace exprime son intérêt pour
notifications d'une source de trace, il s'arrange simplement pour ajouter sa propre fonction à
la liste de rappel.

Si vous êtes intéressé par plus de détails sur la façon dont cela est réellement organisé dans ns-3, ressentir
libre de parcourir la section Callback du ns-3 Manuel.

Procédure pas à pas: quatrième.cc
Nous avons fourni du code pour implémenter ce qui est vraiment l'exemple le plus simple de traçage
qui peut être assemblé. Vous pouvez trouver ce code dans le répertoire du tutoriel comme quatrième.cc.
Parcourons-le :

/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Ce programme est un logiciel gratuit ; vous pouvez le redistribuer et/ou modifier
* sous les termes de la licence publique générale GNU version 2 comme
* publié par la Free Software Foundation ;
*
* Ce programme est distribué dans l'espoir qu'il vous sera utile,
* mais SANS AUCUNE GARANTIE ; sans même la garantie implicite de
* QUALITÉ MARCHANDE ou ADAPTATION À UN USAGE PARTICULIER. Voir le
* Licence publique générale GNU pour plus de détails.
*
* Vous devriez avoir reçu une copie de la licence publique générale GNU
* avec ce programme; sinon, écrivez au Logiciel Libre
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 États-Unis
*/

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

#inclure

en utilisant l'espace de noms ns3 ;

La majeure partie de ce code devrait vous être assez familière. Comme mentionné ci-dessus, le système de trace
fait un usage intensif des systèmes d'objets et d'attributs, vous devrez donc les inclure.
Les deux premiers inclus ci-dessus introduisent explicitement les déclarations de ces systèmes. Tu
pourrait utiliser l'en-tête du module principal pour tout obtenir en même temps, mais nous faisons les inclusions
explicitement ici pour illustrer à quel point tout cela est vraiment simple.

Le fichier, valeur-tracée.h apporte les déclarations requises pour le traçage des données qui
obéit à la sémantique des valeurs. En général, la sémantique des valeurs signifie simplement que vous pouvez passer le
objet lui-même autour, plutôt que de passer l'adresse de l'objet. Qu'est-ce que tout cela vraiment
signifie que vous serez en mesure de tracer toutes les modifications apportées à une TracedValue de manière vraiment
manière simple.

Étant donné que le système de traçage est intégré aux attributs et que les attributs fonctionnent avec les objets,
il doit y avoir un ns-3 Objet pour que la source de trace réside. L'extrait de code suivant
déclare et définit un objet simple avec lequel nous pouvons travailler.

classe MonObjet : Objet public
{
publique:
TypeId statique GetTypeId (vide)
{
statique TypeId tid = TypeId ("MonObjet")
.SetParent (Objet :: GetTypeId ())
.AddConstructor ()
.AddTraceSource ("MonEntier",
"Une valeur entière à tracer.",
MakeTraceSourceAccessor (&MyObject::m_myInt),
"ns3::Traced::Value::Int32Callback")
;
retour tid;
}

MonObjet () {}
Valeur tracée m_monInt ;
};

Les deux lignes de code importantes, ci-dessus, en ce qui concerne le traçage sont les .AddTraceSource
et la Valeur tracée déclaration de m_myInt.

Notre .AddTraceSource fournit les "hooks" utilisés pour connecter la source de trace au
monde extérieur via le système Config. Le premier argument est un nom pour cette trace
source, ce qui le rend visible dans le système de configuration. Le deuxième argument est une chaîne d'aide.
Maintenant, regardez le troisième argument, concentrez-vous en fait sur le argument du troisième argument :
&MonObjet::m_monInt. Il s'agit de la TracedValue qui est ajoutée à la classe ; c'est
toujours un membre de données de classe. (Le dernier argument est le nom d'un typedef pour
Type TracedValue, sous forme de chaîne. Ceci est utilisé pour générer de la documentation pour le bon
La signature de la fonction de rappel, qui est particulièrement utile pour les types plus généraux de
rappels.)

Notre Valeur tracée<> déclaration fournit l'infrastructure qui pilote le rappel
traiter. Chaque fois que la valeur sous-jacente est modifiée, le mécanisme TracedValue fournira
l'ancienne et la nouvelle valeur de cette variable, dans ce cas une int32_t évaluer. La piste
la fonction de puits pour cette TracedValue aura besoin de la signature

void (* TracedValueCallback)(const int32_t oldValue, const int32_t newValue);

Tous les puits de trace accrochant cette source de trace doivent avoir cette signature. Nous discuterons ci-dessous
comment vous pouvez déterminer la signature de rappel requise dans d'autres cas.

Effectivement, en continuant à travers quatrième.cc nous voyons:

annuler
IntTrace (int32_t ancienne valeur, int32_t nouvelle valeur)
{
std::cout << "Tracé" << oldValue << " à " << newValue << std::endl;
}

Il s'agit de la définition d'un récepteur de trace correspondant. Il correspond directement au rappel
signature de fonction. Une fois connectée, cette fonction sera appelée chaque fois que le
Valeur tracée changements.

Nous avons maintenant vu la source de la trace et le puits de la trace. Ce qui reste est le code pour connecter le
source à l'évier, ce qui se produit dans principal:

int
principal (int argc, char *argv[])
{
Ptr monObjet = CréerObjet ();
myObject->TraceConnectWithoutContext ("MyInteger", MakeCallback(&IntTrace));

monObjet->m_myInt = 1234 ;
}

Ici, nous créons d'abord l'instance MyObject dans laquelle réside la source de la trace.

La prochaine étape, la TraceConnexionSansContexte, forme le lien entre la trace
source et le puits de trace. Le premier argument est juste le nom de la source de trace "MyInteger"
nous avons vu plus haut. Remarquez le FaireRappel fonction de modèle. Cette fonction fait la magie
nécessaire pour créer le sous-jacent ns-3 Objet de rappel et associez-le à la fonction
IntTrace. TraceConnect fait l'association entre votre fonction fournie et
surchargé opérateur() dans la variable tracée référencée par l'attribut "MyInteger".
Une fois cette association effectuée, la source de trace "lancera" votre rappel fourni
la fonction.

Le code pour que tout cela se produise est, bien sûr, non trivial, mais l'essentiel est que
vous organisez quelque chose qui ressemble à la pfi() exemple ci-dessus pour être appelé
par la source de trace. La déclaration de la Valeur tracée m_monInt ; dans l'Objet
effectue lui-même la magie nécessaire pour fournir les opérateurs d'affectation surchargés qui
utiliser le opérateur() pour invoquer réellement le rappel avec les paramètres souhaités. La
.AddTraceSource effectue la magie pour connecter le rappel au système de configuration, et
TraceConnexionSansContexte effectue la magie pour connecter votre fonction à la trace
source, qui est spécifié par le nom d'attribut.

Ignorons le peu de contexte pour l'instant.

Enfin, la ligne attribuant une valeur à m_myInt:

monObjet->m_myInt = 1234 ;

doit être interprété comme une invocation opérateur= sur la variable membre m_myInt avec
l'entier 1234 passé en paramètre.

Depuis que m_myInt est une Valeur tracée, cet opérateur est défini pour exécuter un rappel qui
renvoie void et prend deux valeurs entières comme paramètres --- une ancienne valeur et une nouvelle valeur
pour l'entier en question. C'est exactement la signature de fonction pour le rappel
fonction que nous avons fournie --- IntTrace.

Pour résumer, une source de trace est, par essence, une variable qui contient une liste de rappels. UNE
trace sink est une fonction utilisée comme cible d'un rappel. L'attribut et le type d'objet
les systèmes d'information sont utilisés pour fournir un moyen de connecter les sources de trace aux puits de trace.
L'acte de "toucher" une source de trace exécute un opérateur sur la source de trace qui
déclenche des rappels. Cela se traduit par des rappels de puits de trace qui enregistrent un intérêt pour le
source étant appelée avec les paramètres fournis par la source.

Si vous générez et exécutez maintenant cet exemple,

$ ./waf --exécuter le quatrième

vous verrez la sortie du IntTrace la fonction s'exécute dès que la source de la trace est
frapper:

Tracé de 0 à 1234

Lorsque nous avons exécuté le code, monObjet->m_myInt = 1234;, la source de trace déclenchée et
fournissait automatiquement les valeurs avant et après au récepteur de trace. La fonction
IntTrace puis imprimé ceci sur la sortie standard.

Connectez-vous avec Config
Notre TraceConnexionSansContexte l'appel montré ci-dessus dans l'exemple simple est en fait très
rarement utilisé dans le système. Plus typiquement, le Config sous-système est utilisé pour sélectionner une trace
source dans le système en utilisant ce qu'on appelle un Config chemin. Nous en avons vu un exemple dans le
section précédente où nous avons accroché l'événement "CourseChange" lorsque nous expérimentions avec
troisième.cc.

Rappelons que nous avons défini un puits de trace pour imprimer les informations de changement de cap de la mobilité
modèles de notre simulation. Il devrait maintenant être beaucoup plus clair pour vous ce qu'est cette fonction
Faire:

annuler
CourseChange (std :: contexte de chaîne, Ptr maquette)
{
Position du vecteur = modèle->GetPosition ();
NS_LOG_UNCOND (contexte <
" x = " << position.x << ", y = " << position.y);
}

Lorsque nous avons connecté la source de trace "CourseChange" au récepteur de trace ci-dessus, nous avons utilisé un
Chemin de configuration pour spécifier la source lorsque nous avons organisé une connexion entre le pré-défini
source de trace et le nouveau récepteur de trace :

std :: ostringstream oss;
oss << "/NodeList/"
<< wifiStaNodes.Get (nWifi - 1)->GetId ()
<< "/$ns3::MobilityModel/CourseChange" ;

Config ::Connect (oss.str (), MakeCallback (&CourseChange));

Essayons de donner un sens à ce qui est parfois considéré comme un code relativement mystérieux.
Pour les besoins de la discussion, supposons que le numéro de nœud renvoyé par le GetID() is
"sept". Dans ce cas, le chemin ci-dessus s'avère être

"/NodeList/7/$ns3::MobilityModel/CourseChange"

Le dernier segment d'un chemin de configuration doit être un Attribut d'un Objet. En fait, si vous aviez
un pointeur vers le Objet qui a le "CourseChange" Attribut pratique, vous pourriez écrire ceci
comme nous l'avons fait dans l'exemple précédent. Vous savez maintenant que nous stockons généralement
pointeurs vers notre Nodes dans un NodeContainer. Dans le troisième.cc exemple, les nœuds d'intérêt
sont stockés dans le wifiStaNodes NodeContainer. En fait, tout en construisant le chemin,
nous avons utilisé ce conteneur pour obtenir un Ptr que nous avions l'habitude d'appeler GetID(). Nous pourrions avoir
utilisé ceci Ptr pour appeler directement une méthode Connect :

Ptr theObject = wifiStaNodes.Get (nWifi - 1);
theObject->TraceConnectWithoutContext("CourseChange", MakeCallback (&CourseChange));

Dans le troisième.cc exemple, nous voulions en fait qu'un "contexte" supplémentaire soit fourni avec
avec les paramètres de rappel (qui seront expliqués ci-dessous) afin que nous puissions réellement utiliser le
code équivalent suivant :

Ptr theObject = wifiStaNodes.Get (nWifi - 1);
theObject->TraceConnect ("CourseChange", MakeCallback (&CourseChange));

Il s'avère que le code interne de Config :: ConnectWithoutContext et votre Config :: Connecter
trouver en fait un Ptr et appeler le correspondant TraceConnect méthode au plus bas
niveau.

Notre Config les fonctions prennent un chemin qui représente une chaîne de Objet pointeurs. Chaque segment
d'un chemin correspond à un attribut d'objet. Le dernier segment est l'attribut de
intérêt, et les segments précédents doivent être typés pour contenir ou trouver des objets. La Config code
analyse et "parcourt" ce chemin jusqu'à ce qu'il atteigne le dernier segment du chemin. Alors
interprète le dernier segment comme un Attribut sur le dernier objet qu'il a trouvé en parcourant le
chemin. La Config les fonctions appellent ensuite les fonctions appropriées TraceConnect or
TraceConnexionSansContexte méthode sur l'objet final. Voyons un peu ce qui se passe
plus de détails lorsque le chemin ci-dessus est parcouru.

Le premier caractère "/" dans le chemin fait référence à ce que l'on appelle un espace de noms. Un de
espaces de noms prédéfinis dans le système de configuration est "NodeList" qui est une liste de tous les
nœuds dans la simulation. Les éléments de la liste sont référencés par des indices dans la liste, donc
"/NodeList/7" fait référence au huitième nœud dans la liste des nœuds créés lors de la simulation
(les indices de rappel commencent à 0 '). Cette référence is actually a ``Ptr ` et est donc un
sous-classe d'un ns3::Objet.

Comme décrit dans la section Modèle d'objet du ns-3 Manuel, nous utilisons largement
agrégation d'objets. Cela nous permet de former une association entre différents objets
sans construire un arbre d'héritage compliqué ou prédécider quels objets feront partie
d'un nœud. Chaque objet d'une agrégation est accessible à partir des autres objets.

Dans notre exemple, le prochain segment de chemin parcouru commence par le caractère "$". Cette
indique au système de configuration que le segment est le nom d'un type d'objet, donc un
Getobject appel doit être fait à la recherche de ce type. Il s'avère que le Aide à la mobilité
utilisé dans troisième.cc s'arrange pour Agréger, ou associer, un modèle de mobilité à chacun des
sans fil Nodes. Lorsque vous ajoutez le "$", vous demandez un autre objet qui a
vraisemblablement été agrégés auparavant. Vous pouvez considérer cela comme un changement de pointeurs de
le Ptr d'origine comme spécifié par "/NodeList/7" à son modèle de mobilité associé ---
qui est de type ns3::MobilityModèle. Si vous connaissez Getobject, nous avons demandé
le système pour faire ce qui suit :

Ptr MobilityModel = node->GetObject ()

Nous sommes maintenant au dernier objet du chemin, nous portons donc notre attention sur les attributs de
cet Objet. La MobilitéModèle class définit un attribut appelé "CourseChange". Tu peux
voir cela en regardant le code source dans src/mobilité/model/mobility-model.cc et votre
rechercher "CourseChange" dans votre éditeur préféré. Vous devriez trouver

.AddTraceSource ("Changement de parcours",
"La valeur du vecteur position et/ou vitesse a changé",
MakeTraceSourceAccessor (&MobilityModel::m_courseChangeTrace),
"ns3::MobilityModel::CourseChangeCallback")

qui devrait sembler très familier à ce stade.

Si vous recherchez la déclaration correspondante de la variable tracée sous-jacente dans
modèle-de-mobilité.h vous trouverez

Rappel tracé > m_courseChangeTrace ;

La déclaration de type Rappel tracé identifie m_courseChangeTrace sous la forme d'une liste spéciale de
Callbacks pouvant être accrochés à l'aide des fonctions de configuration décrites ci-dessus. La typedef pour
la signature de la fonction de rappel est également définie dans le fichier d'en-tête :

typedef void (* CourseChangeCallback)(Ptr * maquette);

Notre MobilitéModèle est conçue pour être une classe de base fournissant une interface commune pour
toutes les sous-classes spécifiques. Si vous recherchez jusqu'à la fin du fichier, vous verrez un
méthode définie appelée NotifyCourseChange():

annuler
MobilityModel :: NotifyCourseChange (void) const
{
m_courseChangeTrace(this);
}

Les classes dérivées appelleront cette méthode chaque fois qu'elles effectueront un changement de cours pour prendre en charge
tracé. Cette méthode invoque opérateur() sur le sous-jacent m_courseChangeTrace, Qui
invoquera à son tour tous les rappels enregistrés, appelant tous les puits de trace qui
ont manifesté leur intérêt pour la source de trace en appelant une fonction Config.

Donc, dans le troisième.cc exemple que nous avons examiné, chaque fois qu'un changement de cap est effectué dans l'un des
RandomWalk2dMobilityModèle instances installées, il y aura un NotifyCourseChange() Appelez-nous
qui appelle dans le MobilitéModèle classe de base. Comme on l'a vu plus haut, cela invoque opérateur()
on m_courseChangeTrace, qui à son tour appelle tous les récepteurs de trace enregistrés. Dans l'exemple,
le seul code enregistrant un intérêt était le code qui fournissait le chemin de configuration.
Par conséquent, la Changement de cours fonction qui a été accrochée au nœud numéro sept sera la
seul rappel appelé.

La dernière pièce du puzzle est le "contexte". Rappelez-vous que nous avons vu une sortie à la recherche
quelque chose comme ce qui suit de troisième.cc:

/NodeList/7/$ns3::MobilityModel/CourseChange x = 7.27897, y =
2.22677

La première partie de la sortie est le contexte. C'est simplement le chemin par lequel
Le code de configuration a localisé la source de la trace. Dans le cas que nous avons examiné, il peut y avoir
n'importe quel nombre de sources de trace dans le système correspondant à n'importe quel nombre de nœuds avec
modèles de mobilité. Il doit y avoir un moyen d'identifier quelle source de trace est réellement
celui qui a déclenché le rappel. Le moyen le plus simple est de se connecter avec Config :: Connecter, plutôt
of Config :: ConnectWithoutContext.

Trouver Sources
La première question qui se pose inévitablement aux nouveaux utilisateurs du système Tracing est la suivante : "D'accord,
I savoir qui doit be tracer sources in le simulation noyau, mais how do I trouver ande est ce que nous faisons
tracer sources are disponibles à moi?"

La deuxième question est, "D'accord, I trouvé a tracer la source, how do I comprendre ande le Config chemin
à utilisé quand I Contact à ce?"

La troisième question est, "D'accord, I trouvé a tracer source et votre le Config chemin, how do I comprendre
ande est ce que nous faisons le retourner type et votre formel arguments of my rappeler fonction need à être?"

La quatrième question est, "D'accord, I tapé qui tous in et votre eu ceci. incroyablement bizarre erreur
message, est ce que nous faisons in le world it moyenne?"

Nous aborderons chacune de ces questions à tour de rôle.

Disponible Sources
D'accord, I savoir qui doit be tracer sources in le simulation noyau, mais how do I trouver
ande est ce que nous faisons tracer sources are disponibles à moi?

La réponse à la première question se trouve dans ns-3 Documentation API. Si vous allez au
site internet du projet, ns-3 Projet, vous trouverez un lien vers "Documentation" dans la navigation
bar. Si vous sélectionnez ce lien, vous serez redirigé vers notre page de documentation. Il y a un
lien vers "Dernière version" qui vous mènera à la documentation de la dernière version stable
libération de ns-3. Si vous sélectionnez le lien "Documentation API", vous serez redirigé vers la
ns-3 Page de documentation de l'API.

Dans la barre latérale, vous devriez voir une hiérarchie qui commence

· ns-3

· Documentation ns-3

· Toutes les TraceSources

· Tous les attributs

· Toutes les valeurs globales

La liste qui nous intéresse ici est "Toutes les TraceSources". Allez-y et sélectionnez ce lien.
Vous verrez, peut-être pas trop surprenant, une liste de toutes les sources de traces disponibles
in ns-3.

Par exemple, faites défiler jusqu'à ns3::MobilityModèle. Vous trouverez une entrée pour

CourseChange : la valeur du vecteur de position et/ou de vitesse a changé

Vous devez reconnaître cela comme la source de trace que nous avons utilisée dans le troisième.cc Exemple. Lire attentivement
cette liste vous sera utile.

Config Chemins
D'accord, I trouvé a tracer la source, how do I comprendre ande le Config chemin à utilisé quand I Contact à
il?

Si vous savez quel objet vous intéresse, la section "Description détaillée" de la
class listera toutes les sources de trace disponibles. Par exemple, à partir de la liste "Tous
TraceSources", cliquez sur le ns3::MobilityModèle lien, qui vous mènera au
documentation pour le MobilitéModèle classer. Presque en haut de la page se trouve une ligne
brève description de la classe, se terminant par un lien "Plus...". Cliquez sur ce lien pour sauter
le récapitulatif de l'API et rendez-vous dans la "Description détaillée" de la classe. À la fin de
description sera (jusqu'à) trois listes :

· Config Chemins: une liste de chemins de configuration typiques pour cette classe.

· Attributs: une liste de tous les attributs fournis par cette classe.

· TraceSources: une liste de toutes les TraceSources disponibles à partir de cette classe.

Nous allons d'abord discuter des chemins de configuration.

Supposons que vous venez de trouver la source de trace "CourseChange" dans le dossier "All
TraceSources" et vous voulez comprendre comment vous y connecter. Vous savez que vous êtes
en utilisant (encore une fois, à partir du troisième.cc exemple) un ns3 ::RandomWalk2dMobilityModel. Donc soit
cliquez sur le nom de la classe dans la liste "Toutes les TraceSources", ou recherchez
ns3 ::RandomWalk2dMobilityModel dans la "Liste des classes". Quoi qu'il en soit, vous devriez maintenant chercher
sur la page "ns3::RandomWalk2dMobilityModel Class Reference".

Si vous descendez maintenant jusqu'à la section "Description détaillée", après la liste récapitulative des
méthodes et attributs de classe (ou cliquez simplement sur le lien "Plus..." à la fin de la classe
brève description en haut de la page) vous verrez la documentation globale pour le
classer. En continuant à faire défiler vers le bas, trouvez la liste "Chemins de configuration":
Config Chemins

ns3 ::RandomWalk2dMobilityModel est accessible par les chemins suivants avec
Configuration :: Définir et votre Config :: Connecter:

· "/NodeList/[i]/$ns3::MobilityModel/$ns3::RandomWalk2dMobilityModel"

La documentation vous indique comment accéder au RandomWalk2dMobilityModèle Objet. Comparer
la chaîne ci-dessus avec la chaîne que nous avons réellement utilisée dans l'exemple de code :

"/NodeList/7/$ns3::MobilityModel"

La différence est due au fait que deux Getobject les appels sont implicites dans la chaîne trouvée
dans la documentation. Le premier, pour $ns3 ::Modèle de mobilité interrogera l'agrégation pour
la classe de base. La seconde sous-entend Getobject demander $ns3 ::RandomWalk2dMobilityModel,
est utilisé pour convertir la classe de base en classe d'implémentation concrète. La documentation
montre ces deux opérations pour vous. Il s'avère que la source de trace réelle que vous êtes
recherche se trouve dans la classe de base.

Regardez plus bas dans la section "Description détaillée" pour la liste des sources de trace.
Tu trouveras
Aucune TraceSource n'est définie pour ce type.

TraceSources défini in mère classe ``ns3::MobilityModel``

· Changement de cours: La valeur du vecteur position et/ou vitesse a changé.

Signature de rappel : ns3 :: MobilityModel :: CourseChangeCallback

C'est exactement ce que vous devez savoir. La trace de la source d'intérêt se trouve dans
ns3::MobilityModèle (ce que vous saviez de toute façon). La chose intéressante ce morceau d'API
La documentation vous indique que vous n'avez pas besoin de cette distribution supplémentaire dans le chemin de configuration ci-dessus pour
accéder à la classe concrète, puisque la source de la trace se trouve en fait dans la classe de base.
Par conséquent le supplément Getobject n'est pas obligatoire et vous utilisez simplement le chemin :

"/NodeList/[i]/$ns3::MobilityModel"

qui correspond parfaitement à l'exemple de chemin :

"/NodeList/7/$ns3::MobilityModel"

Soit dit en passant, une autre façon de trouver le chemin de configuration consiste à grep autour dans le ns-3 base de code
pour quelqu'un qui a déjà compris. Vous devriez toujours essayer de copier quelqu'un d'autre
code de travail avant de commencer à écrire le vôtre. Essayez quelque chose comme :

$ trouver . -nom '*.cc' | xargs grep CourseChange | grep Se connecter

et vous pouvez trouver votre réponse avec le code de travail. Par exemple, dans ce cas,
src/mobility/examples/main-random-topology.cc a quelque chose qui n'attend que vous pour l'utiliser :

Config::Connect ("/NodeList/*/$ns3::MobilityModel/CourseChange",
MakeCallback (&CourseChange) );

Nous reviendrons sur cet exemple dans un instant.

Rappel Signatures
D'accord, I trouvé a tracer source et votre le Config chemin, how do I comprendre ande est ce que nous faisons le retourner type
et votre formel arguments of my rappeler fonction need à être?

Le moyen le plus simple consiste à examiner la signature de rappel typedef, qui est donné dans le
"Signature de rappel" de la source de trace dans la "Description détaillée" de la classe, comme
montré ci-dessus.

Répétition de l'entrée de la source de trace "CourseChange" à partir de ns3 ::RandomWalk2dMobilityModel we
avoir:

· Changement de cours: La valeur du vecteur position et/ou vitesse a changé.

Signature de rappel : ns3 :: MobilityModel :: CourseChangeCallback

La signature de rappel est donnée sous forme de lien vers le typedef, où l'on trouve
typedef annuler (* CourseChangeCallback)(const std :: string le contexte, Ptr
Modèle de mobilité> * maquette);

Rappel tracé signature pour les notifications de changement de cours.

Si le rappel est connecté à l'aide de ConnexionSansContexte omettre le aux contextes argument de
la signature.

Paramètres:
[dans] contexte La chaîne de contexte fournie par la source Trace.
[in] model Le MobilityModel qui change de cap.

Comme ci-dessus, pour voir cela en cours d'utilisation grep autour dans le ns-3 base de code pour un exemple. L'exemple
ci-dessus, de src/mobility/examples/main-random-topology.cc, relie le "CourseChange"
tracer la source jusqu'au Changement de cours fonction dans le même fichier :

vide statique
CourseChange (std :: contexte de chaîne, Ptr maquette)
{

}

Notez que cette fonction :

· Prend un argument de chaîne de "contexte", que nous décrirons dans une minute. (Si le rappel
est connecté à l'aide du ConnexionSansContexte fonction le aux contextes l'argument sera
omis.)

· A la MobilitéModèle fourni comme dernier argument (ou seul argument si
ConnexionSansContexte est utilisé).

· Retour annuler.

Si, par hasard, la signature de rappel n'a pas été documentée et qu'il n'y a pas d'exemples à
travailler à partir de, déterminer la bonne signature de fonction de rappel peut être, eh bien, difficile à
réellement comprendre à partir du code source.

Avant de me lancer dans une procédure pas à pas du code, je vais être gentil et vous dire juste un moyen simple
pour comprendre ceci : la valeur de retour de votre rappel sera toujours annuler. Le formel
liste de paramètres pour un Rappel tracé peut être trouvé à partir de la liste des paramètres de modèle dans le
déclaration. Rappelons que pour notre exemple actuel, c'est dans modèle-de-mobilité.h, où nous
ont déjà trouvé :

Rappel tracé > m_courseChangeTrace ;

Il existe une correspondance un à un entre la liste des paramètres du modèle dans le
déclaration et les arguments formels de la fonction de rappel. Ici, il y en a un
paramètre de modèle, qui est un Ptr Modèle de mobilité>. Cela vous indique que vous avez besoin d'un
fonction qui renvoie void et prend un Ptr Modèle de mobilité>. Par exemple:

annuler
CourseChange (Ptr maquette)
{

}

C'est tout ce dont tu as besoin si tu veux Config :: ConnectWithoutContext. Si vous voulez un contexte,
vous pouvez Config :: Connecter et utilisez une fonction de rappel qui prend un contexte de chaîne, puis
les arguments du modèle :

annuler
CourseChange (const std :: contexte de chaîne, Ptr maquette)
{

}

Si vous voulez vous assurer que votre CourseChangeCallback fonction n'est visible que dans votre
fichier local, vous pouvez ajouter le mot clé statique et venez avec:

vide statique
CourseChange (const std::string path, Ptr maquette)
{

}

c'est exactement ce que nous avons utilisé dans le troisième.cc Exemple.

Implantation
Cette section est entièrement facultative. Le parcours sera cahoteux, surtout pour ceux
pas familier avec les détails des modèles. Cependant, si vous réussissez, vous aurez
une très bonne prise en main sur beaucoup de ns-3 idiomes de bas niveau.

Donc, encore une fois, déterminons quelle signature de fonction de rappel est requise pour le
Source de trace « CourseChange ». Cela va être douloureux, mais vous n'avez qu'à le faire
une fois que. Après avoir traversé cela, vous pourrez simplement regarder un Rappel tracé et votre
le comprendre.

La première chose que nous devons regarder est la déclaration de la source de la trace. Rappeler que
c'est dans modèle-de-mobilité.h, où nous avons précédemment trouvé :

Rappel tracé > m_courseChangeTrace ;

Cette déclaration est pour un modèle. Le paramètre de modèle est à l'intérieur des crochets angulaires,
donc nous sommes vraiment intéressés à savoir ce que cela Rappel tracé<> est. Si tu as
absolument aucune idée d'où cela pourrait être trouvé, grep est votre ami.

Nous allons probablement être intéressés par une sorte de déclaration dans le ns-3 source, donc
premier changement dans le src annuaire. Ensuite, nous savons que cette déclaration devra
être dans une sorte de fichier d'en-tête, donc juste grep pour cela en utilisant:

$ trouver . -nom '*.h' | xargs grep TracedCallback

Vous verrez passer 303 lignes (j'ai passé ça à travers wc pour voir à quel point c'était mauvais). Bien que
cela peut sembler beaucoup, ce n'est pas vraiment beaucoup. Il suffit de diriger la sortie à travers plus et votre
commencez à le parcourir. Sur la première page, vous verrez quelques-unes très suspectes
des trucs qui ressemblent à des modèles.

TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::TracedCallback ()
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::ConnectWithoutContext (c ...
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::Connect (const CallbackB ...
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::DisconnectWithoutContext ...
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::Disconnect (const Callba ...
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (void) const ...
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1) const ...
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1, T2 a2 ...
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1, T2 a2 ...
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1, T2 a2 ...
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1, T2 a2 ...
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1, T2 a2 ...
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1, T2 a2 ...

Il s'avère que tout cela vient du fichier d'en-tête suivi-callback.h qui sonne
très prometteur. Vous pouvez alors jeter un œil à modèle-de-mobilité.h et voir qu'il y a une ligne
ce qui confirme cette intuition :

#include "ns3/traced-callback.h"

Bien sûr, vous auriez pu aller dans l'autre sens et commencer par regarder
les inclut dans modèle-de-mobilité.h et remarquant l'inclusion de suivi-callback.h et votre
en déduisant que ce doit être le fichier que vous voulez.

Dans les deux cas, la prochaine étape consiste à examiner src/core/model/traced-callback.h in
votre éditeur préféré pour voir ce qui se passe.

Vous verrez un commentaire en haut du fichier qui devrait être réconfortant :
Un ns3::TracedCallback a presque exactement la même API qu'un ns3::Callback normal mais
au lieu de transférer les appels vers une seule fonction (comme le fait normalement un ns3 :: Callback),
il transfère les appels vers une chaîne de ns3::Callback.

Cela devrait vous sembler très familier et vous faire savoir que vous êtes sur la bonne voie.

Juste après ce commentaire, vous trouverez

modèle
nom de type T3 = vide, nom de type T4 = vide,
nom de type T5 = vide, nom de type T6 = vide,
nom de type T7 = vide, nom de type T8 = vide>
classe TracedCallback
{


Cela vous indique que TracedCallback est une classe basée sur un modèle. Il a huit types possibles
paramètres avec des valeurs par défaut. Revenez en arrière et comparez cela avec la déclaration que vous faites
essayer de comprendre:

Rappel tracé > m_courseChangeTrace ;

Notre nom de type T1 dans la déclaration de classe modélisée correspond à la Ptr
Modèle de mobilité> dans la déclaration ci-dessus. Tous les autres paramètres de type sont laissés tels quels
par défaut. Regarder le constructeur ne vous dit pas grand-chose. Le seul endroit où
vous avez vu une connexion établie entre votre fonction Callback et le système de traçage est
dans le Connectez-vous et votre ConnexionSansContexte les fonctions. Si vous faites défiler vers le bas, vous verrez un
ConnexionSansContexte méthode ici :

modèle
nom de type T3, nom de type T4,
nom de type T5, nom de type T6,
nom de type T7, nom de type T8>
annuler
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::ConnectWithoutContext ...
{
Callback<void,T1,T2,T3,T4,T5,T6,T7,T8> cb;
cb.Assign (rappel);
m_callbackList.push_back (cb);
}

Vous êtes maintenant dans le ventre de la bête. Lorsque le modèle est instancié pour le
déclaration ci-dessus, le compilateur remplacera T1 avec Ptr Modèle de mobilité>.

annuler
Rappel tracé ::ConnexionSansContexte ... cb
{
Rappeler > CB ;
cb.Assign (rappel);
m_callbackList.push_back (cb);
}

Vous pouvez maintenant voir la mise en œuvre de tout ce dont nous avons parlé. Le code
crée un Callback du bon type et lui affecte votre fonction. C'est le
équivalent du Pfi = MaFonction nous avons discuté au début de cette section. Le code
ajoute ensuite le rappel à la liste des rappels pour cette source. La seule chose qui reste est
pour regarder la définition de Callback. En utilisant le même grep astuce comme nous avions l'habitude de trouver
Rappel tracé, vous pourrez constater que le fichier ./core/callback.h est celui que nous
besoin de regarder.

Si vous parcourez le fichier, vous verrez beaucoup de choses probablement presque incompréhensibles
code modèle. Vous finirez par arriver à une documentation API pour le rappel
classe de modèle, cependant. Heureusement, il y a un peu d'anglais :
Rappel classe modèle.

Ce modèle de classe implémente le Functor Design Pattern. Il est utilisé pour déclarer le
genre d'un Rappel:

· le premier argument de modèle non facultatif représente le type de retour du rappel.

· les arguments de modèle restants (facultatifs) représentent le type du modèle suivant
arguments au rappel.

· jusqu'à neuf arguments sont pris en charge.

Nous essayons de comprendre ce que

Rappeler > CB ;

moyens de déclaration. Nous sommes maintenant en mesure de comprendre que le premier (non facultatif)
argument de modèle, annuler, représente le type de retour du rappel. La deuxième
(facultatif) argument de modèle, Ptr Modèle de mobilité> représente le type du premier
argument au rappel.

Le Callback en question est votre fonction pour recevoir les événements de trace. A partir de cela, vous pouvez
en déduire que vous avez besoin d'une fonction qui renvoie annuler et prend un Ptr Modèle de mobilité>.
Par exemple,

annuler
CourseChangeCallback (Ptr maquette)
{

}

C'est tout ce dont tu as besoin si tu veux Config :: ConnectWithoutContext. Si vous voulez un contexte,
vous pouvez Config :: Connecter et utilisez une fonction de rappel qui prend un contexte de chaîne. Cette
est parce que le Connectez-vous fonction fournira le contexte pour vous. Tu auras besoin:

annuler
CourseChangeCallback (std :: contexte de chaîne, Ptr maquette)
{

}

Si vous voulez vous assurer que votre CourseChangeCallback n'est visible que dans votre fichier local,
vous pouvez ajouter le mot clé statique et venez avec:

vide statique
CourseChangeCallback (std :: chemin de la chaîne, Ptr maquette)
{

}

c'est exactement ce que nous avons utilisé dans le troisième.cc Exemple. Peut-être devriez-vous maintenant revenir en arrière et
relire la section précédente (Take My Word for It).

Si vous êtes intéressé par plus de détails concernant la mise en œuvre des rappels, n'hésitez pas
pour jeter un oeil à la ns-3 manuel. Il s'agit de l'une des constructions les plus utilisées dans
les parties de bas niveau de ns-3. C'est, à mon avis, une chose assez élégante.

ValeursTracées
Plus tôt dans cette section, nous avons présenté un simple morceau de code qui utilisait un
Valeur tracée pour démontrer les bases du code de traçage. nous venons de passer sous silence
ce qu'est vraiment une TracedValue et comment trouver le type de retour et les arguments formels pour
le rappel.

Comme nous l'avons mentionné, le fichier, valeur-tracée.h apporte les déclarations requises pour le traçage
de données qui obéissent à la sémantique des valeurs. En général, la sémantique des valeurs signifie simplement que vous pouvez
passer l'objet lui-même, plutôt que de passer l'adresse de l'objet. Nous prolongeons
cette exigence d'inclure l'ensemble complet d'opérateurs de style d'affectation qui sont
prédéfinis pour les types de données anciennes (POD) :

-
opérateur= (affectation) │ │
-
opérateur*=opérateur/=
-
opérateur+=opérateur-=
-
opérateur++ (préfixe et │ │
│suffixe) │ │
-
opérateur-- (préfixe et │ │
│suffixe) │ │
-
opérateur<<=opérateur>>=
-
opérateur&=opérateur|=
-
opérateur%=opérateur^=
└─────────────────────────────────┴───┘

Ce que tout cela signifie vraiment, c'est que vous pourrez suivre toutes les modifications apportées à l'aide de ces
opérateurs à un objet C++ qui a une sémantique de valeur.

Notre Valeur tracée<> déclaration que nous avons vue ci-dessus fournit l'infrastructure qui surcharge le
opérateurs mentionnés ci-dessus et pilote le processus de rappel. Lors de l'utilisation de l'un des opérateurs
dessus avec un Valeur tracée il fournira à la fois l'ancienne et la nouvelle valeur de cette variable,
dans ce cas un int32_t évaluer. Par l'inspection du Valeur tracée déclaration, nous connaissons la
la fonction de puits de trace aura des arguments (const int32_t ancienneValeur, const int32_t nouvelle valeur).
Le type de retour pour un Valeur tracée la fonction de rappel est toujours annuler, donc l'attendu
la signature de rappel sera :

void (* TracedValueCallback)(const int32_t oldValue, const int32_t newValue);

Notre .AddTraceSource dans le ObtenirTypeId méthode fournit les "crochets" utilisés pour connecter le
tracer la source vers le monde extérieur via le système Config. Nous avons déjà discuté de la
trois premiers accords à AjouterTraceSource: le nom de l'attribut pour le système de configuration, une aide
chaîne et l'adresse du membre de données de la classe TracedValue.

L'argument de chaîne final, "ns3::Traced::Value::Int32" dans l'exemple, est le nom d'un
typedef pour la signature de la fonction de rappel. Nous exigeons que ces signatures soient définies,
et donner le nom de type complet à AjouterTraceSource, afin que la documentation de l'API puisse
lier une source de trace à la signature de la fonction. Pour TracedValue la signature est
directe; pour TracedCallbacks, nous avons déjà vu la documentation de l'API vraiment utile.

Real Exemple
Faisons un exemple tiré d'un des livres les plus connus sur TCP. "TCP/IP
Illustrated, Volume 1: The Protocols ", de W. Richard Stevens est un classique. Je viens de retourner
le livre s'est ouvert et a traversé un joli tracé de la fenêtre de congestion et de la séquence
nombres en fonction du temps à la page 366. Stevens l'appelle "Figure 21.10. Valeur de cwnd et
envoyer le numéro de séquence pendant la transmission des données." Recréons simplement la partie cwnd
de cette parcelle dans ns-3 en utilisant le système de traçage et gnuplot.

Disponible Sources
La première chose à laquelle il faut réfléchir est de savoir comment nous voulons sortir les données. Qu'est-ce qu'on
besoin de tracer ? Consultons donc la liste "Toutes les sources de trace" pour voir sur quoi nous devons travailler
avec. Rappelons que cela se trouve dans ns-3 Documentation API. Si vous faites défiler le
liste, vous finirez par trouver :
ns3 :: TcpNouveauReno

· CongestionFenêtre: La fenêtre de congestion de la connexion TCP

· Seuil de démarrage lent: seuil de démarrage lent TCP (octets)

Il s'avère que le ns-3 L'implémentation TCP vit (principalement) dans le fichier
src/internet/model/tcp-socket-base.cc tandis que les variantes de contrôle de congestion sont dans des fichiers tels
as src/internet/model/tcp-newreno.cc. Si vous ne savez pas cela a à priori, vous pouvez utiliser le
récursif grep tour:

$ trouver . -nom '*.cc' | xargs grep -i tcp

Vous trouverez page après page des instances de tcp vous dirigeant vers ce fichier.

Apporter la documentation de classe pour TcpNouveauReno et passer à la liste des
TraceSources vous trouverez
TraceSources

· CongestionFenêtre: La fenêtre de congestion de la connexion TCP

Signature de rappel : ns3::Tracé::Valeur::Uint322Callback

Cliquer sur le rappel typedef lien, nous voyons la signature que vous savez maintenant attendre :

typedef void(* ns3::Traced::Value::Int32Callback)(const int32_t oldValue, const int32_t newValue)

Vous devriez maintenant comprendre complètement ce code. Si nous avons un pointeur vers le TcpNouveauReno,
nous pouvons TraceConnect à la source de trace "CongestionWindow" si nous fournissons un
cible de rappel. C'est le même type de source de trace que nous avons vu dans l'exemple simple
au début de cette section, sauf que nous parlons de uint32_t au lieu de
int32_t. Et nous savons que nous devons fournir une fonction de rappel avec cette signature.

Trouver Exemples
Il est toujours préférable d'essayer de trouver du code fonctionnel que vous pouvez modifier, plutôt
que de repartir de zéro. Donc, la première chose à faire maintenant est de trouver un code qui
accroche déjà la source de trace "CongestionWindow" et voyons si nous pouvons la modifier. Comme d'habitude,
grep est votre ami:

$ trouver . -nom '*.cc' | xargs grep CongestionWindow

Cela mettra en évidence quelques candidats prometteurs: exemples/tcp/tcp-large-transfer.cc
et votre src/test/ns3tcp/ns3tcp-cwnd-test-suite.cc.

Nous n'avons encore visité aucun code de test, alors jetons-y un coup d'œil. Vous serez
trouvent généralement que le code de test est assez minime, c'est donc probablement un très bon pari.
Ouvert src/test/ns3tcp/ns3tcp-cwnd-test-suite.cc dans votre éditeur préféré et recherchez
"Fenêtre Congestion". Tu trouveras,

ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow",
MakeCallback (&Ns3TcpCwndTestCase1 ::CwndChange, this) );

Cela devrait vous sembler très familier. Nous avons mentionné ci-dessus que si nous avions un pointeur vers le
TcpNouveauReno, nous pourrions TraceConnect à la source de trace "CongestionWindow". C'est exactement
ce que nous avons ici; il s'avère donc que cette ligne de code fait exactement ce que nous voulons.
Allons-y et extrayons le code dont nous avons besoin de cette fonction (Ns3TcpCwndTestCase1 ::DoRun
(vide)). Si vous regardez cette fonction, vous constaterez qu'elle ressemble à un ns-3
scénario. Il s'avère que c'est exactement ce que c'est. C'est un script exécuté par le test
cadre, afin que nous puissions simplement le retirer et l'envelopper dans principal au lieu de dans Exécuter. Plutôt
que de parcourir cela, étape par étape, nous avons fourni le fichier résultant du portage
ce test revient à un natif ns-3 scénario -- exemples/tutoriel/cinquième.cc.

Dynamique Tracer Sources
Notre cinquième.cc exemple démontre une règle extrêmement importante que vous devez comprendre
avant d'utiliser tout type de source de trace : vous devez vous assurer que la cible d'un
Config :: Connecter commande existe avant d'essayer de l'utiliser. Ce n'est pas différent de dire
un objet doit être instancié avant d'essayer de l'appeler. Bien que cela puisse sembler évident
lorsqu'il est indiqué de cette façon, cela fait trébucher de nombreuses personnes essayant d'utiliser le système pour la première fois
le temps.

Revenons un instant aux fondamentaux. Trois phases d'exécution de base existent dans
tout ns-3 scénario. La première phase est parfois appelée "Temps de configuration" ou "Configuration
Time" et existe pendant la période où le principal fonction de votre script est en cours d'exécution, mais
avant Simulateur :: Exécuter est appelé. La deuxième phase est parfois appelée "Temps de simulation"
et existe pendant la période où Simulateur :: Exécuter organise activement ses événements.
Après avoir terminé l'exécution de la simulation, Simulateur :: Exécuter rendra le contrôle à
le principal fonction. Lorsque cela se produit, le script entre dans ce que l'on peut appeler le "Teardown
Phase", qui correspond au moment où les structures et les objets créés lors de l'installation sont démontés et
libéré.

L'erreur peut-être la plus courante commise en essayant d'utiliser le système de traçage est de supposer que
entités construites dynamiquement pendant simulation fois sont disponibles lors de la configuration
temps. En particulier, un ns-3 Douille est un objet dynamique souvent créé par Applications à
communiquer entre Nodes. Un ns-3 Application a toujours une "Heure de début" et une "Heure d'arrêt"
Temps » qui lui est associé. Dans la grande majorité des cas, un Application ne tentera pas
pour créer un objet dynamique jusqu'à sa Lancer l'application méthode est appelée à certains "Start
Time". Ceci permet de s'assurer que la simulation est complètement configurée avant que l'application
essaie de faire quoi que ce soit (que se passerait-il s'il essayait de se connecter à un nœud qui n'existait pas
encore pendant le temps de configuration ?). Par conséquent, pendant la phase de configuration, vous ne pouvez pas
connecter une source de trace à un récepteur de trace si l'un d'eux est créé dynamiquement lors de la
simulation.

Les deux solutions à ce connundrum sont

1. Créez un événement de simulateur qui est exécuté après la création de l'objet dynamique et accrochez le
trace quand cet événement est exécuté ; ou

2. Créez l'objet dynamique au moment de la configuration, accrochez-le ensuite et donnez l'objet à
le système à utiliser pendant le temps de simulation.

Nous avons adopté la deuxième approche dans le cinquième.cc Exemple. Cette décision nous a obligés à créer
le MyApp Application, dont le seul but est de prendre une Douille en tant que paramètre

Procédure pas à pas: cinquième.cc
Maintenant, regardons l'exemple de programme que nous avons construit en disséquant la congestion
essai de fenêtre. Ouvert exemples/tutoriel/cinquième.cc dans votre éditeur préféré. Tu devrais voir
un code familier:

/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Ce programme est un logiciel gratuit ; vous pouvez le redistribuer et/ou modifier
* sous les termes de la licence publique générale GNU version 2 comme
* publié par la Free Software Foundation ;
*
* Ce programme est distribué dans l'espoir qu'il vous sera utile,
* mais SANS AUCUNE GARANTIE ; sans même la garantie implicite de
* QUALITÉ MARCHANDE ou ADAPTATION À UN USAGE PARTICULIER. Voir le
* Licence publique générale GNU pour plus de détails.
*
* Vous devriez avoir reçu une copie de la licence publique générale GNU
* avec ce programme; sinon, écrivez au Logiciel Libre
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 États-Unis
*/

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

en utilisant l'espace de noms ns3 ;

NS_LOG_COMPONENT_DEFINE ("Cinquième exemple de script");

Tout cela a été couvert, nous ne le ressasserons donc pas. Les prochaines lignes de source sont les
illustration du réseau et un commentaire traitant du problème décrit ci-dessus avec Douille.

// ================================================ ===========================
//
// nœud 0 nœud 1
// +----------------+ +----------------+
// | ns-3TCP | | ns-3TCP |
// +----------------+ +----------------+
// | 10.1.1.1 | | 10.1.1.2 |
// +----------------+ +----------------+
// | point à point | | point à point |
// +----------------+ +----------------+
// | |
// +-----------+
// 5 Mbit/s, 2 ms
//
//
// Nous voulons examiner les changements dans la fenêtre de congestion TCP ns-3. Nous avons besoin
// pour lancer un flux et accrocher l'attribut CongestionWindow sur le socket
// de l'expéditeur. Normalement, on utiliserait une application on-off pour générer un
// flux, mais cela pose quelques problèmes. Tout d'abord, la prise du marche-arrêt
// l'application n'est pas créée avant l'heure de début de l'application, nous ne serions donc pas
// capable d'accrocher le socket (maintenant) au moment de la configuration. Deuxièmement, même si nous
// pourrait organiser un appel après l'heure de début, le socket n'est pas public donc nous
// n'a pas pu y accéder.
//
// Ainsi, nous pouvons concocter une version simple de l'application on-off qui fait ce que
// nous voulons. Du côté positif, nous n'avons pas besoin de toute la complexité du marche-arrêt
// application. Du côté négatif, nous n'avons pas d'aide, nous devons donc obtenir
// un peu plus impliqué dans les détails, mais c'est trivial.
//
// Donc, d'abord, nous créons un socket et faisons la trace se connecter dessus ; puis on passe
// ce socket dans le constructeur de notre application simple que nous avons ensuite
// installe dans le nœud source.
// ================================================ ===========================
//

Cela devrait également être explicite.

La partie suivante est la déclaration du MyApp Application que nous avons mis ensemble pour permettre
le Douille à créer lors de la configuration.

classe MyApp : application publique
{
publique:

MonApp ();
virtuel ~MonApp();

annuler la configuration (Ptr socket, adresse adresse, uint32_t taillepaquet,
uint32_t nPackets, DataRate dataRate);

privé:
Virtual void StartApplication (void);
void virtuel StopApplication (void);

annuler ScheduleTx (annuler);
annuler SendPacket (annuler);

Ptr m_socket ;
Adresse m_peer ;
uint32_t m_packetSize ;
uint32_t m_nPackets ;
DataRate m_dataRate ;
ID d'événement m_sendEvent ;
booléen m_running;
uint32_t m_packetsSent ;
};

Vous pouvez voir que cette classe hérite de la ns-3 Application classer. Jeter un coup d'œil à
src/réseau/modèle/application.h si vous êtes intéressé par ce qui est hérité. La MyApp
la classe est obligée de remplacer la Lancer l'application et votre ArrêterApplication méthodes. Ces
les méthodes sont automatiquement appelées lorsque MyApp est nécessaire pour démarrer et arrêter l'envoi de données
pendant la simulation.

Démarrage/Arrêt Applications
Il vaut la peine de passer un peu de temps à expliquer comment les événements commencent réellement dans le
système. Ceci est une autre explication assez profonde, et peut être ignorée si vous n'êtes pas
l'intention de s'aventurer dans les entrailles du système. Il est cependant utile en ce sens
la discussion porte sur la façon dont certaines parties très importantes de ns-3 travail et expose certains
idiomes importants. Si vous envisagez de mettre en œuvre de nouveaux modèles, vous souhaitez probablement
comprendre cette section.

La manière la plus courante de démarrer des événements de pompage consiste à démarrer un Application. Cela se fait comme
le résultat des lignées familières suivantes (espérons-le) d'un ns-3 script:

Applications ApplicationContainer = ...
apps.Start (secondes (1.0));
apps.Stop (secondes (10.0));

Le code du conteneur d'application (voir src/network/helper/application-container.h si vous êtes
intéressé) parcourt ses applications et appels contenus,

app->SetStartTime (startTime);

à la suite de l' apps.Démarrer appeler et

app->SetStopTime (stopTime);

à la suite de l' apps.Stop appel.

Le résultat final de ces appels est que nous voulons avoir le simulateur automatiquement
passer des appels dans notre Applications pour leur dire quand commencer et s'arrêter. Dans le cas de
MyApp, il hérite de la classe Application et remplace Lancer l'application et
ArrêterApplication. Ce sont les fonctions qui seront appelées par le simulateur à la
temps voulu. Dans le cas de MyApp tu trouveras que MonApp ::DémarrerApplication
la première Lier et Connectez-vous sur le socket, puis commence le flux de données en appelant
MonApp ::SendPacket. MonApp ::StopApplication arrête de générer des paquets en annulant tout
les événements d'envoi en attente ferme alors le socket.

Une des belles choses à propos ns-3 est que vous pouvez complètement ignorer la mise en œuvre
des détails sur la façon dont votre Application est "automagiquement" appelé par le simulateur au bon moment
temps. Mais puisque nous nous sommes déjà aventurés profondément dans ns-3 déjà, allons-y.

Si vous regardez src/réseau/modèle/application.cc vous constaterez que le Définir l'heure de début méthode
d'un Application définit simplement la variable membre m_startTime et la Définir l'heure d'arrêt méthode
juste des ensembles m_stopTime. À partir de là, sans quelques indices, la piste se terminera probablement.

La clé pour reprendre la piste est de savoir qu'il existe une liste globale de tous les
nœuds dans le système. Chaque fois que vous créez un nœud dans une simulation, un pointeur vers ce nœud
est ajouté au global Liste de nœuds.

Jetez un oeil à src/réseau/modèle/node-list.cc et ensuite cherchez NodeList ::Ajouter. Le public
l'implémentation statique appelle une implémentation privée appelée NodeListPriv ::Ajouter. Ce
est un idiome relativement courant dans ns-3. Alors, jetez un œil à NodeListPriv ::Ajouter. Là tu
trouvera,

Simulator::ScheduleWithContext (index, TimeStep (0), &Node::Initialize, nœud);

Cela vous indique que chaque fois qu'un nœud est créé dans une simulation, comme effet secondaire, un appel
à ce nœud Initialiser méthode est prévue pour vous qui se produit au temps zéro. Ne le faites pas
lire trop dans ce nom, encore. Cela ne signifie pas que le nœud va commencer à faire
quoi que ce soit, cela peut être interprété comme un appel informatif au nœud lui indiquant que le
la simulation a commencé, pas un appel à l'action disant au nœud de commencer à faire quelque chose.

Alors, NodeList ::Ajouter planifie indirectement un appel vers Noeud :: Initialiser à l'instant zéro pour conseiller un
nouveau nœud que la simulation a commencé. Si vous regardez dans src/réseau/modèle/node.h vous
ne trouvera cependant pas de méthode appelée Noeud :: Initialiser. Il s'avère que le
Initialiser la méthode est héritée de la classe Objet. Tous les objets du système peuvent être
notifié lorsque la simulation démarre, et les objets de la classe Node ne sont qu'un type de ceux
objets.

Jetez un oeil à src/core/model/object.cc suivant et recherchez Objet :: Initialiser. Ce code
n'est pas aussi simple que vous auriez pu l'imaginer depuis ns-3 Objets Support
agrégation. Le code dans Objet :: Initialiser puis parcourt tous les objets qui
ont été agrégés et appellent leurs FaireInitialiser méthode. C'est un autre idiome
c'est très courant dans ns-3, parfois appelé "template design pattern." : un modèle public
méthode d'API non virtuelle, qui reste constante d'une implémentation à l'autre et qui appelle une
méthode d'implémentation virtuelle privée héritée et implémentée par les sous-classes.
Les noms sont généralement quelque chose comme Nom de la méthode pour l'API publique et NomMéthodeDo pour
l'API privée.

Cela nous dit que nous devrions chercher un Noeud :: DoInitialize méthode en
src/réseau/modèle/node.cc pour la méthode qui continuera notre chemin. Si vous localisez le
code, vous trouverez une méthode qui parcourt tous les appareils du nœud, puis
toutes les applications du nœud appelant périphérique->Initialiser et votre application->Initialiser
respectivement.

Vous savez peut-être déjà que les cours Appareil et votre Application les deux héritent de la classe Objet
et donc la prochaine étape sera de regarder ce qui se passe quand Application ::DoInitialize is
appelé. Jeter un coup d'œil à src/réseau/modèle/application.cc et vous trouverez :

annuler
Application ::DoInitialize (vide)
{
m_startEvent = Simulator::Schedule (m_startTime, &Application::StartApplication, this);
si (m_stopTime != TimeStep (0))
{
m_stopEvent = Simulator::Schedule (m_stopTime, &Application::StopApplication, this);
}
Objet :: DoInitialize ();
}

Ici, nous arrivons enfin au bout du sentier. Si vous avez tout gardé droit, quand vous
mettre en place une solution de ns-3 Application, votre nouvelle application hérite de la classe Application. Vous
remplacer le Lancer l'application et votre ArrêterApplication méthodes et fournir des mécanismes pour
démarrer et arrêter le flux de données sortant de votre nouveau Application. Lorsqu'un nœud est
créé dans la simulation, il est ajouté à un Liste de nœuds. Le fait d'ajouter un nœud à
ceci. Liste de nœuds provoque la planification d'un événement de simulateur pour le temps zéro qui appelle le
Noeud :: Initialiser méthode du nœud nouvellement ajouté à appeler lorsque la simulation démarre.
Puisqu'un nœud hérite de Objet, cela appelle le Objet :: Initialiser méthode sur le nœud
qui, à son tour, appelle le FaireInitialiser méthodes sur l'ensemble des Objets agrégé au
Node (pensez aux modèles de mobilité). Depuis le nœud Objet a outrepassé FaireInitialiser, Que
La méthode est appelée au démarrage de la simulation. La Noeud :: DoInitialize la méthode appelle le
Initialiser méthodes de tous les Applications sur le nœud. Depuis Applications sont également
Objets, ce qui provoque Application ::DoInitialize être appelé. Lorsque
Application ::DoInitialize est appelé, il planifie des événements pour le Lancer l'application et votre
ArrêterApplication invite le Application. Ces appels sont conçus pour démarrer et arrêter le
flux de données de la Application

Cela a été un autre voyage assez long, mais il ne faut le faire qu'une seule fois, et vous
comprendre un autre morceau très profond de ns-3.

Notre MyApp Application
Notre MyApp Application a besoin d'un constructeur et d'un destructeur, bien sûr:

MonApp ::MonApp ()
: m_socket (0),
m_peer (),
m_packetSize (0),
m_nPaquets (0),
m_dataRate (0),
m_sendEvent (),
m_running (faux),
m_paquetsEnvoyés (0)
{
}

MonApp ::~MonApp()
{
m_socket = 0 ;
}

L'existence du prochain bit de code est toute la raison pour laquelle nous avons écrit ceci Application in
la première place.

annuler
MonApp ::Configuration (Ptr socket, adresse adresse, uint32_t taillepaquet,
uint32_t nPackets, DataRate dataRate)
{
m_socket = socket ;
m_peer = adresse ;
m_packetSize = packetSize ;
m_nPaquets = nPaquets ;
m_dataRate = dataRate ;
}

Ce code devrait être assez explicite. Nous initialisons simplement les variables membres.
L'élément important du point de vue du traçage est le Ptr douille que nous
nécessaire de fournir à l'application pendant le temps de configuration. Rappelez-vous que nous allons
pour créer le Douille en tant que TcpSocket (qui est mis en œuvre par TcpNouveauReno) et accrochez-le
source de trace "CongestionWindow" avant de la transmettre au installation méthode.

annuler
MonApp ::StartApplication (vide)
{
m_running = vrai ;
m_paquets envoyés = 0 ;
m_socket->Lier ();
m_socket->Se connecter (m_peer);
EnvoyerPaquet ();
}

Le code ci-dessus est l'implémentation remplacée Application ::DémarrerApplication ce sera
automatiquement appelé par le simulateur pour lancer notre Application courir au bon moment
temps. Vous pouvez voir qu'il fait un Douille Lier opération. Si vous êtes familier avec
Berkeley Sockets cela ne devrait pas être une surprise. Il effectue les travaux requis sur le local
côté de la connexion, comme on pouvait s'y attendre. Ce qui suit Connectez-vous fera ce qui est
nécessaire pour établir une connexion avec le TCP à Adresse m_peer. Cela devrait maintenant être clair
pourquoi nous devons reporter une grande partie de cela au temps de simulation, puisque le Connectez-vous va avoir besoin
un réseau entièrement fonctionnel à compléter. Après le Connectez-vous, Application commence alors
création d'événements de simulation en appelant EnvoyerPaquet.

Le morceau de code suivant explique au Application comment arrêter de créer des événements de simulation.

annuler
MonApp ::StopApplication (vide)
{
m_running = faux ;

si (m_sendEvent.IsRunning ())
{
Simulateur :: Annuler (m_sendEvent);
}

si (m_socket)
{
m_socket->Fermer ();
}
}

Chaque fois qu'un événement de simulation est planifié, un événement est créé. Si la événement est en attente
exécution ou exécution, sa méthode Est en cours d'exécution reviendra oui. Dans ce code, si
Est en cours d'exécution() renvoie vrai, nous Annuler l'événement qui le supprime de l'événement du simulateur
file d'attente. Ce faisant, nous brisons la chaîne d'événements que le Application utilise pour garder
l'envoi de son Paquets et la Application se calme. Après avoir calmé le Application we
Fermer le socket qui détruit la connexion TCP.

La socket est en fait supprimée dans le destructeur lorsque le m_socket = 0 est exécuté. Cette
supprime la dernière référence au Ptr sous-jacent qui provoque le destructeur de
cet objet à appeler.

Rappeler que Lancer l'application appelé EnvoyerPaquet pour commencer la chaîne d'événements qui décrit
le Application comportement.

annuler
MonApp ::SendPacket (vide)
{
Ptr paquet = Créer (m_packetSize);
m_socket->Envoyer (paquet) ;

si (++m_paquets envoyés < m_npaquets)
{
PlanifierTx ();
}
}

Tiens, tu vois ça EnvoyerPaquet fait exactement cela. Il crée un Paquet puis fait un Envoyer
ce qui, si vous connaissez Berkeley Sockets, est probablement exactement ce que vous vous attendiez à voir.

Il est de la responsabilité du Application de continuer à programmer la chaîne d'événements, de sorte que le
appel des prochaines lignes PlanificationTx programmer un autre événement de transmission (un EnvoyerPaquet) jusqu'à ce que le
Application décide qu'il en a envoyé assez.

annuler
MonApp ::ScheduleTx (vide)
{
si (m_running)
{
Temps tNext (Secondes (m_packetSize * 8 / static_cast (m_dataRate.GetBitRate ())));
m_sendEvent = Simulator::Schedule (tNext, &MyApp::SendPacket, this);
}
}

Tiens, tu vois ça PlanificationTx fait exactement cela. Si la Application est en cours d'exécution (si
ArrêterApplication n'a pas été appelé), il planifiera un nouvel événement, qui appellera EnvoyerPaquet
encore. Le lecteur d'alerte repérera quelque chose qui déclenche également de nouveaux utilisateurs. Le débit de données
d'un Application est juste cela. Cela n'a rien à voir avec le débit de données d'un sous-jacent
Développement. C'est le taux auquel le Application produit des bits. Il ne prend pas en
tenir compte de toute surcharge pour les différents protocoles ou canaux qu'il utilise pour transporter le
Les données. Si vous réglez le débit de données d'un Application au même débit de données que votre sous-jacent
Développement vous obtiendrez éventuellement un débordement de tampon.

Tracer Éviers
Le but de cet exercice est d'obtenir des rappels de trace de TCP indiquant le
la fenêtre de congestion a été mise à jour. Le morceau de code suivant implémente le correspondant
puits de trace :

vide statique
CwndChange (uint32_t oldCwnd, uint32_t newCwnd)
{
NS_LOG_UNCOND (Simulator::Now ().GetSeconds () << "\t" << newCwnd);
}

Cela devrait vous être très familier maintenant, nous ne nous attarderons donc pas sur les détails. Cette fonction
enregistre simplement le temps de simulation actuel et la nouvelle valeur de la fenêtre de congestion chaque
fois qu'il est changé. Vous pouvez probablement imaginer que vous pourriez charger la sortie résultante
dans un programme graphique (gnuplot ou Excel) et voir immédiatement un joli graphique de la
comportement de la fenêtre de congestion dans le temps.

Nous avons ajouté un nouveau récepteur de trace pour montrer où les paquets sont déposés. Nous allons ajouter une erreur
modèle à ce code également, nous voulions donc démontrer ce fonctionnement.

vide statique
RxDrop (Ptr p)
{
NS_LOG_UNCOND ("RxDrop à " << Simulateur :: Maintenant ().GetSeconds ());
}

Ce puits de trace sera connecté à la source de trace "PhyRxDrop" du point à point
NetDevice. Cette source de trace se déclenche lorsqu'un paquet est rejeté par la couche physique d'un
NetDevice. Si vous faites un petit détour à la source
(src/point-à-point/model/point-à-point-net-device.cc) vous verrez que cette trace
la source fait référence à PointToPointNetDevice :: m_phyRxDropTrace. Si vous regardez ensuite dans
src/point-à-point/model/point-à-point-net-device.h pour cette variable de membre, vous
constater qu'il est déclaré comme un Rappel tracé Paquet> >. Cela devrait vous dire
que la cible de rappel doit être une fonction qui renvoie void et prend un seul
paramètre qui est un Ptr Paquet> (en supposant que nous utilisons ConnexionSansContexte) -- juste
ce que nous avons ci-dessus.

Entrée Programme
Le code suivant devrait vous être très familier maintenant :

int
principal (int argc, char *argv[])
{
nœuds NodeContainer ;
nœuds.Créer (2);

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

Périphériques NetDeviceContainer ;
devices = pointToPoint.Install (nœuds);

Cela crée deux nœuds avec un canal point à point entre eux, comme indiqué dans le
illustration en début de fichier.

Les quelques lignes de code suivantes montrent quelque chose de nouveau. Si nous traçons une connexion qui se comporte
parfaitement, nous nous retrouverons avec une fenêtre de congestion croissante de manière monotone. Pour voir n'importe
comportement intéressant, nous voulons vraiment introduire des erreurs de lien qui feront tomber des paquets,
provoquer des ACK en double et déclencher les comportements les plus intéressants de la fenêtre de congestion.

ns-3 fournit Modèle d'erreur objets qui peuvent être attachés à Canaux. Nous utilisons le
Modèle d'erreur de taux ce qui nous permet d'introduire des erreurs dans un Développement à un moment donné taux.

Ptr em = CréerObjet ();
em->SetAttribute ("ErrorRate", DoubleValue (0.00001));
devices.Get (1)->SetAttribute ("ReceiveErrorModel", PointerValue (em));

Le code ci-dessus instancie un Modèle d'erreur de taux Object, et nous définissons le "ErrorRate" Attribut
à la valeur souhaitée. Nous définissons ensuite l'instanciation résultante Modèle d'erreur de taux comme l'erreur
modèle utilisé par le point à point NetDevice. Cela nous donnera quelques retransmissions et
rendre notre intrigue un peu plus intéressante.

Pile InternetStackHelper ;
stack.Install (nœuds);

Adresse Ipv4AddressHelper ;
adresse.SetBase ("10.1.1.0", "255.255.255.252");
Ipv4InterfaceContainer interfaces = address.Assign (dispositifs);

Le code ci-dessus devrait être familier. Il installe des piles Internet sur nos deux nœuds et
crée des interfaces et attribue des adresses IP pour les périphériques point à point.

Puisque nous utilisons TCP, nous avons besoin de quelque chose sur le nœud de destination pour recevoir TCP
connexions et données. La Puits de paquets Application est couramment utilisé dans ns-3 pour que
objectif.

uint16_t sinkPort = 8080 ;
Adresse sinkAddress (InetSocketAddress(interfaces.GetAddress (1), sinkPort));
PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory",
InetSocketAddress (Ipv4Address ::GetAny(), sinkPort));
ApplicationContainer SinkApps = packetSinkHelper.Install (nodes.Get (1));
sinkApps.Start (Secondes (0.));
sinkApps.Stop (secondes (20.) );

Tout cela devrait être familier, à l'exception de,

PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory",
InetSocketAddress (Ipv4Address ::GetAny(), sinkPort));

Ce code instancie un PacketSinkHelperPacketSinkHelper et lui dit de créer des sockets en utilisant la classe
ns3 ::TcpSocketFactory. Cette classe implémente un design pattern appelé "object factory"
qui est un mécanisme couramment utilisé pour spécifier une classe utilisée pour créer des objets dans un
manière abstraite. Ici, au lieu d'avoir à créer les objets eux-mêmes, vous fournissez les
PacketSinkHelperPacketSinkHelper une chaîne qui spécifie un ID de type chaîne utilisée pour créer un objet qui
peuvent ensuite être utilisés, à leur tour, pour créer des instances des objets créés par la fabrique.

Le paramètre restant indique le Application quelle adresse et quel port il devrait Lier à.

Les deux lignes de code suivantes créeront le socket et connecteront la source de trace.

Ptr ns3TcpSocket = Socket ::CreateSocket (nodes.Get (0),
TcpSocketFactory ::GetTypeId ());
ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow",
MakeCallback (&CwndChange));

La première instruction appelle la fonction membre statique Socket ::CréerSocket et fournit un
Nœud et un explicite ID de type pour la fabrique d'objets utilisée pour créer le socket. C'est un
appel de niveau légèrement inférieur à celui PacketSinkHelperPacketSinkHelper appel ci-dessus, et utilise un C++ explicite
type au lieu de celui référencé par une chaîne. Sinon, c'est conceptuellement le même
chose.

Une fois que le TcpSocket est créé et attaché au nœud, nous pouvons utiliser
TraceConnexionSansContexte pour connecter la source de trace CongestionWindow à notre récepteur de trace.

Rappelons que nous avons codé un Application donc on pourrait prendre ça Douille nous venons de faire (pendant
temps de configuration) et l'utiliser en temps de simulation. Il faut maintenant instancier cela
Application. Nous ne nous sommes pas donné la peine de créer un assistant pour gérer le Application so
nous allons devoir le créer et l'installer "manuellement". C'est en fait assez facile:

Ptr app = CréerObjet ();
app->Configuration (ns3TcpSocket, sinkAddress, 1040, 1000, DataRate ("1Mbps"));
nodes.Get (0)->AddApplication (app);
app->Démarrer (Secondes (1.) );
app->Stop (Secondes (20.) );

La première ligne crée un Objet De type MyApp -- notre Application. La deuxième ligne indique
le Application est ce que nous faisons Douille utiliser, à quelle adresse se connecter, combien de données envoyer à
chaque événement d'envoi, le nombre d'événements d'envoi à générer et la fréquence à laquelle produire des données
de ces événements.

Ensuite, nous ajoutons manuellement le MyApp Application au nœud source et appeler explicitement le
Accueille et votre Arrêter méthodes sur le Application pour lui dire quand commencer et arrêter de faire son
chose.

Nous devons réellement faire la connexion du récepteur point à point NetDevice événement de dépôt
à notre RxDrop rappeler maintenant.

devices.Get (1)->TraceConnectWithoutContext("PhyRxDrop", MakeCallback (&RxDrop));

Il devrait maintenant être évident que nous obtenons une référence à la réception Nœud NetDevice
de son conteneur et en connectant la source de trace définie par l'attribut "PhyRxDrop" sur
cet appareil au puits de trace RxDrop.

Enfin, nous disons au simulateur de remplacer tout Applications et arrêtez simplement le traitement
événements à 20 secondes dans la simulation.

Simulateur ::Arrêter (Sec(20));
Simulateur::Exécuter ();
Simulateur :: Détruire ();

0 revenir;
}

Rappelons que dès que Simulateur :: Exécuter est appelé, le temps de configuration se termine et la simulation
le temps commence. Tout le travail que nous avons orchestré en créant le Application et l'enseigner
comment se connecter et envoyer des données se produit réellement pendant cet appel de fonction.

Aussitôt que Simulateur :: Exécuter revient, la simulation est terminée et nous entrons dans le démontage
phase. Dans ce cas, Simulateur :: Détruire s'occupe des détails sanglants et nous revenons juste
un code de réussite une fois terminé.

Fonctionnement cinquième.cc
Puisque nous avons fourni le fichier cinquième.cc pour vous, si vous avez construit votre distribution (en
mode débogage puisqu'il utilise NS_LOG -- rappelez-vous que les builds optimisés optimisent NS_LOG) il
vous attendra pour courir.

$ ./waf --run cinquième
Waf : Entrer dans le répertoire `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build'
Waf : quitter le répertoire `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build'
'build' terminé avec succès (0.684s)
1 536
1.0093 1072
1.01528 1608
1.02167 2144

1.11319 8040
1.12151 8576
1.12983 9112
RxDrop à 1.13696


Vous pouvez probablement voir immédiatement un inconvénient à utiliser des impressions de toutes sortes dans vos traces.
Nous obtenons ces messages waf superflus imprimés partout dans nos informations intéressantes le long
avec ces messages RxDrop. Nous y remédierons bientôt, mais je suis sûr que vous avez hâte de voir
les résultats de tout ce travail. Redirigeons cette sortie vers un fichier appelé cwnd.dat:

$ ./waf --run cinquième > cwnd.dat 2>&1

Maintenant, éditez "cwnd.dat" dans votre éditeur préféré et supprimez le statut de construction waf et déposez
lignes, ne laissant que les données tracées (vous pouvez également commenter les
TraceConnectWithoutContext("PhyRxDrop", FaireRappel (&RxDrop)); dans le script pour se débarrasser
de la goutte s'imprime tout aussi facilement.

Vous pouvez maintenant exécuter gnuplot (si vous l'avez installé) et lui dire de générer de jolis
des photos:

$gnuplot
gnuplot> définir la taille du terminal png 640,480 XNUMX
gnuplot> définir la sortie "cwnd.png"
gnuplot> tracer "cwnd.dat" en utilisant le titre 1: 2 "Congestion Window" avec des points de ligne
gnuplot> quitter

Vous devriez maintenant avoir un graphique de la fenêtre de congestion en fonction du temps restant dans le fichier
"cwnd.png" loading="lazy" qui ressemble à :
[image]

En utilisant Niveau moyen assistants
Dans la section précédente, nous avons montré comment accrocher une source de trace et obtenir, espérons-le,
informations intéressantes issues d'une simulation. Peut-être vous souviendrez-vous que nous avons appelé
se connecter à la sortie standard à l'aide de std :: cout un "instrument contondant" beaucoup plus tôt dans ce
chapitre. Nous avons également écrit sur le problème d'analyser la sortie du journal dans l'ordre
pour isoler des informations intéressantes. Il vous est peut-être venu à l'esprit que nous venons de dépenser beaucoup
de temps à mettre en œuvre un exemple qui présente tous les problèmes que nous prétendons résoudre avec
le ns-3 système de traçage ! Vous auriez raison. Mais, supportez-nous. Nous n'avons pas encore fini.

L'une des choses les plus importantes que nous voulons faire est d'avoir la capacité de facilement
contrôler la quantité de sortie sortant de la simulation ; et nous voulons aussi sauver ceux
données dans un fichier afin que nous puissions nous y référer plus tard. Nous pouvons utiliser les assistants de trace de niveau intermédiaire
Fourni dans ns-3 pour faire exactement cela et compléter le tableau.

Nous fournissons un script qui écrit les événements cwnd change et drop développés dans l'exemple
cinquième.cc sur disque dans des fichiers séparés. Les modifications cwnd sont stockées sous forme d'ASCII séparés par des tabulations
fichier et les événements de dépôt sont stockés dans un fichier PCAP. Les changements pour que cela se produise sont
plutôt petit.

Procédure pas à pas: sixième.cc
Examinons les changements nécessaires pour passer de cinquième.cc à sixième.cc. Ouvert
exemples/tutoriel/sixième.cc dans votre éditeur préféré. Vous pouvez voir le premier changement en
recherche de CwndChange. Vous constaterez que nous avons changé les signatures pour la trace
récepteurs et ont ajouté une seule ligne à chaque récepteur qui écrit les informations tracées dans un
flux représentant un fichier.

vide statique
CwndChange (Ptr flux, uint32_t oldCwnd, uint32_t newCwnd)
{
NS_LOG_UNCOND (Simulator::Now ().GetSeconds () << "\t" << newCwnd);
*stream->GetStream () << Simulator::Now ().GetSeconds () << "\t" << oldCwnd << "\t" << newCwnd << std ::endl;
}

vide statique
RxDrop (Ptr fichier, Ptr p)
{
NS_LOG_UNCOND ("RxDrop à " << Simulateur :: Maintenant ().GetSeconds ());
file->Write(Simulator::Now(), p);
}

Nous avons ajouté un paramètre "stream" au CwndChange évier de trace. C'est un objet qui
contient (maintient en vie en toute sécurité) un flux de sortie C++. Il s'avère que c'est très simple
objet, mais qui gère les problèmes de durée de vie du flux et résout un problème que même
les utilisateurs expérimentés de C++ rencontrent. Il s'avère que le constructeur de copie pour std :: ostream
est marqué privé. Cela signifie que std :: ostreams n'obéissent pas à la sémantique des valeurs et ne peuvent pas
être utilisé dans tout mécanisme nécessitant la copie du flux. Cela inclut le ns-3
système de rappel, qui, comme vous vous en souvenez peut-être, nécessite des objets qui obéissent à la sémantique des valeurs.
Notez également que nous avons ajouté la ligne suivante dans le CwndChange évier de trace
la mise en oeuvre:

*stream->GetStream () << Simulator::Now ().GetSeconds () << "\t" << oldCwnd << "\t" << newCwnd << std ::endl;

Ce serait un code très familier si vous remplaciez *stream->GetStream () avec std :: cout, comme
dans:

std::cout << Simulator::Now ().GetSeconds () << "\t" << oldCwnd << "\t" << newCwnd << std::endl;

Ceci illustre que le Ptr est vraiment juste de transporter un
std::offstream pour vous, et vous pouvez l'utiliser ici comme n'importe quel autre flux de sortie.

Une situation similaire se produit dans RxDrop sauf que l'objet qui circule (un
Ptr) représente un fichier PCAP. Il y a une doublure dans l'évier de trace pour
écrivez un horodatage et le contenu du paquet déposé dans le fichier PCAP :

file->Write(Simulator::Now(), p);

Bien sûr, si nous avons des objets représentant les deux fichiers, nous devons les créer quelque part
et également les faire passer aux puits de trace. Si vous regardez dans le principal fonction,
vous trouverez un nouveau code pour faire exactement cela:

AsciiTraceHelper asciiTraceHelper ;
Ptr stream = asciiTraceHelper.CreateFileStream ("sixth.cwnd");
ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow", MakeBoundCallback (&CwndChange, flux));



PcapHelper pcapHelper;
Ptr file = pcapHelper.CreateFile ("sixth.pcap", std::ios::out, PcapHelper::DLT_PPP);
devices.Get (1)->TraceConnectWithoutContext("PhyRxDrop", MakeBoundCallback (&RxDrop, fichier));

Dans la première section de l'extrait de code ci-dessus, nous créons le fichier de trace ASCII,
créer un objet chargé de le gérer et d'utiliser une variante du callback
fonction de création pour faire en sorte que l'objet soit transmis au récepteur. Notre trace ASCII
Les assistants fournissent un riche ensemble de fonctions pour faciliter l'utilisation des fichiers texte (ASCII). Nous sommes
Je vais juste illustrer l'utilisation de la fonction de création de flux de fichiers ici.

Notre Créer un flux de fichiers fonction va essentiellement instancier un std::offstream objet et
créer un nouveau fichier (ou tronquer un fichier existant). Cette std::offstream est emballé dans un
ns-3 objet pour la gestion de la durée de vie et la résolution des problèmes de constructeur de copie.

On prend alors ça ns-3 objet représentant le fichier et le passer à MakeBoundCallback().
Cette fonction crée un rappel comme FaireRappel(), mais il "lie" une nouvelle valeur à
le rappel. Cette valeur est ajoutée comme premier argument au rappel avant qu'il ne soit
appelé.

Essentiellement, MakeBoundCallback(&CwndChange, courant) oblige la source de trace à ajouter le
paramètre "stream" supplémentaire au début de la liste des paramètres formels avant d'invoquer
le rappel. Cela modifie la signature requise du CwndChange évier assorti à celui
ci-dessus, qui inclut le paramètre "extra" Ptr courant.

Dans la deuxième section de code de l'extrait de code ci-dessus, nous instancions un PcapHelper pour faire le
même chose pour notre fichier de trace PCAP que nous avons fait avec le AsciiTraceHelper. La ligne de
code,

Ptr file = pcapHelper.CreateFile ("sixième.pcap",
"w", PcapHelper::DLT_PPP);

crée un fichier PCAP nommé "sixth.pcap" avec le mode de fichier "w". Cela signifie que le nouveau fichier
est tronqué (contenu supprimé) si un fichier existant portant ce nom est trouvé. Le final
paramètre est le "type de liaison de données" du nouveau fichier PCAP. Ce sont les mêmes que le PCAP
types de liaison de données de bibliothèque définis dans bpf.h si vous êtes familier avec PCAP. Dans ce cas,
DLT_PPP indique que le fichier PCAP va contenir des paquets préfixés par pointer vers
en-têtes de points. C'est vrai puisque les paquets proviennent de notre appareil point à point
chauffeur. Les autres types de liaison de données courants sont DLT_EN10MB (Ethernet 10 Mo) approprié pour csma
appareils et DLT_IEEE802_11 (IEEE 802.11) approprié pour les appareils wifi. Ceux-ci sont définis
in src/réseau/helper/trace-helper.h si vous êtes intéressé à voir la liste. La
les entrées de la liste correspondent à celles de bpf.h mais nous les dupliquons pour éviter une source PCAP
dépendance.

A ns-3 l'objet représentant le fichier PCAP est renvoyé de CreateFile et utilisé dans une limite
callback exactement comme dans le cas ASCII.

Un détour important : Il est important de noter que même si ces deux objets sont
déclarés de manière très similaire,

Ptr dossier ...
Ptr flux ...

Les objets sous-jacents sont entièrement différents. Par exemple, le Ptr est une
pointeur intelligent vers un ns-3 Objet qui est une chose assez lourde qui prend en charge
Attributs et est intégré au système Config. La Ptr, Sur la
d'autre part, est un pointeur intelligent vers un objet compté par référence qui est très léger
chose. N'oubliez pas de regarder l'objet auquel vous faites référence avant de faire des suppositions
sur les "pouvoirs" que cet objet peut avoir.

Par exemple, jetez un œil à src/network/utils/pcap-file-wrapper.h dans la distribution et
avis,

classe PcapFileWrapper : objet public

cette classe PcapFileWrapper est un ns-3 Objet en vertu de son héritage. Alors regarde
src/network/model/output-stream-wrapper.h et avis,

classe OutputStreamWrapper : public
SimpleRefCount

que cet objet n'est pas un ns-3 Objet du tout, c'est "simplement" un objet C++ qui arrive à
prendre en charge le comptage intrusif des références.

Le point ici est que juste parce que vous lisez Ptr ça ne veut pas forcément dire
qui quelque chose est un ns-3 Objet sur lequel vous pouvez vous accrocher ns-3 Les attributs, par exemple.

Maintenant, revenons à l'exemple. Si vous générez et exécutez cet exemple,

$ ./waf --exécuter sixième

vous verrez apparaître les mêmes messages que lorsque vous avez exécuté "cinquième", mais deux nouveaux fichiers seront
apparaissent dans le répertoire de niveau supérieur de votre ns-3 distribution.

sixième.cwnd sixième.pcap

Étant donné que "sixth.cwnd" est un fichier texte ASCII, vous pouvez le visualiser avec cat ou votre fichier préféré
téléspectateur.

1 0 536
1.0093 536 1072
1.01528 1072 1608
1.02167 1608 2144

9.69256 5149 5204
9.89311 5204 5259

Vous avez un fichier séparé par des tabulations avec un horodatage, une ancienne fenêtre de congestion et une nouvelle
fenêtre de congestion adaptée à l'importation directe dans votre programme de tracé. Il n'y a pas
des impressions superflues dans le fichier, aucune analyse ou modification n'est requise.

Étant donné que "sixth.pcap" est un fichier PCAP, vous pouvez le visualiser avec tcpdump.

lecture à partir du fichier sixième.pcap, PPP de type lien (PPP)
1.136956 IP 10.1.1.1.49153 > 10.1.1.2.8080 : Drapeaux [.], seq 17177:17681, ack 1, win 32768, options [TS val 1133 ecr 1127,eol], longueur 504
1.403196 IP 10.1.1.1.49153 > 10.1.1.2.8080 : Drapeaux [.], seq 33280:33784, ack 1, win 32768, options [TS val 1399 ecr 1394,eol], longueur 504

7.426220 IP 10.1.1.1.49153 > 10.1.1.2.8080 : Drapeaux [.], seq 785704:786240, ack 1, win 32768, options [TS val 7423 ecr 7421,eol], longueur 536
9.630693 IP 10.1.1.1.49153 > 10.1.1.2.8080 : Drapeaux [.], seq 882688:883224, ack 1, win 32768, options [TS val 9620 ecr 9618,eol], longueur 536

Vous avez un fichier PCAP avec les paquets qui ont été abandonnés dans la simulation. Il n'y a pas
d'autres paquets présents dans le fichier et il n'y a rien d'autre présent pour rendre la vie
difficile.

Le voyage a été long, mais nous en sommes maintenant à un point où nous pouvons apprécier la ns-3
système de traçage. Nous avons retiré des événements importants du milieu d'une implémentation TCP
et un pilote de périphérique. Nous avons stocké ces événements directement dans des fichiers utilisables avec des
outils. Nous l'avons fait sans modifier le code de base impliqué, et nous l'avons fait en
seulement 18 lignes de code :

vide statique
CwndChange (Ptr flux, uint32_t oldCwnd, uint32_t newCwnd)
{
NS_LOG_UNCOND (Simulator::Now ().GetSeconds () << "\t" << newCwnd);
*stream->GetStream () << Simulator::Now ().GetSeconds () << "\t" << oldCwnd << "\t" << newCwnd << std ::endl;
}



AsciiTraceHelper asciiTraceHelper ;
Ptr stream = asciiTraceHelper.CreateFileStream ("sixth.cwnd");
ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow", MakeBoundCallback (&CwndChange, flux));



vide statique
RxDrop (Ptr fichier, Ptr p)
{
NS_LOG_UNCOND ("RxDrop à " << Simulateur :: Maintenant ().GetSeconds ());
file->Write(Simulator::Now(), p);
}



PcapHelper pcapHelper;
Ptr file = pcapHelper.CreateFile ("sixth.pcap", "w", PcapHelper::DLT_PPP);
devices.Get (1)->TraceConnectWithoutContext("PhyRxDrop", MakeBoundCallback (&RxDrop, fichier));

Tracer assistants
Notre ns-3 les assistants de trace fournissent un environnement riche pour configurer et sélectionner différents
suivre les événements et les écrire dans des fichiers. Dans les sections précédentes, principalement
BuildingTopologies, nous avons vu plusieurs variétés de méthodes d'aide à la trace conçues
pour une utilisation à l'intérieur d'autres assistants (de périphérique).

Peut-être vous souviendrez-vous avoir vu certaines de ces variations :

pointToPoint.EnablePcapAll ("seconde");
pointToPoint.EnablePcap ("deuxième", p2pNodes.Get (0)->GetId (), 0);
csma.EnablePcap ("troisième", csmaDevices.Get (0), vrai);
pointToPoint.EnableAsciiAll (ascii.CreateFileStream ("myfirst.tr"));

Ce qui n'est peut-être pas évident, cependant, c'est qu'il existe un modèle cohérent pour tous les
méthodes liées à la trace trouvées dans le système. Nous allons maintenant prendre un peu de temps et jeter un œil
à la "grande image".

Il existe actuellement deux principaux cas d'utilisation des assistants de traçage dans ns-3: assistants de périphérique
et aides au protocole. Les assistants de périphérique examinent le problème de la spécification des traces
doit être activé via une paire (nœud, périphérique). Par exemple, vous pouvez spécifier
que le traçage PCAP doit être activé sur un périphérique particulier sur un nœud spécifique. Cette
découle de la ns-3 modèle conceptuel de l'appareil, ainsi que les modèles conceptuels du
divers assistants de périphérique. Suite naturellement à cela, les fichiers créés suivent un
- - convention de nommage.

Les assistants de protocole examinent le problème de la spécification des traces à activer via
une paire de protocole et d'interface. Cela découle de la ns-3 pile de protocoles conceptuel
modèle, ainsi que les modèles conceptuels des aides de pile Internet. Naturellement, la trace
les fichiers doivent suivre un - - convention de nommage.

Les assistants de trace s'inscrivent donc naturellement dans une taxonomie bidimensionnelle. Il y a
subtilités qui empêchent les quatre classes de se comporter de manière identique, mais nous nous efforçons de
faire en sorte qu'ils fonctionnent tous de la manière la plus similaire possible ; et chaque fois que possible, il existe des analogues pour
toutes les méthodes dans toutes les classes.

┌────────────────┬──────┬───────┐
│ │ PCAP │ ASCII │
└────────────────┴──────┴───────┘

│Aide de l'appareil │ │ │
├────────────────┼──────┼───────┤
│Aide au protocole │ │ │
└────────────────┴──────┴───────┘

Nous utilisons une approche appelée mixin pour ajouter une fonctionnalité de traçage à nos classes d'assistance. UNE
mixin est une classe qui fournit des fonctionnalités lorsqu'elle est héritée par une sous-classe.
L'héritage d'un mixin n'est pas considéré comme une forme de spécialisation mais est vraiment un moyen de
collecter des fonctionnalités.

Jetons un coup d'œil rapide à ces quatre cas et à leurs mélanges.

Appareil assistants
PPCE
L'objectif de ces assistants est de faciliter l'ajout d'une fonction de trace PCAP cohérente à un
ns-3 dispositif. Nous voulons que toutes les différentes versions du traçage PCAP fonctionnent de la même manière
tous les périphériques, de sorte que les méthodes de ces assistants sont héritées par les assistants de périphérique. Regarde
at src/réseau/helper/trace-helper.h si vous voulez suivre la discussion tout en regardant
code réel.

La classe PcapHelperForDevice est une mixin fournit la fonctionnalité de haut niveau pour l'utilisation
Le traçage PCAP dans un ns-3 appareil. Chaque appareil doit implémenter une seule méthode virtuelle
hérité de cette classe.

vide virtuel EnablePcapInternal (std :: préfixe de chaîne, Ptr nd, bool promiscuous, bool explicitFilename) = 0 ;

La signature de cette méthode reflète la vision centrée sur l'appareil de la situation à ce
niveau. Toutes les méthodes publiques héritées de la classe PcapUserHelperForDevice réduire à
appeler cette méthode de mise en œuvre dépendante de l'appareil unique. Par exemple, le niveau le plus bas
Méthode PCAP,

void EnablePcap (std::string prefix, Ptr nd, bool promiscuous = false, bool explicitFilename = false);

appellera l'implémentation de l'appareil de ActiverPcapInterne directement. Tous les autres PCAP publics
les méthodes de suivi s'appuient sur cette implémentation pour fournir des informations supplémentaires au niveau de l'utilisateur
Fonctionnalité. Cela signifie pour l'utilisateur que tous les assistants de périphérique du système
disposer de toutes les méthodes de traçage PCAP ; et ces méthodes fonctionneront toutes de la même manière
chemin à travers les appareils si l'appareil implémente ActiverPcapInterne correctement.

Méthodologie
void EnablePcap (std::string prefix, Ptr nd, bool promiscuous = false, bool explicitFilename = false);
void EnablePcap (préfixe std::string, std::string ndName, bool promiscuous = false, bool explicitFilename = false);
void EnablePcap (préfixe std::string, NetDeviceContainer d, bool promiscuous = false);
void EnablePcap (préfixe std::string, NodeContainer n, bool promiscuous = false);
void EnablePcap (préfixe std::string, uint32_t nodeid, uint32_t deviceid, bool promiscuous = false);
void EnablePcapAll (préfixe std::string, bool promiscuous = false);

Dans chacune des méthodes présentées ci-dessus, il existe un paramètre par défaut appelé immoral qui
Par défaut non. Ce paramètre indique que la trace ne doit pas être collectée dans
mode de promiscuité. Si vous souhaitez que vos traces incluent tout le trafic vu par l'appareil
(et si l'appareil prend en charge un mode de promiscuité), ajoutez simplement un vrai paramètre à l'un des
appels ci-dessus. Par exemple,

Ptr sd ;

helper.EnablePcap ("prefix", nd, true);

activera les captures en mode promiscuité sur le NetDevice spécifié par nd.

Les deux premières méthodes incluent également un paramètre par défaut appelé expliciteNomFichier cela va
être discuté ci-dessous.

Nous vous encourageons à consulter la documentation de l'API pour la classe PcapHelperForDevice trouver
les détails de ces méthodes ; mais pour résumer...

· Vous pouvez activer le traçage PCAP sur une paire nœud/réseau-périphérique particulière en fournissant un
Ptr à un ActiverPcap méthode. le Ptr est implicite puisque le net device
doit appartenir à exactement un nœud. Par exemple,

Ptr sd ;

helper.EnablePcap ("préfixe", nd);

· Vous pouvez activer le traçage PCAP sur une paire nœud/réseau-périphérique particulière en fournissant un
std :: string représentant une chaîne de service de nom d'objet à un ActiverPcap méthode. le
Ptr est recherché à partir de la chaîne de nom. Encore une fois, le est implicite puisque
le périphérique réseau nommé doit appartenir à exactement un nœud. Par exemple,

Names::Add ("serveur" ...);
Names::Add ("serveur/eth0" ...);

helper.EnablePcap ("préfixe", "serveur/ath0");

· Vous pouvez activer le traçage PCAP sur une collection de paires nœud/réseau-périphérique en fournissant un
NetDeviceContainer. Pour chaque NetDevice dans le conteneur, le type est vérifié. Pour chaque
périphérique du type approprié (le même type que celui géré par l'assistant de périphérique), le traçage est
activée. Encore une fois, le est implicite puisque le périphérique réseau trouvé doit appartenir à
exactement un nœud. Par exemple,

NetDeviceContainer d = ...;

helper.EnablePcap ("préfixe", d);

· Vous pouvez activer le traçage PCAP sur une collection de paires nœud/réseau-périphérique en fournissant un
Conteneur de nœud. Pour chaque nœud du Conteneur de nœud c'est attaché NetDevices sont itérés.
Pour chaque NetDevice attaché à chaque nœud dans le conteneur, le type de cet appareil est
vérifié. Pour chaque appareil du type approprié (le même type que celui géré par l'appareil
helper), le traçage est activé.

NodeContainer n ;

helper.EnablePcap ("préfixe", n);

· Vous pouvez activer le traçage PCAP sur la base de l'ID de nœud et de l'ID de périphérique ainsi qu'avec
explicite Ptr. Chaque nœud du système a un ID de nœud entier et chaque appareil connecté
à un nœud a un ID de périphérique entier.

helper.EnablePcap ("préfixe", 21, 1);

· Enfin, vous pouvez activer le traçage PCAP pour tous les appareils du système, avec le même type
comme celui géré par l'assistant de périphérique.

helper.EnablePcapAll ("préfixe");

Noms de fichiers
Implicite dans les descriptions de méthodes ci-dessus est la construction d'un nom de fichier complet par
la méthode de mise en œuvre. Par convention, PCAP trace dans le ns-3 système sont de la forme
- identifiant>- identifiant>.pcap

Comme mentionné précédemment, chaque nœud du système aura un identifiant de nœud attribué par le système ; et
chaque périphérique aura un index d'interface (également appelé identifiant de périphérique) relatif à son nœud.
Par défaut, un fichier de trace PCAP créé à la suite de l'activation de la trace sur le premier
périphérique du nœud 21 utilisant le préfixe "préfixe" serait préfixe-21-1.pcap.

Vous pouvez toujours utiliser le ns-3 service de nom d'objet pour rendre cela plus clair. Par exemple, si
vous utilisez le service de nom d'objet pour attribuer le nom "serveur" au nœud 21, le PCAP résultant
le nom du fichier de trace deviendra automatiquement, préfixe-serveur-1.pcap et si vous affectez également le
nom "eth0" à l'appareil, votre nom de fichier PCAP le détectera automatiquement et sera
appelé préfixe-serveur-eth0.pcap.

Enfin, deux des méthodes présentées ci-dessus,

void EnablePcap (std::string prefix, Ptr nd, bool promiscuous = false, bool explicitFilename = false);
void EnablePcap (préfixe std::string, std::string ndName, bool promiscuous = false, bool explicitFilename = false);

avoir un paramètre par défaut appelé expliciteNomFichier. Lorsqu'il est défini sur vrai, ce paramètre
désactive le mécanisme de complétion automatique des noms de fichiers et vous permet de créer un
nom de fichier. Cette option n'est disponible que dans les méthodes qui activent le traçage PCAP sur un
appareil unique.

Par exemple, afin de faire en sorte qu'un assistant d'appareil crée un seul PCAP promiscuité
fichier de capture d'un nom spécifique mon-fichier-pcap.pcap sur un appareil donné, on pourrait :

Ptr sd ;

helper.EnablePcap ("mon-fichier-pcap.pcap", nd, vrai, vrai);

La première oui le paramètre active les traces en mode promiscuité et le second indique à l'assistant
interpréter le préfixe paramètre comme un nom de fichier complet.

ASCII
Le comportement de l'assistant de trace ASCII mixin est sensiblement similaire à la version PCAP.
Jetez un oeil à src/réseau/helper/trace-helper.h si vous voulez suivre la discussion
tout en regardant du vrai code.

La classe AsciiTraceHelperForDevice ajoute la fonctionnalité de haut niveau pour l'utilisation d'ASCII
suivi d'une classe d'assistance de périphérique. Comme dans le cas du PCAP, chaque appareil doit implémenter un
méthode virtuelle unique héritée de la trace ASCII mixin.

vide virtuel EnableAsciiInternal (Ptr flux,
std :: préfixe de chaîne,
Ptr sd,
bool nomFichier explicite) = 0 ;

La signature de cette méthode reflète la vision centrée sur l'appareil de la situation à ce
niveau; et aussi le fait que l'assistant peut écrire dans un flux de sortie partagé. Tous
les méthodes publiques liées à la trace ASCII héritées de la classe AsciiTraceHelperForDevice
réduire à appeler cette seule méthode d'implémentation dépendante de l'appareil. Par exemple, le
méthodes de trace ascii de plus bas niveau,

void EnableAscii (std::string prefix, Ptr nd, bool explicitFilename = false);
annuler EnableAscii (Ptr flux, Ptr nd);

appellera l'implémentation de l'appareil de ActiverAsciiInterne directement, en fournissant soit un
préfixe ou flux valide. Toutes les autres méthodes de traçage ASCII publiques s'appuieront sur ces
fonctions de bas niveau pour fournir des fonctionnalités supplémentaires au niveau de l'utilisateur. Ce que cela signifie pour
l'utilisateur est que tous les assistants de périphérique du système auront toutes les méthodes de trace ASCII
disponible; et ces méthodes fonctionneront toutes de la même manière sur tous les appareils si les appareils
Mettre en oeuvre ActiverAsciiInterne correctement.

Méthodologie
void EnableAscii (std::string prefix, Ptr nd, bool explicitFilename = false);
annuler EnableAscii (Ptr flux, Ptr nd);

void EnableAscii (std :: préfixe de chaîne, std :: chaîne ndName, bool explicitFilename = false);
annuler EnableAscii (Ptr flux, std :: chaîne ndName);

void EnableAscii (préfixe std::string, NetDeviceContainer d);
annuler EnableAscii (Ptr flux, NetDeviceContainer d);

void EnableAscii (std::string préfixe, NodeContainer n);
annuler EnableAscii (Ptr flux, NodeContainer n);

void EnableAsciiAll (std :: préfixe de chaîne);
annuler EnableAsciiAll (Ptr flux);

void EnableAscii (préfixe std::string, uint32_t nodeid, uint32_t deviceid, bool explicitFilename);
annuler EnableAscii (Ptr flux, uint32_t nodeid, uint32_t deviceid);

Nous vous encourageons à consulter la documentation de l'API pour la classe AsciiTraceHelperForDevice à
trouver les détails de ces méthodes ; mais pour résumer...

· Il existe deux fois plus de méthodes disponibles pour le traçage ASCII que pour le PCAP
tracé. En effet, en plus du modèle de type PCAP où les traces de chaque
une paire nœud/dispositif unique sont écrites dans un fichier unique, nous prenons en charge un modèle dans lequel la trace
les informations pour de nombreuses paires nœud/dispositif sont écrites dans un fichier commun. Cela signifie que le
- - mécanisme de génération de nom de fichier est remplacé par un mécanisme
se référer à un dossier commun ; et le nombre de méthodes API est doublé pour permettre à tous
combinaisons.

· Tout comme dans le traçage PCAP, vous pouvez activer le traçage ASCII sur un particulier (noeud, net-device)
paire en fournissant un Ptr à un ActiverAscii méthode. le Ptr est implicite
étant donné que le périphérique réseau doit appartenir à exactement un nœud. Par exemple,

Ptr sd ;

helper.EnableAscii ("préfixe", nd);

· Les quatre premières méthodes incluent également un paramètre par défaut appelé expliciteNomFichier qui
fonctionnent de la même manière que les paramètres équivalents dans le cas du PCAP.

Dans ce cas, aucun contexte de trace n'est écrit dans le fichier de trace ASCII car ils seraient
redondant. Le système choisira le nom du fichier à créer en utilisant les mêmes règles que
décrit dans la section PCAP, sauf que le fichier aura le suffixe .tr au lieu de
.pcap.

· Si vous souhaitez activer le traçage ASCII sur plusieurs périphériques réseau et que tous les suivis soient envoyés
à un seul fichier, vous pouvez également le faire en utilisant un objet pour faire référence à un seul fichier.
Nous avons déjà vu cela dans l'exemple "cwnd" ci-dessus :

Ptr nd1 ;
Ptr nd2 ;

Ptr stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");

helper.EnableAscii (flux, nd1);
helper.EnableAscii (flux, nd2);

Dans ce cas, les contextes de trace are écrites dans le fichier de trace ASCII puisqu'elles sont nécessaires
pour lever l'ambiguïté des traces des deux appareils. Notez que puisque l'utilisateur est complètement
en spécifiant le nom du fichier, la chaîne doit inclure le ,tr suffixe de cohérence.

· Vous pouvez activer le traçage ASCII sur une paire particulière (nœud, périphérique réseau) en fournissant un
std :: string représentant une chaîne de service de nom d'objet à un ActiverPcap méthode. le
Ptr est recherché à partir de la chaîne de nom. Encore une fois, le est implicite puisque
le périphérique réseau nommé doit appartenir à exactement un nœud. Par exemple,

Noms ::Ajouter ("client" ...);
Names::Add ("client/eth0" ...);
Names::Add ("serveur" ...);
Names::Add ("serveur/eth0" ...);

helper.EnableAscii ("préfixe", "client/eth0");
helper.EnableAscii ("préfixe", "serveur/eth0");

Cela donnerait deux fichiers nommés ``prefix-client-eth0.tr`` et
``prefix-server-eth0.tr`` avec des traces pour chaque périphérique dans le
fichier de trace respectif. Puisque toutes les fonctions ``EnableAscii``
sont surchargés pour prendre un wrapper de flux, vous pouvez utiliser ce formulaire comme
bien::

Noms ::Ajouter ("client" ...);
Names::Add ("client/eth0" ...);
Names::Add ("serveur" ...);
Names::Add ("serveur/eth0" ...);

Ptr stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");

helper.EnableAscii (flux, "client/eth0");
helper.EnableAscii (flux, "serveur/eth0");

Cela se traduirait par un seul fichier de trace appelé nom-fichier-trace.tr qui contient tout
les événements de trace pour les deux appareils. Les événements seraient désambiguïsés par le contexte de trace
cordes.

· Vous pouvez activer le traçage ASCII sur une collection de paires (noeud, net-device) en fournissant un
NetDeviceContainer. Pour chaque NetDevice dans le conteneur, le type est vérifié. Pour chaque
périphérique du type approprié (le même type que celui géré par l'assistant de périphérique), le traçage est
activée. Encore une fois, le est implicite puisque le périphérique réseau trouvé doit appartenir à
exactement un nœud. Par exemple,

NetDeviceContainer d = ...;

helper.EnableAscii ("préfixe", d);

Cela entraînerait la création d'un certain nombre de fichiers de trace ASCII,
dont chacun suit le `` - - .tr``
convention.

La combinaison de toutes les traces dans un seul fichier est réalisée de la même manière que dans les exemples
au dessus de:

NetDeviceContainer d = ...;

Ptr stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");

helper.EnableAscii (flux, d);

· Vous pouvez activer le traçage ASCII sur une collection de paires (noeud, net-device) en fournissant un
Conteneur de nœud. Pour chaque nœud du Conteneur de nœud c'est attaché NetDevices sont itérés.
Pour chaque NetDevice attaché à chaque nœud dans le conteneur, le type de cet appareil est
vérifié. Pour chaque appareil du type approprié (le même type que celui géré par l'appareil
helper), le traçage est activé.

NodeContainer n ;

helper.EnableAscii ("préfixe", n);

Cela entraînerait la création d'un certain nombre de fichiers de trace ASCII, chacun suivant
le - identifiant>- identifiant>.tr convention. Regroupant toutes les traces dans un
fichier unique est accompli de la même manière que dans les exemples ci-dessus.

· Vous pouvez activer le traçage PCAP sur la base de l'ID de nœud et de l'ID de périphérique ainsi qu'avec
explicite Ptr. Chaque nœud du système a un ID de nœud entier et chaque appareil connecté
à un nœud a un ID de périphérique entier.

helper.EnableAscii ("préfixe", 21, 1);

Bien sûr, les traces peuvent être combinées dans un seul fichier comme indiqué ci-dessus.

· Enfin, vous pouvez activer le traçage PCAP pour tous les appareils du système, avec le même type
comme celui géré par l'assistant de périphérique.

helper.EnableAsciiAll ("préfixe");

Cela entraînerait la création d'un certain nombre de fichiers de trace ASCII, un pour chaque périphérique
dans le système du type géré par l'assistant. Tous ces fichiers suivront la
- identifiant>- identifiant>.tr convention. Regroupant toutes les traces en une seule
fichier est accompli de la même manière que dans les exemples ci-dessus.

Noms de fichiers
Implicite dans les descriptions de méthodes de style préfixe ci-dessus est la construction du
noms de fichiers par la méthode d'implémentation. Par convention, les traces ASCII dans le ns-3 Système
sont de la forme - identifiant>- identifiant>.tr

Comme mentionné précédemment, chaque nœud du système aura un identifiant de nœud attribué par le système ; et
chaque périphérique aura un index d'interface (également appelé identifiant de périphérique) relatif à son nœud.
Par défaut, un fichier de trace ASCII créé à la suite de l'activation de la trace sur le premier
périphérique du nœud 21, en utilisant le préfixe "préfixe", serait préfixe-21-1.tr.

Vous pouvez toujours utiliser le ns-3 service de nom d'objet pour rendre cela plus clair. Par exemple, si
vous utilisez le service de nom d'objet pour attribuer le nom "serveur" au nœud 21, le résultat
Le nom du fichier de trace ASCII deviendra automatiquement, préfixe-serveur-1.tr et si vous attribuez également
le nom "eth0" à l'appareil, votre nom de fichier de trace ASCII le détectera automatiquement
et être appelé préfixe-serveur-eth0.tr.

Plusieurs des méthodes ont un paramètre par défaut appelé expliciteNomFichier. Lorsqu'il est réglé sur
true, ce paramètre désactive le mécanisme de complétion automatique des noms de fichiers et vous permet
pour créer un nom de fichier explicite. Cette option n'est disponible que dans les méthodes qui prennent un
préfixe et activer le traçage sur un seul appareil.

Passerelle assistants
PPCE
Le but de ces mélanges est de faciliter l'ajout d'une fonction de traçabilité PCAP cohérente à
protocoles. Nous voulons que toutes les différentes saveurs de traçage PCAP fonctionnent de la même manière sur tous
protocoles, de sorte que les méthodes de ces assistants sont héritées par les assistants de pile. Jeter un coup d'œil à
src/réseau/helper/trace-helper.h si vous voulez suivre la discussion tout en regardant
code réel.

Dans cette section, nous allons illustrer les méthodes appliquées au protocole Ipv4. Pour
spécifiez des traces dans des protocoles similaires, remplacez simplement le type approprié. Par example,
utiliser un Ptr au lieu d'une Ptr et appelle ActiverPcapIpv6 au lieu de ActiverPcapIpv4.

La classe PcapHelperForIpv4 fournit la fonctionnalité de haut niveau pour l'utilisation du traçage PCAP
dans le Ipv4 protocole. Chaque assistant de protocole permettant ces méthodes doit implémenter un seul
méthode virtuelle héritée de cette classe. Il y aura une implémentation séparée pour
Ipv6, par exemple, mais la seule différence sera dans les noms de méthode et les signatures.
Différents noms de méthode sont nécessaires pour désambiguïser la classe Ipv4 de Ipv6 qui sont les deux
dérivé de la classe Objet, et les méthodes qui partagent la même signature.

vide virtuel EnablePcapIpv4Internal (std :: préfixe de chaîne,
Ptr ipv4,
interface uint32_t,
bool nomFichier explicite) = 0 ;

La signature de cette méthode reflète la vision centrée sur le protocole et l'interface du
situation à ce niveau. Toutes les méthodes publiques héritées de la classe PcapHelperForIpv4
réduire à appeler cette seule méthode de mise en œuvre dépendante de l'appareil. Par exemple, le
méthode PCAP de niveau le plus bas,

annuler EnablePcapIpv4 (std :: préfixe de chaîne, Ptr ipv4, interface uint4_t, booléen explicitFilename = false);

appellera l'implémentation de l'appareil de ActiverPcapIpv4Internal directement. Tous les autres publics
Les méthodes de traçage PCAP s'appuient sur cette implémentation pour fournir des informations supplémentaires au niveau de l'utilisateur.
Fonctionnalité. Cela signifie pour l'utilisateur que tous les assistants de protocole du système
disposera de toutes les méthodes de traçage PCAP ; et ces méthodes fonctionneront toutes dans le
de la même manière à travers les protocoles si l'assistant implémente ActiverPcapIpv4Internal correctement.

Méthodologie
Ces méthodes sont conçues pour être en correspondance biunivoque avec les nœuds et
NetDevice- versions centrées des versions de l'appareil. Au lieu de nœud et NetDevice paire
contraintes, nous utilisons des contraintes de protocole et d'interface.

Notez que tout comme dans la version de l'appareil, il existe six méthodes :

annuler EnablePcapIpv4 (std :: préfixe de chaîne, Ptr ipv4, interface uint4_t, booléen explicitFilename = false);
void EnablePcapIpv4 (std::string prefix, std::string ipv4Name, interface uint32_t, bool explicitFilename = false);
void EnablePcapIpv4 (std :: préfixe de chaîne, Ipv4InterfaceContainer c);
void EnablePcapIpv4 (std :: préfixe de chaîne, NodeContainer n);
void EnablePcapIpv4 (préfixe std::string, uint32_t nodeid, interface uint32_t, bool explicitFilename) ;
annuler EnablePcapIpv4All (std::string préfixe);

Nous vous encourageons à consulter la documentation de l'API pour la classe PcapHelperForIpv4 pour trouver le
détails de ces méthodes; mais pour résumer...

· Vous pouvez activer le traçage PCAP sur une paire protocole/interface particulière en fournissant un
Ptr et votre interface à un ActiverPcap méthode. Par exemple,

Ptr ipv4 = nœud->GetObject ();

helper.EnablePcapIpv4 ("préfixe", ipv4, 0);

· Vous pouvez activer le traçage PCAP sur une paire nœud/réseau-périphérique particulière en fournissant un
std :: string représentant une chaîne de service de nom d'objet à un ActiverPcap méthode. le
Ptr est recherché à partir de la chaîne de nom. Par exemple,

Names::Add ("serverIPv4" ...);

helper.EnablePcapIpv4 ("préfixe", "serverIpv4", 1);

· Vous pouvez activer le traçage PCAP sur un ensemble de paires protocole/interface en fournissant un
Conteneur d'interface IPv4. Pour chaque Ipv4 /paire d'interface dans le conteneur le protocole
le type est coché. Pour chaque protocole du type approprié (le même type que celui géré par
l'assistant de périphérique), le traçage est activé pour l'interface correspondante. Par exemple,

nœuds NodeContainer ;

Périphériques NetDeviceContainer = deviceHelper.Install (nœuds);

Ipv4AddressHelper ipv4 ;
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
interfaces Ipv4InterfaceContainer = ipv4.Assign (périphériques);

helper.EnablePcapIpv4 ("préfixe", interfaces);

· Vous pouvez activer le traçage PCAP sur un ensemble de paires protocole/interface en fournissant un
Conteneur de nœud. Pour chaque nœud du Conteneur de nœud le protocole approprié est trouvé.
Pour chaque protocole, ses interfaces sont énumérées et le traçage est activé sur le
paires. Par exemple,

NodeContainer n ;

helper.EnablePcapIpv4 ("préfixe", n);

· Vous pouvez également activer le traçage PCAP sur la base de l'ID de nœud et de l'interface. Dans ce
cas, le node-id est traduit en un Ptr et le protocole approprié est recherché
dans le nœud. Le protocole et l'interface résultants sont utilisés pour spécifier le
origine des traces.

helper.EnablePcapIpv4 ("préfixe", 21, 1);

· Enfin, vous pouvez activer le traçage PCAP pour toutes les interfaces du système, avec les
protocole étant du même type que celui géré par le device helper.

helper.EnablePcapIpv4All ("préfixe");

Noms de fichiers
Implicite dans toutes les descriptions de méthodes ci-dessus est la construction du
noms de fichiers par la méthode d'implémentation. Par convention, les traces PCAP prises pour les appareils dans
le ns-3 système sont de la forme " - - .pcap". Dans le cas de
traces de protocole, il existe une correspondance un à un entre les protocoles et Nodes. Ce
c'est parce que le protocole Objets sont agrégés à Nœud Objets. Puisqu'il n'y a pas de global
identifiant de protocole dans le système, nous utilisons l'identifiant de nœud correspondant dans la dénomination du fichier. Par conséquent
il existe une possibilité de collisions de noms de fichiers dans les noms de fichiers de trace choisis automatiquement.
Pour cette raison, la convention de nom de fichier est modifiée pour les traces de protocole.

Comme mentionné précédemment, chaque nœud du système aura un ID de nœud attribué par le système.
Puisqu'il existe une correspondance biunivoque entre les instances de protocole et les instances de nœud
nous utilisons l'identifiant de nœud. Chaque interface a un identifiant d'interface relatif à son protocole. Nous utilisons
la Convention " -n -je .pcap" pour nommer le fichier de trace dans
aides au protocole.

Par conséquent, par défaut, un fichier de trace PCAP créé à la suite de l'activation de la trace sur
l'interface 1 du protocole Ipv4 du Node 21 utilisant le préfixe "prefix" serait
"préfixe-n21-i1.pcap".

Vous pouvez toujours utiliser le ns-3 service de nom d'objet pour rendre cela plus clair. Par exemple, si
vous utilisez le service de nom d'objet pour attribuer le nom "serverIpv4" au Ptr sur le nœud
21, le nom du fichier de trace PCAP résultant deviendra automatiquement,
"préfixe-nserverIpv4-i1.pcap".

Plusieurs des méthodes ont un paramètre par défaut appelé expliciteNomFichier. Lorsqu'il est réglé sur
true, ce paramètre désactive le mécanisme de complétion automatique des noms de fichiers et vous permet
pour créer un nom de fichier explicite. Cette option n'est disponible que dans les méthodes qui prennent un
préfixe et activer le traçage sur un seul appareil.

ASCII
Le comportement des assistants de trace ASCII est sensiblement similaire au cas PCAP. Prenez un
regarder src/réseau/helper/trace-helper.h si vous voulez suivre la discussion pendant
regarder du vrai code.

Dans cette section, nous allons illustrer les méthodes appliquées au protocole Ipv4. Pour
spécifiez des traces dans des protocoles similaires, remplacez simplement le type approprié. Par example,
utiliser un Ptr au lieu d'une Ptr et appelle ActiverAsciiIpv6 au lieu de
ActiverAsciiIpv4.

La classe AsciitraceHelperForIpv4 ajoute la fonctionnalité de haut niveau pour l'utilisation d'ASCII
traçage vers un assistant de protocole. Chaque protocole qui permet ces méthodes doit implémenter un
méthode virtuelle unique héritée de cette classe.

vide virtuel EnableAsciiIpv4Internal (Ptr flux,
std :: préfixe de chaîne,
Ptr ipv4,
interface uint32_t,
bool nomFichier explicite) = 0 ;

La signature de cette méthode reflète la vision centrée sur le protocole et l'interface de la
situation à ce niveau ; et aussi le fait que l'assistant peut écrire à un partage
flux de sortie. Toutes les méthodes publiques héritées de la classe
PcapAndAsciiTraceHelperForIpv4 réduire à appeler ce seul appareil dépendant
méthode de mise en œuvre. Par exemple, les méthodes de trace ASCII de niveau le plus bas,

void EnableAsciiIpv4 (std::string prefix, Ptr ipv4, interface uint4_t, booléen explicitFilename = false);
annuler EnableAsciiIpv4 (Ptr flux, Ptr ipv4, interface uint4_t);

appellera l'implémentation de l'appareil de ActiverAsciiIpv4Interne directement, en fournissant soit
le préfixe ou le flux. Toutes les autres méthodes de traçage ASCII publiques s'appuieront sur ces
fonctions de bas niveau pour fournir des fonctionnalités supplémentaires au niveau de l'utilisateur. Ce que cela signifie pour
l'utilisateur est que tous les assistants de périphérique du système auront toutes les méthodes de trace ASCII
disponible; et ces méthodes fonctionneront toutes de la même manière à travers les protocoles si le
les protocoles implémentent ActiverAsciiIpv4Interne correctement.

Méthodologie
void EnableAsciiIpv4 (std::string prefix, Ptr ipv4, interface uint4_t, booléen explicitFilename = false);
annuler EnableAsciiIpv4 (Ptr flux, Ptr ipv4, interface uint4_t);

void EnableAsciiIpv4 (std::string prefix, std::string ipv4Name, interface uint32_t, bool explicitFilename = false);
annuler EnableAsciiIpv4 (Ptr flux, std :: string ipv4Name, interface uint32_t);

void EnableAsciiIpv4 (std :: préfixe de chaîne, Ipv4InterfaceContainer c);
annuler EnableAsciiIpv4 (Ptr flux, Ipv4InterfaceContainer c);

void EnableAsciiIpv4 (std :: préfixe de chaîne, NodeContainer n);
annuler EnableAsciiIpv4 (Ptr flux, NodeContainer n);

annuler EnableAsciiIpv4All (std::string préfixe);
annuler EnableAsciiIpv4All (Ptr flux);

void EnableAsciiIpv4 (std :: préfixe de chaîne, uint32_t nodeid, uint32_t deviceid, bool explicitFilename) ;
annuler EnableAsciiIpv4 (Ptr flux, uint32_t nodeid, interface uint32_t);

Nous vous encourageons à consulter la documentation de l'API pour la classe PcapAndAsciiHelperForIpv4 à
trouver les détails de ces méthodes ; mais pour résumer...

· Il existe deux fois plus de méthodes disponibles pour le traçage ASCII que pour le PCAP
tracé. En effet, en plus du modèle de type PCAP où les traces de chaque
paire protocole/interface unique sont écrites dans un fichier unique, nous prenons en charge un modèle dans lequel
les informations de trace pour de nombreuses paires protocole/interface sont écrites dans un fichier commun. Cette
signifie que le -n - mécanisme de génération de nom de fichier est
remplacé par un mécanisme de référence à un fichier commun ; et le nombre de méthodes API est
doublé pour permettre toutes les combinaisons.

· Tout comme dans le traçage PCAP, vous pouvez activer le traçage ASCII sur un protocole/interface particulier
paire en fournissant un Ptr et le interface à un ActiverAscii méthode. Par exemple,

Ptr ipv4 ;

helper.EnableAsciiIpv4 ("préfixe", ipv4, 1);

Dans ce cas, aucun contexte de trace n'est écrit dans le fichier de trace ASCII car ils seraient
redondant. Le système choisira le nom du fichier à créer en utilisant les mêmes règles que
décrit dans la section PCAP, sauf que le fichier aura le suffixe ".tr" à la place
de ".pcap".

· Si vous souhaitez activer le traçage ASCII sur plusieurs interfaces et que toutes les traces soient envoyées
à un seul fichier, vous pouvez également le faire en utilisant un objet pour faire référence à un seul fichier.
Nous avons déjà quelque chose de similaire dans l'exemple "cwnd" ci-dessus :

Ptr protocol4 = node1->GetObject ();
Ptr protocol4 = node2->GetObject ();

Ptr stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");

helper.EnableAsciiIpv4 (flux, protocole1, 1);
helper.EnableAsciiIpv4 (flux, protocole2, 1);

Dans ce cas, les contextes de trace sont écrits dans le fichier de trace ASCII puisqu'ils sont obligatoires
pour désambiguïser les traces des deux interfaces. Notez que puisque l'utilisateur est complètement
en spécifiant le nom du fichier, la chaîne doit inclure le ", tr" pour plus de cohérence.

· Vous pouvez activer le traçage ASCII sur un protocole particulier en fournissant un std :: string
représentant une chaîne de service de nom d'objet à un ActiverPcap méthode. le Ptr is
recherché à partir de la chaîne de nom. le dans les noms de fichiers résultants est implicite puisque
il existe une correspondance un à un entre les instances de protocole et les nœuds, par exemple,

Noms ::Ajouter ("node1Ipv4" ...);
Noms ::Ajouter ("node2Ipv4" ...);

helper.EnableAsciiIpv4 ("préfixe", "node1Ipv4", 1);
helper.EnableAsciiIpv4 ("préfixe", "node2Ipv4", 1);

Cela se traduirait par deux fichiers nommés "prefix-nnode1Ipv4-i1.tr" et
"prefix-nnode2Ipv4-i1.tr" avec des traces pour chaque interface dans le fichier de trace respectif.
Étant donné que toutes les fonctions EnableAscii sont surchargées pour prendre un wrapper de flux, vous pouvez
utilisez également ce formulaire :

Noms ::Ajouter ("node1Ipv4" ...);
Noms ::Ajouter ("node2Ipv4" ...);

Ptr stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");

helper.EnableAsciiIpv4 (flux, "node1Ipv4", 1);
helper.EnableAsciiIpv4 (flux, "node2Ipv4", 1);

Cela se traduirait par un seul fichier de trace appelé "trace-file-name.tr" qui contient tous
des événements de trace pour les deux interfaces. Les événements seraient désambiguïsés par la trace
chaînes de contexte.

· Vous pouvez activer le traçage ASCII sur une collection de paires protocole/interface en fournissant un
Conteneur d'interface IPv4. Pour chaque protocole du type approprié (le même type que
géré par l'assistant de périphérique), le traçage est activé pour l'interface correspondante.
Encore une fois, le est implicite puisqu'il existe une correspondance biunivoque entre chaque
protocole et son nœud. Par exemple,

nœuds NodeContainer ;

Périphériques NetDeviceContainer = deviceHelper.Install (nœuds);

Ipv4AddressHelper ipv4 ;
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
interfaces Ipv4InterfaceContainer = ipv4.Assign (périphériques);


helper.EnableAsciiIpv4 ("préfixe", interfaces);

Cela entraînerait la création d'un certain nombre de fichiers de trace ASCII, chacun suivant
la -n -je convention .tr. Regroupant toutes les traces dans un
fichier unique est réalisé de la même manière que dans les exemples ci-dessus :

nœuds NodeContainer ;

Périphériques NetDeviceContainer = deviceHelper.Install (nœuds);

Ipv4AddressHelper ipv4 ;
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
interfaces Ipv4InterfaceContainer = ipv4.Assign (périphériques);

Ptr stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");

helper.EnableAsciiIpv4 (flux, interfaces) ;

· Vous pouvez activer le traçage ASCII sur une collection de paires protocole/interface en fournissant un
Conteneur de nœud. Pour chaque nœud du Conteneur de nœud le protocole approprié est trouvé.
Pour chaque protocole, ses interfaces sont énumérées et le traçage est activé sur le
paires. Par exemple,

NodeContainer n ;

helper.EnableAsciiIpv4 ("préfixe", n);

Cela entraînerait la création d'un certain nombre de fichiers de trace ASCII, chacun suivant
la - - convention .tr. Regroupant toutes les traces dans un
fichier unique est accompli de la même manière que dans les exemples ci-dessus.

· Vous pouvez également activer le traçage PCAP sur la base de l'ID de nœud et de l'ID de périphérique. Dans ce
cas, le node-id est traduit en un Ptr et le protocole approprié est recherché
dans le nœud. Le protocole et l'interface résultants sont utilisés pour spécifier le
origine des traces.

helper.EnableAsciiIpv4 ("préfixe", 21, 1);

Bien sûr, les traces peuvent être combinées dans un seul fichier comme indiqué ci-dessus.

· Enfin, vous pouvez activer le traçage ASCII pour toutes les interfaces du système, avec les
protocole étant du même type que celui géré par le device helper.

helper.EnableAsciiIpv4All ("préfixe");

Cela entraînerait la création d'un certain nombre de fichiers de trace ASCII, un pour chaque
interface dans le système liée à un protocole du type géré par l'assistant. Tous
ces fichiers suivront -n -je
toutes les traces dans un seul fichier sont accomplies de la même manière que dans les exemples ci-dessus.

Noms de fichiers
Implicite dans les descriptions de méthodes de style préfixe ci-dessus est la construction du
noms de fichiers par la méthode d'implémentation. Par convention, les traces ASCII dans le ns-3 Système
sont de la forme " - - .tr"

Comme mentionné précédemment, chaque nœud du système aura un ID de nœud attribué par le système.
Puisqu'il existe une correspondance un à un entre les protocoles et les nœuds, nous utilisons node-id
pour identifier l'identité du protocole. Chaque interface sur un protocole donné aura un
index d'interface (également appelé simplement une interface) relatif à son protocole. Par défaut,
puis, un fichier de trace ASCII créé à la suite de l'activation de la trace sur le premier appareil de
Le nœud 21, utilisant le préfixe "prefix", serait "prefix-n21-i1.tr". Utilisez le préfixe pour
lever l'ambiguïté de plusieurs protocoles par nœud.

Vous pouvez toujours utiliser le ns-3 service de nom d'objet pour rendre cela plus clair. Par exemple, si
vous utilisez le service de nom d'objet pour attribuer le nom "serverIpv4" au protocole sur Node
21, et spécifiez également l'interface un, le nom du fichier de trace ASCII résultant sera automatiquement
devenir "prefix-nserverIpv4-1.tr".

Plusieurs des méthodes ont un paramètre par défaut appelé expliciteNomFichier. Lorsqu'il est réglé sur
true, ce paramètre désactive le mécanisme de complétion automatique des noms de fichiers et vous permet
pour créer un nom de fichier explicite. Cette option n'est disponible que dans les méthodes qui prennent un
préfixe et activer le traçage sur un seul appareil.

Résumé
ns-3 comprend un environnement extrêmement riche permettant aux utilisateurs à plusieurs niveaux de personnaliser
les types d'informations qui peuvent être extraites des simulations.

Il existe des fonctions d'assistance de haut niveau qui permettent aux utilisateurs de contrôler simplement la collecte de
sorties prédéfinies avec une granularité fine. Il existe des fonctions d'assistance de niveau intermédiaire pour permettre
des utilisateurs plus sophistiqués pour personnaliser la manière dont les informations sont extraites et enregistrées ; et là
sont des fonctions de base de bas niveau pour permettre aux utilisateurs experts de modifier le système pour présenter de nouvelles et
informations précédemment non exportées d'une manière qui sera immédiatement accessible aux utilisateurs à
Niveaux plus élevés.

C'est un système très complet, et on se rend compte que c'est beaucoup à digérer, surtout
pour les nouveaux utilisateurs ou ceux qui ne connaissent pas intimement C++ et ses idiomes. Nous considérons
le système de traçage une partie très importante de ns-3 et recommande donc de devenir aussi familier que
possible avec elle. C'est probablement le cas que la compréhension du reste de la ns-3 Système
sera assez simple une fois que vous aurez maîtrisé le système de traçage

DONNEES COLLECTION


Notre dernier chapitre du didacticiel présente certains composants qui ont été ajoutés à ns-3 en version
3.18, et qui sont encore en cours de développement. Cette section de didacticiel est également une
travaux en cours.

motivation
L'un des principaux points de l'exécution de simulations est de générer des données de sortie, soit pour
à des fins de recherche ou simplement pour en savoir plus sur le système. Dans le chapitre précédent, nous
introduit le sous-système de traçage et l'exemple sixième.cc. à partir de quelle trace PCAP ou ASCII
les fichiers sont générés. Ces traces sont précieuses pour l'analyse des données à l'aide d'une variété de
outils externes, et pour de nombreux utilisateurs, ces données de sortie sont un moyen privilégié de collecte
données (pour analyse par des outils externes).

Cependant, il existe également des cas d'utilisation pour plus que la génération de fichiers de trace, y compris le
Suivante à la suite:

· génération de données qui ne correspondent pas bien aux traces PCAP ou ASCII, telles que les non-paquets
les données (par exemple, les transitions de la machine d'état du protocole),

· grandes simulations pour lesquelles les exigences d'E/S disque pour générer des fichiers de trace sont
prohibitifs ou encombrants, et

· Le besoin de en ligne réduction ou calcul des données, au cours de la simulation.
Un bon exemple de ceci est de définir une condition de terminaison pour la simulation, de dire
quand s'arrêter quand il a reçu suffisamment de données pour former une confiance suffisamment étroite
intervalle autour de l'estimation d'un paramètre.

Notre ns-3 le cadre de collecte de données est conçu pour fournir ces capacités supplémentaires
au-delà de la sortie basée sur la trace. Nous recommandons au lecteur intéressé par ce sujet de consulter
le ns-3 Manuel pour un traitement plus détaillé de ce cadre; ici, on résume avec
un exemple de programme certaines des capacités de développement.

Exemple Code
L'exemple du tutoriel exemples/tutoriel/septième.cc ressemble au sixième.cc exemple nous
précédemment examiné, à l'exception de quelques modifications. Tout d'abord, il a été activé pour IPv6
prise en charge avec une option de ligne de commande :

cmd de ligne de commande ;
cmd.AddValue ("useIpv6", "Utiliser Ipv6", useV6);
cmd.Parse (argc, argv);

Si l'utilisateur spécifie utiliserIpv6, le programme sera exécuté en utilisant IPv6 au lieu d'IPv4.
Notre vous aider option, disponible sur tous ns-3 programmes qui prennent en charge l'objet CommandLine comme
indiqué ci-dessus, peut être invoqué comme suit (veuillez noter l'utilisation de guillemets doubles) :

./waf --run "septième --help"

qui produit:

ns3-dev-seventh-debug [Arguments du programme] [Arguments généraux]

Argumentation du programme :
--useIpv6 : Utiliser Ipv6 [faux]

Arguments généraux :
--PrintGlobals : imprime la liste des variables globales.
--PrintGroups : imprime la liste des groupes.
--PrintGroup=[groupe] : Imprime tous les TypeIds du groupe.
--PrintTypeIds : imprime tous les TypeIds.
--PrintAttributes=[typeid] : affiche tous les attributs de typeid.
--PrintHelp : imprime ce message d'aide.

Cette valeur par défaut (utilisation d'IPv4, puisque useIpv6 est faux) peut être modifiée en basculant le booléen
valeur comme suit :

./waf --run "septième --useIpv6=1"

et regardez le pcap généré, comme avec tcpdump:

tcpdump -r septième.pcap -nn -tt

Cela a été une courte digression dans le support IPv6 et la ligne de commande, qui a également été
présenté plus tôt dans ce didacticiel. Pour un exemple dédié d'utilisation de la ligne de commande,
s'il te plait regarde src/core/examples/command-line-example.cc.

Revenons maintenant à la collecte de données. Dans le exemples/tutoriel/ répertoire, tapez ce qui suit
commander: diff -u sixième.cc septième.cc, et examinez certaines des nouvelles lignes de ce diff :

+ std ::string type de sonde ;
+ std::string tracePath ;
+ si (useV6 == faux)
+ {

+ probeType = "ns3::Ipv4PacketProbe" ;
+ tracePath = "/NodeList/*/$ns3::Ipv4L3Protocol/Tx" ;
+ }
+ autre
+ {

+ probeType = "ns3::Ipv6PacketProbe" ;
+ tracePath = "/NodeList/*/$ns3::Ipv6L3Protocol/Tx" ;
+ }

+ // Utilisez GnuplotHelper pour tracer le nombre d'octets du paquet dans le temps
+ GnuplotHelper plotHelper ;
+
+ // Configurer le tracé. Le premier argument est le préfixe du nom de fichier
+ // pour les fichiers de sortie générés. Les deuxième, troisième et quatrième
+ // les arguments sont, respectivement, le titre du tracé, les étiquettes de l'axe des x et de l'axe des y
+ plotHelper.ConfigurePlot ("nombre d'octets du septième paquet",
+ "Nombre d'octets de paquets par rapport au temps",
+ "Temps (secondes)",
+ "Compte d'octets de paquets" );
+
+ // Spécifiez le type de sonde, le chemin de la source de trace (dans l'espace de noms de configuration) et
+ // sonde la source de trace de sortie ("OutputBytes") à tracer. Le quatrième argument
+ // spécifie le nom de l'étiquette de la série de données sur le tracé. Le dernier
+ // l'argument formate le tracé en spécifiant où la clé doit être placée.
+ plotHelper.PlotProbe (type de sonde,
+ tracePath,
+ "Octets de sortie",
+ "Compte d'octets de paquets",
+ GnuplotAggregator ::KEY_BELOW);
+
+ // Utilisez FileHelper pour écrire le nombre d'octets du paquet au fil du temps
+ FileHelper fileHelper ;
+
+ // Configurez le fichier à écrire et le formatage des données de sortie.
+ fileHelper.ConfigureFile ("nombre d'octets du septième paquet",
+ FileAggregator :: FORMATTED);
+
+ // Définir les étiquettes pour ce fichier de sortie formaté.
+ fileHelper.Set2dFormat ("Time (Seconds) = %.3e\tPacket Byte Count = %.0f");
+
+ // Spécifiez le type de sonde, le chemin de la sonde (dans l'espace de noms de configuration) et
+ // sonde la source de trace de sortie ("OutputBytes") à écrire.
+ fileHelper.WriteProbe (probeType,
+ tracePath,
+ "OutputBytes");
+
Simulator::Stop (Secondes (20));
Simulateur::Exécuter ();
Simulateur :: Détruire ();

Le lecteur attentif aura remarqué, lors du test de l'attribut de ligne de commande IPv6 ci-dessus,
qui septième.cc avait créé un certain nombre de nouveaux fichiers de sortie :

septième-paquet-octet-compte-0.txt
septième-paquet-octet-compte-1.txt
septième-paquet-octet-count.dat
septième-paquet-octet-count.plt
nombre-d-octets-du-septième-paquet.png
nombre-d'octets-de-septième-paquet.sh

Celles-ci ont été créées par les instructions supplémentaires introduites ci-dessus ; notamment, par un
GnuplotHelper et un FileHelper. Ces données ont été produites en accrochant la collecte de données
composants à ns-3 tracer les sources et rassembler les données dans un format gnuplot et votre
dans un fichier texte formaté. Dans les sections suivantes, nous passerons en revue chacun d'entre eux.

GnuplotHelperGenericName
Le GnuplotHelper est un ns-3 objet assistant destiné à la production de gnuplot parcelles avec
le moins d'énoncés possible, pour les cas courants. Ça accroche ns-3 tracer des sources avec des données
types pris en charge par le système de collecte de données. Pas tout ns-3 les types de données des sources de trace sont
pris en charge, mais de nombreux types de trace courants le sont, y compris TracedValues ​​avec plain old
type de données (POD).

Regardons la sortie produite par cet assistant :

septième-paquet-octet-count.dat
septième-paquet-octet-count.plt
nombre-d'octets-de-septième-paquet.sh

Le premier est un fichier de données gnuplot avec une série d'horodatages et de paquets délimités par des espaces.
compte d'octets. Nous verrons comment cette sortie de données particulière a été configurée ci-dessous, mais voyons
continuez avec les fichiers de sortie. Le fichier septième-paquet-octet-count.plt est un complot gnuplot
fichier, qui peut être ouvert depuis gnuplot. Les lecteurs qui comprennent la syntaxe de gnuplot peuvent
voyez que cela produira un fichier PNG de sortie formaté nommé
nombre-d-octets-du-septième-paquet.png. Enfin, un petit script shell
nombre-d'octets-de-septième-paquet.sh exécute ce fichier de tracé via gnuplot pour produire le résultat souhaité
PNG (qui peut être visualisé dans un éditeur d'images) ; c'est-à-dire la commande :

sh nombre-d'octets-de-septième-paquet.sh

cédera nombre-d-octets-du-septième-paquet.png. Pourquoi ce PNG n'a-t-il pas été produit dans le premier
lieu? La réponse est qu'en fournissant le fichier plt, l'utilisateur peut configurer manuellement le
résultat si désiré, avant de produire le PNG.

Le titre de l'image PNG indique que ce tracé est un tracé de "Compte d'octets de paquets en fonction du temps", et
qu'il trace les données sondées correspondant au chemin source de la trace :

/NodeList/*/$ns3::Ipv6L3Protocol/Tx

Notez le caractère générique dans le chemin de trace. En résumé, ce que cette intrigue capture est l'intrigue
d'octets de paquet observés à la source de trace de transmission de l'objet Ipv6L3Protocol ;
en grande partie des segments TCP de 596 octets dans une direction et des accusés de réception TCP de 60 octets dans l'autre (deux
les sources de trace du nœud correspondaient à cette source de trace).

Comment cela a-t-il été configuré ? Quelques déclarations doivent être fournies. Tout d'abord, le GnuplotHelper
objet doit être déclaré et configuré :

+ // Utilisez GnuplotHelper pour tracer le nombre d'octets du paquet dans le temps
+ GnuplotHelper plotHelper ;
+
+ // Configurer le tracé. Le premier argument est le préfixe du nom de fichier
+ // pour les fichiers de sortie générés. Les deuxième, troisième et quatrième
+ // les arguments sont, respectivement, le titre du tracé, les étiquettes de l'axe des x et de l'axe des y
+ plotHelper.ConfigurePlot ("nombre d'octets du septième paquet",
+ "Nombre d'octets de paquets par rapport au temps",
+ "Temps (secondes)",
+ "Compte d'octets de paquets" );

À ce stade, une parcelle vide a été configurée. Le préfixe du nom de fichier est le premier
argument, le titre du tracé est le deuxième, l'étiquette de l'axe des x le troisième et l'étiquette de l'axe des y
le quatrième argument.

L'étape suivante consiste à configurer les données, et c'est ici que la source de trace est accrochée.
Tout d'abord, notez ci-dessus dans le programme que nous avons déclaré quelques variables pour une utilisation ultérieure :

+ std ::string type de sonde ;
+ std::string tracePath ;
+ probeType = "ns3::Ipv6PacketProbe" ;
+ tracePath = "/NodeList/*/$ns3::Ipv6L3Protocol/Tx" ;

Nous les utilisons ici :

+ // Spécifiez le type de sonde, le chemin de la source de trace (dans l'espace de noms de configuration) et
+ // sonde la source de trace de sortie ("OutputBytes") à tracer. Le quatrième argument
+ // spécifie le nom de l'étiquette de la série de données sur le tracé. Le dernier
+ // l'argument formate le tracé en spécifiant où la clé doit être placée.
+ plotHelper.PlotProbe (type de sonde,
+ tracePath,
+ "Octets de sortie",
+ "Compte d'octets de paquets",
+ GnuplotAggregator ::KEY_BELOW);

Les deux premiers arguments sont le nom du type de sonde et le chemin de la source de trace. Ces
deux sont probablement les plus difficiles à déterminer lorsque vous essayez d'utiliser ce cadre pour tracer d'autres
traces. La trace de la sonde ici est la Tx tracer la source de la classe Protocole IPv6L3. quand nous
examiner cette implémentation de classe (src/internet/model/ipv6-l3-protocol.cc) nous pouvons observer:

.AddTraceSource ("Tx", "Envoyer le paquet IPv6 à l'interface sortante.",
MakeTraceSourceAccessor (&Ipv6L3Protocol::m_txTrace))

Ceci dit que Tx est un nom de variable m_txTrace, qui a une déclaration de :

/ **
* \brief Callback pour tracer les paquets TX (transmission).
*/
Rappel tracé , Ptr , uint6_t> m_txTrace ;

Il s'avère que cette signature de source de trace spécifique est prise en charge par une classe Probe (ce qui
dont nous avons besoin ici) de la classe Ipv6PacketProbe. Voir les fichiers
src/internet/model/ipv6-packet-probe.{h,cc}.

Ainsi, dans l'instruction PlotProbe ci-dessus, nous voyons que l'instruction accroche la trace
source (identifiée par la chaîne de chemin) avec une correspondance ns-3 Type de sonde de Ipv6PacketProbe. Si
nous n'avons pas pris en charge ce type de sonde (correspondant à la signature de la source de trace), nous aurions pu ne pas
utilisé cette déclaration (bien que certaines déclarations de niveau inférieur plus compliquées auraient pu être
utilisé, comme décrit dans le manuel).

Le Ipv6PacketProbe exporte lui-même certaines sources de trace qui extraient les données du
objet Packet sondé :

ID de type
Ipv6PacketProbe ::GetTypeId ()
{
statique TypeId tid = TypeId ("ns3::Ipv6PacketProbe")
.SetParent ()
.AddConstructor ()
.AddTraceSource ( "Sortie",
"Le paquet plus son objet IPv6 et son interface qui servent de sortie pour cette sonde",
MakeTraceSourceAccessor (&Ipv6PacketProbe::m_output))
.AddTraceSource ( "OutputBytes",
"Le nombre d'octets dans le paquet",
MakeTraceSourceAccessor (&Ipv6PacketProbe::m_outputBytes))
;
retour tid;
}

Le troisième argument de notre instruction PlotProbe précise que nous sommes intéressés par la
nombre d'octets dans ce paquet ; spécifiquement, la source de trace "OutputBytes" de
Ipv6PacketProbe. Enfin, les deux derniers arguments de l'instruction fournissent la légende de l'intrigue
pour cette série de données ("Packet Byte Count"), et une instruction de formatage gnuplot facultative
(GnuplotAggregator :: KEY_BELOW) que nous voulons que la clé de tracé soit insérée sous le tracé.
Les autres options incluent NO_KEY, KEY_INSIDE et KEY_ABOVE.

Appareils Tracer Types
Les valeurs tracées suivantes sont prises en charge avec les sondes au moment de la rédaction :

┌─────────────────┬─────────────────┬─── ────────── ────────────────────┐
│Type TracedValue │ Type de sonde │ Fichier │
├─────────────────┼─────────────────┼─── ────────── ────────────────────┤
│double │ DoubleProbe │ stats/model/double-probe.h │
├─────────────────┼─────────────────┼─── ────────── ────────────────────┤
│uint8_t │ Uinteger8Probe │ stats/model/uinteger-8-probe.h │
├─────────────────┼─────────────────┼─── ────────── ────────────────────┤
│uint16_t │ Uinteger16Probe │ stats/model/uinteger-16-probe.h │
├─────────────────┼─────────────────┼─── ────────── ────────────────────┤
│uint32_t │ Uinteger32Probe │ stats/model/uinteger-32-probe.h │
├─────────────────┼─────────────────┼─── ────────── ────────────────────┤
│bool │ BooleanProbe │ stats/model/uinteger-16-probe.h │
├─────────────────┼─────────────────┼─── ────────── ────────────────────┤
│ns3::Time │ TimeProbe │ stats/model/time-probe.h │
└─────────────────┴─────────────────┴─── ────────── ────────────────────┘

Les types TraceSource suivants sont pris en charge par les sondes au moment de la rédaction :

┌────────────────────┬────────────────── ──────┬─── ────────────┬─────────────────────────── ────────── ──────────┐
├────────────────────┼────────────────── ──────┼─── ────────────┼─────────────────────────── ────────── ──────────┤
├────────────────────┼────────────────── ──────┼─── ────────────┼─────────────────────────── ────────── ──────────┤
├────────────────────┼────────────────── ──────┼─── ────────────┼─────────────────────────── ────────── ──────────┤
├────────────────────┼────────────────── ──────┼─── ────────────┼─────────────────────────── ────────── ──────────┤
├────────────────────┼────────────────── ──────┼─── ────────────┼─────────────────────────── ────────── ──────────┤
└────────────────────┴────────────────── ──────┴─── ────────────┴─────────────────────────── ────────── ──────────┘

Comme on peut le voir, seules quelques sources de traces sont supportées, et elles sont toutes orientées vers
sortie de la taille du paquet (en octets). Cependant, la plupart des types de données fondamentaux
disponible en tant que TracedValues ​​peut être pris en charge avec ces assistants.

Aide-fichier
La classe FileHelper n'est qu'une variante de l'exemple GnuplotHelper précédent. Le
exemple de programme fournit une sortie formatée des mêmes données horodatées, comme suit :

Temps (secondes) = 9.312e+00 Nombre d'octets de paquets = 596
Temps (secondes) = 9.312e+00 Nombre d'octets de paquets = 564

Deux fichiers sont fournis, un pour le nœud "0" et un pour le nœud "1" comme on peut le voir dans le
noms de fichiers. Regardons le code morceau par morceau :

+ // Utilisez FileHelper pour écrire le nombre d'octets du paquet au fil du temps
+ FileHelper fileHelper ;
+
+ // Configurez le fichier à écrire et le formatage des données de sortie.
+ fileHelper.ConfigureFile ("nombre d'octets du septième paquet",
+ FileAggregator :: FORMATTED);

Le préfixe du fichier d'assistance de fichier est le premier argument, suivi d'un spécificateur de format. Quelques
les autres options de formatage incluent SPACE_SEPARATED, COMMA_SEPARATED et TAB_SEPARATED.
Les utilisateurs peuvent modifier le formatage (si FORMATTED est spécifié) avec une chaîne de format
comme suit :

+
+ // Définir les étiquettes pour ce fichier de sortie formaté.
+ fileHelper.Set2dFormat ("Time (Seconds) = %.3e\tPacket Byte Count = %.0f");

Enfin, la source de trace d'intérêt doit être accrochée. Encore une fois, le probeType et tracePath
les variables de cet exemple sont utilisées et la source de trace de sortie de la sonde "OutputBytes" est
accroché:

+
+ // Spécifiez le type de sonde, le chemin de la source de trace (dans l'espace de noms de configuration) et
+ // sonde la source de trace de sortie ("OutputBytes") à écrire.
+ fileHelper.WriteProbe (probeType,
+ tracePath,
+ "OutputBytes");
+

Les champs génériques de ce spécificateur de source de trace correspondent à deux sources de trace. Contrairement à la
Exemple GnuplotHelper, dans lequel deux séries de données ont été superposées sur le même tracé, ici, deux
des fichiers séparés sont écrits sur le disque.

Résumé
La prise en charge de la collecte de données est nouvelle à partir de ns-3.18 et la prise en charge de base pour fournir des séries chronologiques
sortie a été ajoutée. Le modèle de base décrit ci-dessus peut être reproduit dans le
étendue de la prise en charge des sondes et des sources de traces existantes. Plus de capacités, y compris
le traitement des statistiques sera ajouté dans les prochaines versions.

CONCLUSION


Contrats à terme
Ce document se veut un document vivant. Nous espérons et nous nous attendons à ce qu'il grandisse avec le temps
pour couvrir de plus en plus les écrous et boulons de ns-3.

Écrire des chapitres de manuels et de didacticiels n'est pas quelque chose qui nous passionne tous, mais c'est
très important pour le projet. Si vous êtes un expert dans l'un de ces domaines, veuillez
envisager de contribuer à ns-3 en fournissant l'un de ces chapitres ; ou tout autre chapitre que vous
peut penser que c'est important.

Fermeture
ns-3 est un système vaste et complexe. Il est impossible de couvrir toutes les choses que vous
aurez besoin de savoir dans un petit tutoriel. Les lecteurs qui souhaitent en savoir plus sont invités à
lire la documentation supplémentaire suivante :

· Le ns-3 Manuel

· Le ns-3 documentation de la bibliothèque de modèles

· Le ns-3 Doxygen (documentation API)

· Le ns-3 wiki

-- Le ns-3 équipe de développement.

Utiliser ns-3-tutorial en ligne en utilisant les services onworks.net


Serveurs et postes de travail gratuits

Télécharger des applications Windows et Linux

Commandes Linux

Ad