InglésFrancésCursos de

icono de página de OnWorks

ns-3-tutorial: en línea en la nube

Ejecute ns-3-tutorial en el proveedor de alojamiento gratuito de OnWorks sobre Ubuntu Online, Fedora Online, emulador en línea de Windows o emulador en línea de MAC OS

Este es el comando ns-3-tutorial que se puede ejecutar en el proveedor de alojamiento gratuito de OnWorks utilizando una de nuestras múltiples estaciones de trabajo en línea gratuitas, como Ubuntu Online, Fedora Online, emulador en línea de Windows o emulador en línea de MAC OS.

PROGRAMA:

NOMBRE


ns-3-tutorial - tutorial ns-3

Este es el ns-3 Tutorial. La documentación principal para el proyecto ns-3 está disponible en cinco
formas:

· ns-3 Doxygen: Documentación de las API públicas del simulador

· Tutorial (esta documento), Manual y biblioteca de modelos para más reciente , y
Desarrollo tree

· ns-3 wiki

Este documento está escrito en reStructuredText for Esfinge y se mantiene en el
doc / tutorial directorio del código fuente de ns-3.

INTRODUCCIÓN


Los ns-3 simulator es un simulador de red de eventos discretos dirigido principalmente a la investigación
y uso educativo. los ns-3 Antecedentes, iniciado en 2006, es un proyecto de código abierto
el desarrollo ns-3.

El propósito de este tutorial es presentar nuevos ns-3 usuarios al sistema de forma estructurada
camino. A veces es difícil para los nuevos usuarios obtener información esencial de
manuales y convertir esta información en simulaciones de trabajo. En este tutorial,
Construirá varias simulaciones de ejemplo, presentando y explicando conceptos clave y
características a medida que avanzamos.

A medida que se desarrolla el tutorial, presentaremos el ns-3 documentación y proporcionar
punteros al código fuente para aquellos interesados ​​en profundizar en el funcionamiento de la
.

Vale la pena señalar algunos puntos clave desde el principio:

· ns-3 es de código abierto, y el proyecto se esfuerza por mantener un entorno abierto para
investigadores para contribuir y compartir su software.

· ns-3 no es una extensión compatible con versiones anteriores de ns-2; es un nuevo simulador. Los dos
los simuladores están escritos en C ++ pero ns-3 es un nuevo simulador que no es compatible con
ns-2 API. Algunos modelos de ns-2 ya han sido portados desde ns-2 a ns-3.
El proyecto continuará manteniendo ns-2 mientras ns-3 se está construyendo y estudiará
Mecanismos de transición e integración.

¿Quién Soy? ns-3
ns-3 ha sido desarrollado para proporcionar una plataforma de simulación de red abierta y extensible, para
investigación y educación en red. En breve, ns-3 proporciona modelos de cómo los paquetes de datos
Las redes funcionan y funcionan, y proporciona un motor de simulación para que los usuarios realicen
experimentos de simulación. Algunas de las razones para usar ns-3 incluir para realizar estudios que
son más difíciles o no posibles de realizar con sistemas reales, para estudiar el comportamiento del sistema
en un entorno altamente controlado y reproducible, y para aprender cómo funcionan las redes.
Los usuarios notarán que el modelo disponible establecido en ns-3 se centra en modelar cómo Internet
los protocolos y las redes funcionan, pero ns-3 no se limita a los sistemas de Internet; varios usuarios
están usando ns-3 para modelar sistemas no basados ​​en Internet.

Existen muchas herramientas de simulación para estudios de simulación de redes. A continuación se muestran algunos
características distintivas de ns-3 a diferencia de otras herramientas.

· ns-3 está diseñado como un conjunto de bibliotecas que se pueden combinar entre sí y también con otras
bibliotecas de software externas. Si bien algunas plataformas de simulación brindan a los usuarios una
Entorno de interfaz gráfica de usuario única e integrada en el que se llevan a cabo todas las tareas.
fuera, ns-3 es más modular en este sentido. Varios animadores externos y análisis de datos.
y las herramientas de visualización se pueden utilizar con ns-3. Sin embargo, los usuarios deben esperar trabajar en
la línea de comandos y con herramientas de desarrollo de software C ++ y / o Python.

· ns-3 se utiliza principalmente en sistemas Linux, aunque existe soporte para FreeBSD, Cygwin
(para Windows), y el soporte nativo de Visual Studio de Windows está en proceso de ser
desarrollado.

· ns-3 no es un producto de software con soporte oficial de ninguna empresa. Apoyo para ns-3
se realiza con el mejor esfuerzo posible en la lista de correo ns-3-users.

Para ns-2 Usuarios
Para aquellos familiarizados con ns-2 (una herramienta popular que precedió ns-3), el más visible hacia afuera
cambiar al mudarse a ns-3 es la elección del lenguaje de secuencias de comandos. Programas en ns-2 están
con guión en OTcl y los resultados de las simulaciones se pueden visualizar utilizando Network Animator
nam. No es posible ejecutar una simulación en ns-2 puramente de C ++ (es decir, como main ()
programa sin OTcl). Además, algunos componentes de ns-2 están escritos en C ++ y
otros en OTcl. En ns-3, el simulador está escrito completamente en C ++, con Python opcional
fijaciones. Por tanto, los scripts de simulación se pueden escribir en C ++ o en Python. Nuevos animadores
y visualizadores están disponibles y en desarrollo actual. Ya que ns-3 genera pcap
archivos de seguimiento de paquetes, también se pueden utilizar otras utilidades para analizar los seguimientos. En esto
tutorial, primero nos concentraremos en crear scripts directamente en C ++ e interpretar los resultados
a través de archivos de seguimiento.

Pero también hay similitudes (ambos, por ejemplo, se basan en objetos C ++, y algunos
código de ns-2 ya ha sido portado a ns-3). Intentaremos resaltar las diferencias.
entre ns-2 y ns-3 a medida que avanzamos en este tutorial.

Una pregunta que a menudo escuchamos es "¿Debo usar ns-2 o mudarse a ns-3?" En esto
opinión del autor, a menos que el usuario de alguna manera tenga derecho a ns-2 (ya sea basado en
comodidad personal y conocimiento de ns-2, o basado en un modelo de simulación específico que
solo esta disponible en ns-2), un usuario será más productivo con ns-3 para el siguiente
razones:

· ns-3 se mantiene activamente con una lista de correo de usuarios activa y receptiva, mientras ns-2 is
solo se mantiene ligeramente y no ha experimentado un desarrollo significativo en su árbol de código principal
por mas de una decada.

· ns-3 proporciona funciones no disponibles en ns-2, como la ejecución de un código de implementación
entorno (que permite a los usuarios ejecutar código de implementación real en el simulador)

· ns-3 proporciona un nivel base de abstracción más bajo en comparación con ns-2, lo que le permite alinearse
mejor con la forma en que se ensamblan los sistemas reales. Algunas limitaciones encontradas en ns-2 (Tales como
soportando varios tipos de interfaces en los nodos correctamente) se han solucionado en ns-3.

ns-2 tiene un conjunto de módulos de contribución más diverso que el ns-3, debido a su largo
historia. Sin embargo, ns-3 tiene modelos más detallados en varias áreas populares de investigación
(incluidos los modelos sofisticados de LTE y WiFi) y su compatibilidad con el código de implementación
admite un espectro muy amplio de modelos de alta fidelidad. Los usuarios pueden sorprenderse al saber que
toda la pila de redes de Linux se puede encapsular en un ns-3 nodo, usando el Direct
Marco de ejecución de código (DCE). ns-2 los modelos a veces se pueden portar a ns-3, en particular
si se han implementado en C ++.

En caso de duda, una buena pauta sería mirar ambos simuladores (así como otros
simuladores), y en particular los modelos disponibles para su investigación, pero tenga en cuenta
que su experiencia puede ser mejor en el uso de la herramienta que se está desarrollando activamente y
mantenidons-3).

Contribuir
ns-3 es un simulador de investigación y educación, por y para la comunidad investigadora. Va a
confiar en las contribuciones continuas de la comunidad para desarrollar nuevos modelos, depurar o
mantener los existentes y compartir los resultados. Hay algunas políticas que esperamos sean
animar a las personas a contribuir a ns-3 como lo han hecho para ns-2:

· Licencias de código abierto basadas en compatibilidad GNU GPLv2

· wiki

· contribuido Código página, similar a ns-2El popular código contribuido página

· Abierto error rastreador

Sabemos que si está leyendo este documento, contribuir al proyecto es
probablemente no sea su principal preocupación en este momento, pero queremos que sepa que
contribuir está en el espíritu del proyecto y que incluso el acto de dejarnos una nota
sobre tu experiencia temprana con ns-3 (por ejemplo, "esta sección del tutorial no estaba clara ..."),
Se agradecen mucho los informes de documentación obsoleta, etc.

Tutorial Organización
El tutorial asume que los nuevos usuarios inicialmente pueden seguir una ruta como la siguiente:

· Intente descargar y crear una copia;

· Intente ejecutar algunos programas de muestra;

· Observe la salida de la simulación e intente ajustarla.

Como resultado, hemos intentado organizar el tutorial a lo largo de las amplias secuencias de
eventos.

RECURSOS


Los Webtracking
Hay varios recursos importantes de los cuales ns-3 el usuario debe ser consciente. La web principal
el sitio está ubicado en http://www.nsnam.org y proporciona acceso a información básica sobre el
ns-3 sistema. La documentación detallada está disponible en el sitio web principal en
http://www.nsnam.org/documentation/. También puede encontrar documentos relacionados con el sistema.
arquitectura de esta página.

Existe una Wiki que complementa la principal ns-3 sitio web que encontrará en
http://www.nsnam.org/wiki/. Allí encontrará preguntas frecuentes de usuarios y desarrolladores, así como
guías de resolución de problemas, código aportado por terceros, documentos, etc.

El código fuente se puede encontrar y navegar en http://code.nsnam.org/. Allí encontrarás
el árbol de desarrollo actual en el repositorio denominado ns-3-dev. Lanzamientos anteriores y
También se pueden encontrar allí repositorios experimentales de los desarrolladores principales.

mercurial
Los sistemas de software complejos necesitan alguna forma de administrar la organización y los cambios en el
código y documentación subyacentes. Hay muchas formas de realizar esta hazaña, y puede
He oído hablar de algunos de los sistemas que se utilizan actualmente para hacer esto. El concurrente
Version System (CVS) es probablemente el más conocido.

Los ns-3 El proyecto utiliza Mercurial como su sistema de gestión de código fuente. Aunque tu no
necesita saber mucho sobre Mercurial para poder completar este tutorial, le recomendamos
familiarizarse con Mercurial y usarlo para acceder al código fuente. Mercurial tiene un
sitio web en http://www.selenic.com/mercurial/, del cual puede obtener binario o fuente
versiones de este sistema de gestión de configuración de software (SCM). Selenic (el desarrollador
de Mercurial) también proporciona un tutorial en
http://www.selenic.com/mercurial/wiki/index.cgi/Tutorial/y una guía de inicio rápido en
http://www.selenic.com/mercurial/wiki/index.cgi/QuickStart/.

También puede encontrar información vital sobre el uso de Mercurial y ns-3 en lo principal ns-3 web
.

Waf
Una vez que haya descargado el código fuente en su sistema local, deberá compilarlo
fuente para producir programas utilizables. Al igual que en el caso de la gestión del código fuente, hay
Hay muchas herramientas disponibles para realizar esta función. Probablemente el más conocido de estos
herramientas es “piensen de nuevo sobre los incrementos de precio”. Además de ser el más conocido, “piensen de nuevo sobre los incrementos de precio” es probablemente el mas dificil
para usar en un sistema muy grande y altamente configurable. Debido a esto, muchas alternativas
ha sido desarrollado. Recientemente, estos sistemas se han desarrollado utilizando Python
idioma.

El sistema de compilación Waf se utiliza en el ns-3 proyecto. Es uno de la nueva generación de
Sistemas de compilación basados ​​en Python. No necesitará comprender Python para construir el
existente ns-3 .

Para aquellos interesados ​​en los detalles sangrientos de Waf, el sitio web principal se puede encontrar en
http://code.google.com/p/waf/.

Desarrollo Medio Ambiente
Como se mencionó anteriormente, las secuencias de comandos en ns-3 se realiza en C ++ o Python. La mayoría de ns-3 API es
disponible en Python, pero los modelos están escritos en C ++ en cualquier caso. Un trabajo
En este documento se asume el conocimiento de C ++ y conceptos orientados a objetos. Nosotros lo tomaremos
algo de tiempo para repasar algunos de los conceptos más avanzados o posiblemente un lenguaje desconocido
características, modismos y patrones de diseño tal como aparecen. No queremos que este tutorial
Sin embargo, se convierte en un tutorial de C ++, por lo que esperamos un dominio básico del lenguaje.
Hay una cantidad casi inimaginable de fuentes de información sobre C ++ disponibles en la
web o en forma impresa.

Si es nuevo en C ++, es posible que desee encontrar un libro o sitio web basado en tutoriales o libros de cocina.
y analizar al menos las características básicas del idioma antes de continuar. Para
ejemplo, este vídeo tutoriales.

Los ns-3 El sistema utiliza varios componentes de la "cadena de herramientas" de GNU para el desarrollo. A
La cadena de herramientas de software es el conjunto de herramientas de programación disponibles en el entorno dado. Para
una revisión rápida de lo que se incluye en la cadena de herramientas GNU, ver,
http://en.wikipedia.org/wiki/GNU_toolchain. ns-3 usa gcc, GNU binutils y gdb.
Sin embargo, no usamos las herramientas del sistema de construcción GNU, ni make ni autotools. Usamos Waf
para estas funciones.

Normalmente un ns-3 El autor funcionará en Linux o en un entorno similar a Linux. Para esos
ejecutando bajo Windows, existen entornos que simulan el entorno Linux para
varios grados. los ns-3 proyecto ha apoyado en el pasado (pero no en la actualidad)
desarrollo en el entorno Cygwin para estos usuarios. Ver http://www.cygwin.com/ for
detalles sobre la descarga y visite el ns-3 wiki para obtener más información sobre Cygwin y
ns-3. Actualmente, MinGW no es compatible oficialmente. Otra alternativa a Cygwin es
Instale un entorno de máquina virtual como un servidor VMware e instale un entorno virtual de Linux.
maquina

Enchufe Programación
Asumiremos una instalación básica con la API de Berkeley Sockets en los ejemplos utilizados en este
tutorial. Si es nuevo en los sockets, le recomendamos que revise la API y algunos usos comunes.
casos. Para obtener una buena descripción general de la programación de sockets TCP / IP, recomendamos TCP / IP Enchufes in
C, Donahoo y Calvert.

Hay un sitio web asociado que incluye la fuente de los ejemplos del libro, que
puedes encontrar en: http://cs.baylor.edu/~donahoo/practical/CSockets/.

Si comprende los primeros cuatro capítulos del libro (o para aquellos que no tienen acceso
a una copia del libro, los clientes y servidores de echo que se muestran en el sitio web anterior)
estar en buena forma para entender el tutorial. Hay un libro similar sobre multidifusión
Enchufes Multicast Enchufes Makofské y Almeroth. que cubre el material que puede necesitar
Comprenda si observa los ejemplos de multidifusión en la distribución.

CONSIGUIENDO EMPEZADO


Esta sección tiene como objetivo llevar a un usuario a un estado de trabajo comenzando con una máquina que
puede que nunca haya tenido ns-3 instalado. Cubre plataformas compatibles, requisitos previos, formas de
obtener ns-3, formas de construir ns-3y formas de verificar su compilación y ejecutar programas simples.

Descripción General
ns-3 está construido como un sistema de bibliotecas de software que funcionan en conjunto. Los programas de usuario pueden
escrito que se vincula con (o importa desde) estas bibliotecas. Los programas de usuario están escritos en
ya sea los lenguajes de programación C ++ o Python.

ns-3 se distribuye como código fuente, lo que significa que el sistema de destino debe tener un
entorno de desarrollo de software para construir las bibliotecas primero, luego construir el usuario
. ns-3 en principio, podrían distribuirse como bibliotecas preconstruidas para determinados
sistemas, y en el futuro puede distribuirse de esa manera, pero en la actualidad, muchos usuarios
realmente hacen su trabajo editando ns-3 en sí mismo, por lo que tener el código fuente para reconstruir
las bibliotecas es útil. Si alguien quisiera emprender el trabajo de hacer prefabricados
bibliotecas y paquetes para sistemas operativos, póngase en contacto con el correo de ns-developers
lista.

A continuación, veremos dos formas de descargar y compilar ns-3. El primero es
para descargar y crear una versión oficial desde el sitio web principal. El segundo es buscar
y crear copias de desarrollo de ns-3. Repasaremos ambos ejemplos, ya que las herramientas
involucrados son ligeramente diferentes.

Descarga de ns-3
Los ns-3 El sistema en su conjunto es un sistema bastante complejo y tiene una serie de dependencias de
otros componentes. Junto con los sistemas con los que probablemente tratará todos los días (el
GNU toolchain, Mercurial, un editor de texto) deberá asegurarse de que varios
hay bibliotecas adicionales en su sistema antes de continuar. ns-3 proporciona una wiki
página que incluye páginas con muchas sugerencias y consejos útiles. Una de esas páginas es la
Página "Instalación", http://www.nsnam.org/wiki/Installation.

La sección "Requisitos previos" de esta página wiki explica qué paquetes son necesarios para
apoyo común ns-3 opciones, y también proporciona los comandos utilizados para instalarlos para
variantes comunes de Linux. Los usuarios de Cygwin deberán usar el instalador Cygwin (si es un
Usuario de Cygwin, lo usó para instalar Cygwin).

Es posible que desee aprovechar esta oportunidad para explorar el ns-3 wiki un poco ya que realmente hay
una gran cantidad de información allí.

A partir de este punto, asumiremos que el lector está trabajando en Linux o en un
Entorno de emulación de Linux (Linux, Cygwin, etc.) y tiene la cadena de herramientas GNU instalada y
verificado junto con los requisitos previos mencionados anteriormente. También vamos a asumir que
tiene Mercurial y Waf instalados y ejecutándose en el sistema de destino.

Los ns-3 el código está disponible en los repositorios de Mercurial en el servidor http://code.nsnam.org.
También puede descargar una versión tarball en http://www.nsnam.org/release/o puedes trabajar
con repositorios que utilizan Mercurial. Recomendamos usar Mercurial a menos que haya una buena
razón para no hacerlo. Consulte el final de esta sección para obtener instrucciones sobre cómo obtener un tarball
en libertad.

La forma más sencilla de empezar a utilizar los repositorios de Mercurial es utilizar el ns-3-allinona
medio ambiente. Este es un conjunto de scripts que administra la descarga y construcción de
varios subsistemas de ns-3 para ti. Le recomendamos que comience su ns-3 trabajar en esto
ambiente.

Una práctica es crear un directorio llamado espacio de trabajo en el directorio de inicio de uno bajo el cual
se pueden mantener repositorios Mercurial locales. Cualquier nombre de directorio servirá, pero asumiremos
que espacio de trabajo se utiliza aquí (nota: repos también se puede utilizar en alguna documentación como
ejemplo de nombre de directorio).

Descarga de ns-3 Gracias a a bola de alquitrán
Un tarball es un formato particular de archivo de software en el que se agrupan varios archivos
juntos y el archivo posiblemente comprimido. ns-3 las versiones de software se proporcionan a través de un
tarball descargable. El proceso de descarga ns-3 a través de tarball es simple; tu solo
tienes que elegir una versión, descargarla y descomprimirla.

Supongamos que usted, como usuario, desea crear ns-3 en un directorio local llamado
espacio de trabajo. Si adopta el espacio de trabajo enfoque de directorio, puede obtener una copia de una versión
escribiendo lo siguiente en su shell de Linux (sustituya los números de versión apropiados,
por supuesto):

$ cd
$ mkdir espacio de trabajo
$ cd espacio de trabajo
$ wget http://www.nsnam.org/release/ns-allinone-3.22.tar.bz2
$ alquitrán xjf ns-allinone-3.22.tar.bz2

Si cambia al directorio ns-allinona-3.22 debería ver una serie de archivos:

$ls
hornear constantes.py ns-3.22 LÉAME
build.py netanim-3.105 pybindgen-0.16.0.886 util.py

Ahora está listo para construir la base. ns-3 distribución.

Descarga de ns-3 Gracias a Hornear
Bake es una herramienta para la integración y construcción distribuida, desarrollada para el ns-3 proyecto.
Bake se puede utilizar para obtener versiones de desarrollo del ns-3 software, y para descargar y
construir extensiones a la base ns-3 distribución, como la ejecución directa de código
entorno, base de simulación de red, capacidad para crear nuevos enlaces de Python y otros.

En ns-3 lanzamientos, Bake se ha incluido en el tarball de lanzamiento. La configuración
El archivo incluido en la versión publicada permitirá descargar cualquier software que
actual en el momento del lanzamiento. Es decir, por ejemplo, la versión de Bake que es
distribuido con el ns-3.21 la liberación se puede utilizar para buscar componentes para ese ns-3 ,
o anterior, pero no se puede utilizar para buscar componentes para versiones posteriores (a menos que el
hornearconf.xml el archivo está actualizado).

También puede obtener la copia más reciente de cocción escribiendo lo siguiente en su Linux
shell (suponiendo que haya instalado Mercurial):

$ cd
$ mkdir espacio de trabajo
$ cd espacio de trabajo
$ hg clon http://code.nsnam.org/bake

A medida que se ejecuta el comando hg (Mercurial), debería ver algo como lo siguiente
desplegado,

...
directorio de destino: hornear
solicitando todos los cambios
agregando conjuntos de cambios
agregando manifiestos
agregando cambios de archivo
se agregaron 339 conjuntos de cambios con 796 cambios en 63 archivos
actualizar a la sucursal predeterminada
45 archivos actualizados, 0 archivos fusionados, 0 archivos eliminados, 0 archivos sin resolver

Una vez que se completa el comando de clonación, debe tener un directorio llamado cocción, los contenidos
de los cuales debería tener un aspecto similar al siguiente:

$ls
hornear bakeconf.xml doc generate-binary.py TODO
prueba de ejemplos de bake.py

Observe que realmente acaba de descargar algunos scripts de Python y un módulo de Python llamado
cocción. El siguiente paso será utilizar esos scripts para descargar y compilar el ns-3
distribución de su elección.

Hay algunos objetivos de configuración disponibles:

1. ns-3.22: el módulo correspondiente al lanzamiento; descargará componentes similares
al tarball de lanzamiento.

2. ns-3-dev: un módulo similar pero usando el árbol de código de desarrollo

3. ns-allinona-3.22: el módulo que incluye otras características opcionales como hacer clic
enrutamiento, flujo abierto para ns-3y la base de simulación de red

4. ns-3-allinona: similar a la versión publicada del módulo allinone, pero para
código de desarrollo.

La instantánea de desarrollo actual (inédita) de ns-3 se puede encontrar en
http://code.nsnam.org/ns-3-dev/. Los desarrolladores intentan mantener estos repositorios en
estados de trabajo consistentes, pero se encuentran en un área de desarrollo con código inédito
presente, por lo que es posible que desee considerar quedarse con un comunicado oficial si no necesita
características recién introducidas.

Puede encontrar la última versión del código mediante la inspección de la lista de repositorios
o yendo a la "ns-3 Lanzamientos " página web y haciendo clic en el enlace de la última versión.
Continuaremos en este ejemplo de tutorial con ns-3.22.

Ahora vamos a utilizar la herramienta de horneado para bajar las distintas piezas de ns-3 Tú serás
utilizando. Primero, diremos unas palabras sobre la ejecución de hornear.

bake funciona descargando paquetes fuente en un directorio fuente e instalando
bibliotecas en un directorio de compilación. hornear se puede ejecutar haciendo referencia al binario, pero si uno
elige ejecutar bake desde fuera del directorio en el que se descargó, es aconsejable
para poner bake en su ruta, como se muestra a continuación (ejemplo de shell bash de Linux). Primero, cambia
en el directorio 'bake', y luego establezca las siguientes variables de entorno

$ exportar BAKE_HOME = `pwd`
$ export PATH = $ PATH: $ BAKE_HOME: $ BAKE_HOME / build / bin
$ export PYTHONPATH = $ PYTHONPATH: $ BAKE_HOME: $ BAKE_HOME / build / lib

Esto colocará el programa bake.py en la ruta del shell y permitirá que otros programas
busque ejecutables y bibliotecas creadas por bake. Aunque varios casos de uso de horneado no
requieren configurar PATH y PYTHONPATH como arriba, compilaciones completas de ns-3-allinone (con el
paquetes opcionales) normalmente lo hacen.

Ingrese al directorio del espacio de trabajo y escriba lo siguiente en su shell:

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

A continuación, le pediremos a Bake que compruebe si tenemos suficientes herramientas para descargar varios componentes.
Tipo:

$ ./bake.py cheque

Debería ver algo como lo siguiente,

> Python - OK
> Compilador GNU C ++ - OK
> Mercurial - OK
> CVS - OK
> GIT - OK
> Bazar - OK
> Herramienta de alquitrán - Aceptar
> Herramienta de descompresión - Aceptar
> Herramienta Unrar - falta
> Utilidad de compresión de datos 7z - OK
> Utilidad de compresión de datos XZ - OK
> Hacer - Aceptar
> cMake - OK
> herramienta de parche - OK
> herramienta de autoreconf - Aceptar

> Ruta de búsqueda de herramientas: /usr/lib64/qt-3.3/bin / usr / lib64 / ccache
/ usr / local / bin /compartimiento / usr / bin / usr / local / sbin / usr / sbin / sbin
/ inicio / tomh / bin bin

En particular, las herramientas de descarga como Mercurial, CVS, GIT y Bazaar son nuestras principales
preocupaciones en este punto, ya que nos permiten obtener el código. Por favor instale faltante
herramientas en esta etapa, de la manera habitual para su sistema (si puede), o póngase en contacto con
el administrador del sistema según sea necesario para instalar estas herramientas.

A continuación, intente descargar el software:

$ ./bake.py descargar

debería producir algo como:

>> Buscando pygoocanvas de dependencia del sistema - OK
>> Buscando la dependencia del sistema python-dev - OK
>> Buscando la dependencia del sistema pygraphviz - OK
>> Descargando pybindgen-0.16.0.886 - OK
>> Buscando dependencia del sistema g ++ - OK
>> Buscando dependencia del sistema qt4 - OK
>> Descargando netanim-3.105 - OK
>> Descargando ns-3.22 - OK

Lo anterior sugiere que se han descargado tres fuentes. Comprobar el fuente directorio
ahora y escriba ls; uno debería ver:

$ls
netanim-3.105 ns-3.22 pybindgen-0.16.0.886

Ahora está listo para construir el ns-3 distribución.

Contruyendo ns-3
Contruyendo con construir.py
Cuando trabaje desde un tarball publicado, la primera vez que compile el ns-3 proyecto que puedes
construir usando un programa de conveniencia que se encuentra en el allinone directorio. Este programa se llama
construir.py. Este programa obtendrá el proyecto configurado para usted en la forma más común
forma útil. Sin embargo, tenga en cuenta que la configuración más avanzada y el trabajo con ns-3 will
normalmente implican el uso del nativo ns-3 sistema de compilación, Waf, que se presentará más adelante en este
tutorial.

Si descargaste usando un tarball, deberías tener un directorio llamado algo como
ns-allinona-3.22 bajo su ~ / espacio de trabajo directorio. Escriba lo siguiente:

$ ./build.py --habilitar-ejemplos --habilitar-pruebas

Porque estamos trabajando con ejemplos y pruebas en este tutorial, y porque no son
construido por defecto en ns-3, los argumentos para build.py le dicen que los construya por nosotros. los
El programa también tiene por defecto la construcción de todos los módulos disponibles. Más tarde, puedes construir ns-3
sin ejemplos y pruebas, o eliminar los módulos que no son necesarios para su trabajo,
si lo desea.

Verá muchos mensajes de salida del compilador típicos que se muestran a medida que se construye el script de compilación
las diversas piezas que descargaste. Finalmente, debería ver lo siguiente:

Waf: Saliendo del directorio `/path/to/workspace/ns-allinone-3.22/ns-3.22/build '
'compilación' finalizada correctamente (6m25.032s)

Módulos construidos:
aplicaciones de antena aodv
tienda de configuración de edificios de puente
núcleo csma csma-diseño
energía dsdv dsr
Internet del monitor de flujo del dispositivo fd-net
malla lr-wpan lte
movilidad mpi netanim (sin Python)
red nix-vector-routing olsr
Propagación de diseño punto a punto punto a punto
estadísticas de espectro sixlowpan
prueba tap-bridge (sin Python) lectura de topología
uan onda de dispositivo de red virtual
wi-fi wimax

Módulos no construidos (consulte el tutorial ns-3 para obtener una explicación):
brite clic openflow
visualizador

Saliendo del directorio `./ns-3.22 '

Con respecto a la parte sobre módulos no construidos:

Módulos no construidos (consulte el tutorial ns-3 para obtener una explicación):
brite clic openflow
visualizador

Esto solo significa que algunos ns-3 Los módulos que tienen dependencias en bibliotecas externas no pueden
se han construido, o que la configuración solicitó específicamente no construirlos. Lo hace
no significa que el simulador no se haya construido correctamente o que proporcionará datos incorrectos
resultados para los módulos enumerados como en construcción.

Contruyendo con cocción
Si usó bake arriba para obtener el código fuente de los repositorios del proyecto, puede continuar
úsalo para construir ns-3. Tipo

$ ./bake.py compilación

y debería ver algo como:

>> Construyendo pybindgen-0.16.0.886 - OK
>> Construyendo netanim-3.105 - OK
>> Edificio ns-3.22 - OK

Insinuación: usted can also realizar ambas pasos, descargar y construimos by llamar 'bake.py desplegar'.

Si ocurre una falla, por favor, eche un vistazo a lo que dice el siguiente comando
usted; puede dar una pista sobre una dependencia faltante:

$ ./bake.py espectáculo

Esto mostrará una lista de las diversas dependencias de los paquetes que está intentando construir.

Contruyendo con Waf
Hasta este punto, hemos utilizado el construir.py guión, o el cocción herramienta para conseguir
comenzó con la construcción ns-3. Estas herramientas son útiles para construir ns-3 y apoyar
bibliotecas, y llaman a la ns-3 directorio para llamar a la herramienta de compilación de Waf para hacer el
edificio actual. La mayoría de los usuarios pasan rápidamente al uso de Waf directamente para configurar y
construimos ns-3. Entonces, para continuar, cambie su directorio de trabajo al ns-3 directorio
que ha construido inicialmente.

No es estrictamente necesario en este punto, pero será valioso tomar un pequeño desvío.
y observe cómo realizar cambios en la configuración del proyecto. Probablemente el mas
El cambio de configuración útil que puede realizar será crear la versión optimizada del
código. De forma predeterminada, ha configurado su proyecto para crear la versión de depuración. Vamos a contar
el proyecto para hacer una compilación optimizada. Explicarle a Waf que debería hacerlo optimizado.
compilaciones que incluyen los ejemplos y las pruebas, deberá ejecutar lo siguiente
comandos:

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

Esto ejecuta Waf fuera del directorio local (que se proporciona para su comodidad).
El primer comando para limpiar la compilación anterior no suele ser estrictamente necesario, pero
es una buena práctica (pero vea CONSTRUIR Perfiles, debajo); eliminará el construido previamente
bibliotecas y archivos de objetos que se encuentran en el directorio construir/. Cuando el proyecto se reconfigura
y el sistema de compilación verifica varias dependencias, debería ver un resultado que se ve
similar a lo siguiente:

Ajuste de la parte superior a:.
Proponiéndose: construir
Comprobando 'gcc' (compilador de c): / usr / bin / gcc
Comprobando la versión cc: 4.2.1
Comprobando 'g ++' (compilador de c ++): / usr / bin / g ++
La verificación de impulso incluye: 1_46_1
Comprobando boost libs: ok
Comprobando el enlace de refuerzo: ok
Comprobando la ubicación del clic: no encontrado
Comprobando el programa pkg-config: / sw / bin / pkg-config
Comprobando 'gtk + -2.0'> = 2.12: sí
Comprobando 'libxml-2.0'> = 2.7: sí
Comprobando el tipo uint128_t: no encontrado
Comprobando el tipo __uint128_t: sí
Comprobación de la implementación de alta precisión: entero de 128 bits (predeterminado)
Comprobando el encabezado stdint.h: sí
Comprobando el encabezado inttypes.h: sí
Comprobando el encabezado sys / inttypes.h: no encontrado
Comprobando el encabezado sys / types.h: sí
Comprobando el encabezado sys / stat.h: sí
Comprobando el encabezado dirent.h: sí
Comprobando el encabezado stdlib.h: sí
Comprobando la señal del encabezado. H: sí
Comprobando el encabezado pthread.h: sí
Comprobando el encabezado stdint.h: sí
Comprobando el encabezado inttypes.h: sí
Comprobando el encabezado sys / inttypes.h: no encontrado
Buscando biblioteca rt: no encontrado
Comprobando el encabezado netpacket / packet.h: no encontrado
Comprobando el encabezado sys / ioctl.h: sí
Comprobando el encabezado net / if.h: no encontrado
Comprobando el encabezado net / ethernet.h: sí
Comprobando encabezado linux / if_tun.h: no encontrado
Comprobando el encabezado netpacket / packet.h: no encontrado
Comprobando la ubicación del NSC: no encontrado
Comprobando 'mpic ++': sí
Comprobando 'sqlite3': sí
Comprobando encabezado linux / if_tun.h: no encontrado
Comprobando el programa sudo: / usr / bin / sudo
Comprobando el programa valgrind: / sw / bin / valgrind
Comprobando 'gsl': sí
Comprobando el indicador de compilación -Wno-error = deprecated-d ... soporte: ok
Comprobando el indicador de compilación -Wno-error = deprecated-d ... soporte: ok
Comprobando el indicador de compilación -fstrict-aliasing ... soporte: ok
Comprobando el indicador de compilación -fstrict-aliasing ... soporte: ok
Comprobando el indicador de compilación -Wstrict-aliasing ... soporte: ok
Comprobando el indicador de compilación -Wstrict-aliasing ... soporte: ok
Comprobando el programa doxygen: / usr / local / bin / doxygen
---- Resumen de las características opcionales del NS-3:
Perfil de compilación: depuración
Directorio de compilación: compilación
Enlaces de Python: habilitado
Integración BRITE: no habilitado (BRITE no habilitado (ver opción --con-brite))
Integración de NS-3 Click: no habilitado (nsclick no habilitado (vea la opción --with-nsclick))
GtkConfigStore: habilitado
XmlIo: habilitado
Primitivas de subprocesamiento: habilitado
Simulador en tiempo real: habilitado (librt no está disponible)
Dispositivo de red emulado: habilitado ( incluir no detectado)
Descriptor de archivo NetDevice: habilitado
Toque FdNetDevice: no habilitado (necesita linux / if_tun.h)
Emulación FdNetDevice: no habilitado (necesita netpacket / packet.h)
PlanetLab FdNetDevice: no habilitado (no se detectó el sistema operativo PlanetLab (consulte la opción --force-planetlab))
Base de simulación de red: no habilitado (NSC no encontrado (consulte la opción --con-nsc))
Soporte MPI: habilitado
Integración de NS-3 OpenFlow: no habilitado (no se encontraron las bibliotecas de refuerzo necesarias, faltan: sistema, señales, sistema de archivos)
Salida de datos de estadísticas de SQlite: habilitado
Tap Bridge: no habilitado ( incluir no detectado)
Visualizador de PyViz: habilitado
Use sudo para establecer el bit suid: no habilitado (opción --enable-sudo no seleccionada)
Pruebas de compilación: habilitadas
Ejemplos de compilación: habilitado
Biblioteca científica GNU (GSL): habilitada
'configurar' finalizó correctamente (1.944 s)

Tenga en cuenta la última parte de la salida anterior. Algunos ns-3 las opciones no están habilitadas de forma predeterminada o
requieren el apoyo del sistema subyacente para funcionar correctamente. Por ejemplo, para habilitar
XmlTo, la biblioteca libxml-2.0 debe encontrarse en el sistema. Si esta biblioteca no fuera
encontrado, el correspondiente ns-3 la función no estaría habilitada y un mensaje sería
desplegado. Tenga en cuenta además que hay una función para utilizar el programa sudo para configurar el suid
un poco de ciertos programas. Esto no está habilitado de forma predeterminada y, por lo tanto, se informa de esta función
como "no habilitado".

Ahora continúe y vuelva a la versión de depuración que incluye los ejemplos y las pruebas.

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

El sistema de compilación ahora está configurado y puede compilar las versiones de depuración del ns-3
programas simplemente escribiendo

$ ./waf

Está bien, lo siento, te hice construir el ns-3 parte del sistema dos veces, pero ahora sabe cómo
cambie la configuración y cree código optimizado.

El script build.py discutido anteriormente también admite el --habilitar-ejemplos y habilitar-pruebas
argumentos, pero en general, no admite directamente otras opciones de waf; por ejemplo, esto
no trabajará:

$ ./build.py --disable-python

resultará en

build.py: error: no existe tal opción: --disable-python

Sin embargo, el operador especial -- se puede utilizar para pasar opciones adicionales a waf, por lo que
en lugar de lo anterior, funcionará lo siguiente:

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

ya que genera el comando subyacente ./waf configurar --disable-python.

Aquí hay algunos consejos introductorios más sobre Waf.

Configurar vs CONSTRUIR
Algunos comandos de Waf solo son significativos durante la fase de configuración y algunos comandos son
válido en la fase de construcción. Por ejemplo, si desea utilizar las funciones de emulación de
ns-3, es posible que desee habilitar la configuración del bit suid usando sudo como se describe anteriormente. Esta
resulta ser un comando de tiempo de configuración, por lo que podría reconfigurar usando el
siguiente comando que también incluye los ejemplos y las pruebas.

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

Si hace esto, Waf habrá ejecutado sudo para cambiar los programas de creación de sockets del
código de emulación para ejecutar como root.

Hay muchas otras opciones de configuración y tiempo de compilación disponibles en Waf. Para explorar estos
opciones, escriba:

$ ./waf --ayuda

Usaremos algunos de los comandos relacionados con las pruebas en la siguiente sección.

CONSTRUIR Perfiles
Ya vimos cómo se puede configurar Waf para depurar or optimizado construye:

$ ./waf --build-profile = debug

También hay un perfil de construcción intermedio, ,. -d es sinónimo de
--construir perfil.

Por defecto, Waf coloca los artefactos de construcción en el construimos directorio. Puede especificar un
directorio de salida diferente con el --fuera opción, por ejemplo

$ ./waf configure --out = foo

Combinar esto con perfiles de compilación le permite cambiar entre las diferentes opciones de compilación
de forma limpia:

$ ./waf configure --build-profile = debug --out = build / debug
$ ./waf compilación
...
$ ./waf configure --build-profile = optimizado --out = build / optimizado
$ ./waf compilación
...

Esto le permite trabajar con varias compilaciones en lugar de sobrescribir siempre la última
construir. Cuando cambia, Waf solo compilará lo que tenga que hacer, en lugar de volver a compilar
todo.

Cuando cambia los perfiles de compilación de esta manera, debe tener cuidado de dar el mismo
parámetros de configuración cada vez. Puede ser conveniente definir algún entorno
variables para ayudarte a evitar errores:

$ export NS3CONFIG = "- enable-examples --enable-tests"
$ export NS3DEBUG = "- build-profile = debug --out = build / debug"
$ export NS3OPT == "- perfil de compilación = optimizado --out = compilación / optimizado"

$ ./waf configurar $ NS3CONFIG $ NS3DEBUG
$ ./waf compilación
...
$ ./waf configurar $ NS3CONFIG $ NS3OPT
$ ./waf compilación

Compiladores
En los ejemplos anteriores, Waf usa el compilador GCC C ++, g ++, para construir ns-3. Sin embargo,
es posible cambiar el compilador de C ++ utilizado por Waf definiendo el CXX entorno
variable. Por ejemplo, para usar el compilador Clang C ++, clang ++,

$ CXX = "clang ++" ./waf configure
$ ./waf compilación

También se puede configurar Waf para realizar una compilación distribuida con distrito En una forma similar:

$ CXX = "distcc g ++" ./waf configure
$ ./waf compilación

Más información sobre distrito y la compilación distribuida se puede encontrar en su Antecedentes página bajo
Sección de documentación.

Instalar
Waf se puede utilizar para instalar bibliotecas en varios lugares del sistema. El valor por defecto
La ubicación donde se compilan las bibliotecas y los ejecutables está en el construimos directorio, y porque
Waf conoce la ubicación de estas bibliotecas y ejecutables, no es necesario instalar
las bibliotecas en otros lugares.

Si los usuarios eligen instalar cosas fuera del directorio de compilación, los usuarios pueden emitir el
./waf instalar mando. De forma predeterminada, el prefijo para la instalación es / usr / local, asi que ./waf
instalar instalará programas en / usr / local / bin, bibliotecas en / usr / local / liby
encabezados en / usr / local / include. Los privilegios de superusuario suelen ser necesarios para instalar
el prefijo predeterminado, por lo que el comando típico sería sudo ./waf instalar. Al correr
programas con Waf, Waf primero preferirá usar bibliotecas compartidas en el directorio de compilación,
luego buscará bibliotecas en la ruta de la biblioteca configurada en el entorno local. Entonces
al instalar bibliotecas en el sistema, es una buena práctica comprobar que el
se están utilizando bibliotecas.

Los usuarios pueden optar por instalar con un prefijo diferente pasando el --prefijo opción en
configurar el tiempo, como:

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

Si más tarde, después de la compilación, el usuario emite el ./waf instalar comando, el prefijo / opt / local
se utilizará.

Los ./waf limpia El comando debe usarse antes de reconfigurar el proyecto si Waf será
utilizado para instalar cosas con un prefijo diferente.

En resumen, no es necesario llamar ./waf instalar que se utilizará ns-3. La mayoría de los usuarios no
Necesito este comando ya que Waf recogerá las bibliotecas actuales de la construimos directorio,
pero algunos usuarios pueden encontrarlo útil si su caso de uso implica trabajar con programas externos
de las ns-3 directorio.

Un Waf
Solo hay una secuencia de comandos Waf, en el nivel superior de la ns-3 árbol de origen. Mientras trabaja, usted
puede encontrarse pasando mucho tiempo en rasguño/, o en lo profundo src / ...y necesitando
invocar Waf. Podrías recordar dónde estás e invocar a Waf así:

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

pero eso se vuelve tedioso y propenso a errores, y hay mejores soluciones.

Si tienes el completo ns-3 repositorio esta pequeña joya es un comienzo:

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

Aún mejor es definir esto como una función de shell:

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

$ compilación de waff

Si solo tiene el tarball, una variable de entorno puede ayudar:

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

$ cd cero
$ compilación de waff

Puede ser tentador en un directorio de módulo agregar un trivial waf guión a lo largo de las líneas de
ejecutivo ../../waf. Por favor no lo hagas. Es confuso para los recién llegados, y cuando se hace mal,
conduce a errores sutiles de construcción. Las soluciones anteriores son el camino a seguir.

Pruebas ns-3
Puede ejecutar las pruebas unitarias del ns-3 distribución ejecutando el ./prueba.py -c centro
script:

$ ./test.py -c núcleo

Estas pruebas se ejecutan en paralelo por Waf. Eventualmente debería ver un informe que diga que

92 de 92 pruebas pasaron (92 pasaron, 0 fallaron, 0 fallaron, 0 errores de valgrind)

Este es el mensaje importante.

También verá el resultado resumido de Waf y el corredor de pruebas que ejecuta cada prueba,
que en realidad se verá algo así como:

Waf: Ingresando al directorio `/ ruta / a / espacio de trabajo / ns-3-allinone / ns-3-dev / build '
Waf: saliendo del directorio `/ ruta / a / espacio de trabajo / ns-3-allinone / ns-3-dev / build '
'compilación' finalizada correctamente (1.799 s)

Módulos construidos:
puente de aplicaciones aodv
haga clic en config-store core
csma diseño csma dsdv
monitor de flujo de energía emu
internet lte malla
movilidad mpi netanim
red nix-vector-enrutamiento ns3tcp
flujo abierto ns3wifi olsr
Propagación de diseño punto a punto punto a punto
estadísticas del espectro tap-bridge
herramientas de prueba de plantilla
topología-leer uan virtual-net-device
visualizador wifi wimax

APROBADO: TestSuite ns3-wifi-interferencia
APROBADO: histograma de TestSuite

...

APROBADO: objeto TestSuite
APROBADO: Generadores de números aleatorios TestSuite
92 de 92 pruebas pasaron (92 pasaron, 0 fallaron, 0 fallaron, 0 errores de valgrind)

Normalmente, los usuarios ejecutan este comando para verificar rápidamente que un ns-3 la distribución tiene
construido correctamente. (Tenga en cuenta el orden de APROBAR: ... las líneas pueden variar, lo cual está bien. Qué
importante es que la línea de resumen al final informe que se aprobaron todas las pruebas; ninguno falló o
se estrelló.)

Correr a Guión
Normalmente ejecutamos scripts bajo el control de Waf. Esto permite que el sistema de compilación garantice
que las rutas de las bibliotecas compartidas están configuradas correctamente y que las bibliotecas están disponibles en
tiempo de ejecución. Para ejecutar un programa, simplemente use el --correr opción en Waf. Ejecutemos el ns-3
equivalente al omnipresente programa hello world escribiendo lo siguiente:

$ ./waf --ejecutar hola-simulador

Waf primero verifica para asegurarse de que el programa esté construido correctamente y ejecuta una compilación si
requerido. Luego, Waf ejecuta el programa, que produce el siguiente resultado.

Hola simulador

¡Felicidades! ¡Ahora es un usuario de ns-3!

What do I do if I don't ver los ¿producción?

Si ve mensajes de Waf que indican que la compilación se completó correctamente, pero no
ver la salida "Hello Simulator", es probable que haya cambiado su modo de compilación a
optimizado en la categoría Industrial. Contruyendo con Waf sección, pero he perdido el cambio de nuevo a depurar modo.
Toda la salida de la consola usada en este tutorial usa un especial ns-3 componente de registro que
es útil para imprimir mensajes de usuario en la consola. La salida de este componente es
se desactiva automáticamente cuando se compila el código optimizado: está "optimizado". Si tu
no ve la salida "Hello Simulator", escriba lo siguiente:

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

para decirle a Waf que cree las versiones de depuración del ns-3 programas que incluyen los ejemplos
y pruebas. Aún debe crear la versión de depuración real del código escribiendo

$ ./waf

Ahora, si ejecuta el hola-simulador programa, debería ver la salida esperada.

Programa Argumentos
Para alimentar argumentos de línea de comando a un ns-3 programa usa este patrón:

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

Sustituya el nombre de su programa por , y los argumentos a favor .
--comando-plantilla El argumento de Waf es básicamente una receta para construir el
línea de comando que Waf debe usar para ejecutar el programa. Waf comprueba que la compilación es
complete, establece las rutas de la biblioteca compartida, luego invoca el ejecutable utilizando el
plantilla de línea de comando, insertando el nombre del programa para el %s marcador de posición. (Admito esto
es un poco incómodo, pero así es. ¡Parches bienvenidos!)

Otro ejemplo particularmente útil es ejecutar un conjunto de pruebas por sí solo. Supongamos que un
mi prueba El conjunto de pruebas existe (no lo hace). Arriba, usamos el ./prueba.py script para ejecutar un
una gran cantidad de pruebas en paralelo, invocando repetidamente el programa de prueba real, corredor de pruebas.
Invocar corredor de pruebas directamente para una sola prueba:

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

Esto pasa los argumentos al corredor de pruebas programa. Ya que mi prueba no existe, un
Se generará un mensaje de error. Para imprimir el disponible corredor de pruebas opciones:

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

Depuración
Correr ns-3 programas bajo el control de otra utilidad, como un depurador (por ejemplo: documentación que demuestre copropiedad de bienes, residencia compartida, recursos económicos combinados, declaraciones juradas de personas que lo conocen y que puedan dar fe de su relación y vida compartida, Decretos o certificados de adopción, Constancia de custodia legal de un niño adoptado durante un período de dos años gdb)
o comprobador de memoriapor ejemplo: documentación que demuestre copropiedad de bienes, residencia compartida, recursos económicos combinados, declaraciones juradas de personas que lo conocen y que puedan dar fe de su relación y vida compartida, Decretos o certificados de adopción, Constancia de custodia legal de un niño adoptado durante un período de dos años Valgrind), usas un similar --command-template = "..." .

Por ejemplo, para ejecutar su ns-3 programa hola-simulador con los argumentos bajo el
gdb depurador:

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

Observe que el ns-3 el nombre del programa va con el --correr argumento y la utilidad de control
(aquí gdb) es el primer token en el - plantilla de comando argumento. La --argumentos decirles gdb
que el resto de la línea de comando pertenece al programa "inferior". (Algunos gdb's
no entiendo el --argumentos característica. En este caso, omita los argumentos del programa del
--comando-plantilla, Y utilizar el gdb comando para reinventar la industria logística y redefinir las soluciones ecológicas para reinventar la industria logística y redefinir las soluciones ecológicas. args.)

Podemos combinar esta receta y la anterior para ejecutar una prueba bajo el depurador:

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

Acoplar Directory
Waf debe ejecutarse desde su ubicación en la parte superior de la ns-3 árbol. Esto se convierte en el trabajo
directorio donde se escribirán los archivos de salida. Pero, ¿y si quieres mantener esos fuera de lugar?
los ns-3 árbol de origen? Utilizar el --cwd argumento:

$ ./waf --cwd = ...

Puede ser más conveniente comenzar con su directorio de trabajo donde desea la salida
archivos, en cuyo caso un poco de indirección puede ayudar:

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

Este adorno de la versión anterior guarda el directorio de trabajo actual, cdes para
el directorio de Waf, luego le indica a Waf que cambie el directorio de trabajo back a los salvados
directorio de trabajo actual antes de ejecutar el programa.

CONCEPTUAL Descripción


Lo primero que debemos hacer antes de comenzar a mirar o escribir ns-3 el código es para
explicar algunos conceptos básicos y abstracciones del sistema. Mucho de esto puede parecer
transparentemente obvio para algunos, pero recomendamos tomarse el tiempo para leer este
sección solo para asegurarse de que está comenzando sobre una base firme.

Clave Abstracciones
En esta sección, revisaremos algunos términos que se usan comúnmente en redes, pero tienen un
significado específico en ns-3.

Nodo
En la jerga de Internet, un dispositivo informático que se conecta a una red se denomina fortaleza or
a veces un final te. Porque ns-3 es un del sistema, simulador, no específicamente un
Internet simulador, intencionalmente no utilizamos el término host ya que está muy
asociados con Internet y sus protocolos. En cambio, usamos un término más genérico también
utilizado por otros simuladores que se origina en la teoría de grafos --- el nodo.

In ns-3 la abstracción básica del dispositivo informático se llama nodo. Esta abstracción es
representado en C ++ por la clase Nodo. Nodo La clase proporciona métodos para administrar el
representaciones de dispositivos informáticos en simulaciones.

Deberías pensar en un Nodo como una computadora a la que agregará funcionalidad. Uno agrega
cosas como aplicaciones, pilas de protocolos y tarjetas periféricas con sus asociados
controladores para permitir que la computadora realice un trabajo útil. Usamos el mismo modelo básico en ns-3.

Nueva Solicitud de Empleo
Por lo general, el software de computadora se divide en dos grandes clases. System Software organiza
varios recursos informáticos como la memoria, los ciclos del procesador, el disco, la red, etc.
según algún modelo informático. El software del sistema generalmente no usa esos recursos
para completar tareas que beneficien directamente a un usuario. Un usuario normalmente ejecutaría un Práctica
que adquiere y utiliza los recursos controlados por el software del sistema para lograr algunos
Gol.

A menudo, la línea de separación entre el sistema y el software de aplicación se realiza en el
cambio de nivel de privilegio que ocurre en las trampas del sistema operativo. En ns-3 no hay real
concepto de sistema operativo y especialmente ningún concepto de niveles de privilegios o llamadas al sistema.
Sin embargo, tenemos la idea de una aplicación. Así como las aplicaciones de software se ejecutan en
computadoras para realizar tareas en el "mundo real", ns-3 las aplicaciones se ejecutan en ns-3 Nodes a
conducir simulaciones en el mundo simulado.

In ns-3 la abstracción básica para un programa de usuario que genera alguna actividad para ser
simulado es la aplicación. Esta abstracción está representada en C ++ por la clase
Nueva Solicitud de Empleo. Nueva Solicitud de Empleo La clase proporciona métodos para gestionar las representaciones de
nuestra versión de aplicaciones a nivel de usuario en simulaciones. Se espera que los desarrolladores
especializarse en Nueva Solicitud de Empleo clase en el sentido de la programación orientada a objetos para crear nuevos
aplicaciones. En este tutorial, usaremos especializaciones de clase. Nueva Solicitud de Empleo , que son
UdpEchoClientApplicationUdpEchoClientApplication y UdpEchoServerApplicationUdpEchoServerApplication. Como era de esperar, estos
Las aplicaciones componen un conjunto de aplicaciones cliente / servidor que se utiliza para generar y hacer eco
paquetes de red

Channel
En el mundo real, uno puede conectar una computadora a una red. A menudo, los medios sobre los que
Los flujos de datos en estas redes se denominan canales. Cuando conecta su cable Ethernet a
el enchufe en la pared, está conectando su computadora a una comunicación Ethernet
canal. En el mundo simulado de ns-3, uno conecta un Nodo a un objeto que representa un
canal de comunicación. Aquí, la abstracción básica de la subred de comunicación se denomina
canal y está representado en C ++ por la clase Channel.

Los Channel La clase proporciona métodos para administrar objetos de subred de comunicación y
conectando nodos a ellos. Canales Los desarrolladores también pueden especializarse en el objeto.
sentido de programación orientado. A Channel La especialización puede modelar algo tan simple como
cable. El especializado Channel también puede modelar cosas tan complicadas como una Ethernet grande
interruptor, o espacio tridimensional lleno de obstrucciones en el caso de las redes inalámbricas.

Usaremos versiones especializadas del Channel , que son CsmaCanal, PuntoAPuntoCanal
y Canal Wifi en este tutorial. los CsmaCanal, por ejemplo, modela una versión de un
subred de comunicación que implementa un portador sentido una variedad de la máquina la comunicación
medio. Esto nos da una funcionalidad similar a la de Ethernet.

Red Device
Solía ​​ocurrir que si deseaba conectar una computadora a una red, tenía que
comprar un tipo específico de cable de red y un dispositivo de hardware llamado (en terminología de PC) un
periférico tarjeta que necesitaba ser instalado en su computadora. Si la tarjeta periférica
implementado alguna función de red, se llamaban tarjetas de interfaz de red, o NIC.
Hoy en día, la mayoría de las computadoras vienen con el hardware de interfaz de red integrado y los usuarios no ven
estos bloques de construcción.

Una NIC no funcionará sin un controlador de software para controlar el hardware. En Unix (o
Linux), una pieza de hardware periférico se clasifica como dispositivo. Los dispositivos están controlados
usando dispositivo conductoresy los dispositivos de red (NIC) se controlan mediante del sistema, dispositivo
conductores colectivamente conocido como red Médicos. En Unix y Linux te refieres a estos net
dispositivos por nombres como eth0.

In ns-3 los red dispositivo La abstracción cubre tanto el controlador de software como la simulación
hardware. Un dispositivo de red está "instalado" en un Nodo para habilitar el Nodo a
comunicarse con otros Nodes en la simulación a través de Canales. Al igual que en una computadora real,
a Nodo puede estar conectado a más de una Channel a través de múltiples Dispositivos de red.

La abstracción del dispositivo de red está representada en C ++ por la clase dispositivo de red. dispositivo de red
La clase proporciona métodos para administrar conexiones a Nodo y Channel objetos; y tal vez
especializado por desarrolladores en el sentido de la programación orientada a objetos. Usaremos el
varias versiones especializadas del dispositivo de red , que son Dispositivo CsmaNet, Dispositivo de red punto a punto,
y WifiRedDispositivo en este tutorial. Al igual que una NIC Ethernet está diseñada para funcionar con un
Red Ethernet, la Dispositivo CsmaNet está diseñado para trabajar con un CsmaCanal; El
Dispositivo de red punto a punto está diseñado para trabajar con un PuntoAPuntoCanal y Wi-FiNetNevice
está diseñado para trabajar con un Canal Wifi.

topología Ayudantes
En una red real, encontrará equipos host con NIC agregadas (o integradas). En ns-3 we
diría que encontraras Nodes con adjunto Dispositivos de red. En una gran red simulada
tendrá que organizar muchas conexiones entre Nodes, Dispositivos de red y Canales.

Desde que se conectó Dispositivos de red a Nodes, Dispositivos de red a Canales, asignando direcciones IP,
etc., son tareas tan comunes en ns-3, proporcionamos lo que llamamos topología ayudantes para hacer esto
tan fácil como sea posible. Por ejemplo, pueden ser necesarios muchos ns-3 operaciones centrales para
crear un NetDevice, agregar una dirección MAC, instalar ese dispositivo de red en un Nodo, configura el
pila de protocolos del nodo, y luego conecte el dispositivo de red a una Channel. Incluso más operaciones
Sería necesario conectar varios dispositivos en canales multipunto y luego conectar
redes individuales juntas en internetworks. Proporcionamos objetos auxiliares de topología que
combine esas muchas operaciones distintas en un modelo fácil de usar para su conveniencia.

A Primer nombre ns-3 Guión
Si descargó el sistema como se sugirió anteriormente, tendrá una versión de ns-3 en un parche de
directorio llamado repos en su directorio personal. Cambie a ese directorio de versiones y
debería encontrar una estructura de directorio similar a la siguiente:

AUTORES ejemplos scratch utils waf.bat *
enlaces LICENCIA src utils.py waf-tools
compilar ns3 test.py * utils.pyc wscript
CHANGES.html LÉAME testpy-salida VERSIÓN wutils.py
doc RELEASE_NOTES testpy.supp waf * wutils.pyc

Cambia al ejemplos / tutorial directorio. Debería ver un archivo llamado primero.cc situados
allí. Este es un script que creará un enlace simple punto a punto entre dos nodos.
y hacer eco de un solo paquete entre los nodos. Echemos un vistazo a esa línea de guión por
línea, así que adelante y abre primero.cc en tu editor favorito.

Repetitivo
La primera línea del archivo es una línea de modo emacs. Esto le dice a emacs sobre el formato.
convenciones (estilo de codificación) que usamos en nuestro código fuente.

/ * - * - Modo: C ++; estilo-archivo-c: "gnu"; indent-tabs-mode: nil; - * - * /

Este es siempre un tema algo controvertido, por lo que es mejor que lo saquemos del camino.
inmediatamente. La ns-3 proyecto, como la mayoría de los grandes proyectos, ha adoptado un estilo de codificación para
que deben cumplir todos los códigos aportados. Si desea contribuir con su código al
proyecto, eventualmente tendrá que ajustarse a la ns-3 estándar de codificación como se describe en
el archivo doc / codingstd.txt o se muestra en la página web del proyecto aquí.

Le recomendamos que, bueno, se acostumbre a la apariencia de ns-3 codificar y adoptar
este estándar siempre que esté trabajando con nuestro código. Todo el equipo de desarrollo y
los contribuyentes lo han hecho con varias quejas. La línea de modo emacs arriba
hace que sea más fácil obtener el formato correcto si usa el editor emacs.

Los ns-3 El simulador tiene la licencia GNU General Public License. Verás el
jerga legal GNU apropiada al comienzo de cada archivo en el ns-3 distribución. A menudo tu
verá un aviso de derechos de autor para una de las instituciones involucradas en el ns-3 proyecto arriba
el texto de la GPL y un autor que se enumera a continuación.

/*
* Este programa es software gratuito; puedes redistribuirlo y / o modificarlo
* bajo los términos de la GNU General Public License versión 2 como
* publicado por la Free Software Foundation;
*
* Este programa se distribuye con la esperanza de que sea de utilidad,
* pero SIN NINGUNA GARANTÍA; sin siquiera la garantía implícita de
* COMERCIABILIDAD o APTITUD PARA UN PROPÓSITO PARTICULAR. Ver el
* Licencia pública general GNU para más detalles.
*
* Debería haber recibido una copia de la Licencia Pública General GNU
* junto con este programa; si no, escriba al software libre
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 EE. UU.
*/

Módulo Incluye
El código propiamente dicho comienza con una serie de declaraciones de inclusión.

#include "ns3 / core-module.h"
#include "ns3 / network-module.h"
#include "ns3 / internet-module.h"
#include "ns3 / módulo-punto-a-punto.h"
#include "ns3 / applications-module.h"

Para ayudar a nuestros usuarios de scripts de alto nivel a lidiar con la gran cantidad de archivos de inclusión presentes en
el sistema, agrupamos incluye según módulos relativamente grandes. Proporcionamos un solo
archivo de inclusión que cargará de forma recursiva todos los archivos de inclusión utilizados en cada módulo.
En lugar de tener que buscar exactamente qué encabezado necesita, y posiblemente tener que obtener un
número de dependencias correcto, le damos la capacidad de cargar un grupo de archivos en un gran
granularidad. Este no es el enfoque más eficiente, pero ciertamente hace que la escritura
guiones mucho más fáciles.

Cada uno de los ns-3 incluir archivos se coloca en un directorio llamado ns3 (debajo de la construcción
directorio) durante el proceso de compilación para ayudar a evitar incluir colisiones de nombres de archivos. los
ns3 / core-module.h el archivo corresponde al módulo ns-3 que encontrará en el directorio
src / core en la distribución de la versión descargada. Si incluye este directorio,
encontrar una gran cantidad de archivos de encabezado. Cuando haces una compilación, Waf colocará un encabezado público
archivos en un ns3 directorio bajo el apropiado construir / depurar or construir / optimizado directorio
dependiendo de su configuración. Waf también generará automáticamente un módulo incluido
file para cargar todos los archivos de encabezado públicos.

Como está, por supuesto, siguiendo este tutorial religiosamente, ya lo habrá hecho.
a

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

con el fin de configurar el proyecto para realizar versiones de depuración que incluyan ejemplos y pruebas.
También habrás hecho un

$ ./waf

para construir el proyecto. Así que ahora si miras en el directorio ../../construir/depurar/ns3 usted podrá
busque los archivos de inclusión de cuatro módulos que se muestran arriba. Puedes echar un vistazo al contenido de
estos archivos y descubren que incluyen todos los archivos de inclusión públicos en sus
respectivos módulos.

Ns3 Espacio de nombres
La siguiente línea en el primero.cc script es una declaración de espacio de nombres.

usando el espacio de nombres ns3;

Los ns-3 El proyecto se implementa en un espacio de nombres de C ++ llamado ns3. Esto agrupa a todos
ns-3-declaraciones relacionadas en un ámbito fuera del espacio de nombres global, que esperamos ayuden
con integración con otro código. El C ++ usando declaración introduce el ns-3 espacio de nombres
en la región declarativa actual (global). Esta es una forma elegante de decir que después
esta declaración, no tendrá que escribir ns3 :: operador de resolución de alcance antes de todos los
los ns-3 código para poder usarlo. Si no está familiarizado con los espacios de nombres, consulte
casi cualquier tutorial de C ++ y compare el ns3 espacio de nombres y uso aquí con instancias del
enfermedades de transmisión sexual espacio de nombres y el usando espacio de nombres estándar; declaraciones que encontrará a menudo en las discusiones
of cout y arroyos.

Inicio de sesión
La siguiente línea del script es la siguiente,

NS_LOG_COMPONENT_DEFINE ("EjemploPrimerScript");

Usaremos esta declaración como un lugar conveniente para hablar sobre nuestra documentación de Doxygen
sistema. Si miras el sitio web del proyecto, ns-3 Antecedentes, encontrará un enlace a
"Documentación" en la barra de navegación. Si selecciona este enlace, será redirigido a nuestro
página de documentación. Hay un enlace a "Última versión" que lo llevará a la
documentación para la última versión estable de ns-3. Si selecciona la "API
Documentación", se le llevará a la ns-3 Página de documentación de la API.

A lo largo del lado izquierdo, encontrará una representación gráfica de la estructura del
documentación. Un buen lugar para comenzar es el NS-3 Módulos "libro" en el ns-3 navegación
árbol. si expandes Módulos verás una lista de ns-3 documentación del módulo. los
El concepto de módulo aquí se relaciona directamente con los archivos de inclusión del módulo discutidos anteriormente. los
ns-3 subsistema de registro se discute en el C + + Construcciones Usado by Todo Módulos sección, entonces
continúe y amplíe ese nodo de documentación. Ahora, expanda el Depuración libro y luego
seleccionar el Inicio de sesión .

Ahora debería estar mirando la documentación de Doxygen para el módulo de registro. En el
lista de #definir's en la parte superior de la página, verá la entrada para
NS_LOG_COMPONENT_DEFINE. Antes de saltar, probablemente sería bueno buscar el
"Descripción detallada" del módulo de registro para tener una idea de la operación general. Tú
puede desplazarse hacia abajo o seleccionar el enlace "Más..." debajo del diagrama de colaboración para hacer
esta.

Una vez que tenga una idea general de lo que está pasando, continúe y eche un vistazo a las
NS_LOG_COMPONENT_DEFINE documentación. No duplicaré la documentación aquí, pero para
resume, esta línea declara un componente de registro llamado PrimerScriptEjemplo que permite
le permite habilitar y deshabilitar el registro de mensajes de la consola por referencia al nombre.

Main Función
Las siguientes líneas del script que encontrarás son,

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

Esta es solo la declaración de la función principal de su programa (script). Al igual que en
cualquier programa C++, necesita definir una función principal que será la primera función ejecutada.
No hay nada especial aquí. Tu ns-3 script es solo un programa C++.

La siguiente línea establece la resolución de tiempo en un nanosegundo, que resulta ser la predeterminada
valor:

Hora::EstablecerResolución (Hora::NS);

La resolución es el valor de tiempo más pequeño que se puede representar (así como el valor más pequeño
diferencia representable entre dos valores de tiempo). Puedes cambiar la resolución exactamente
una vez. El mecanismo que permite esta flexibilidad tiene un poco de memoria, por lo que una vez que el
La resolución se ha establecido explícitamente, liberamos la memoria, evitando más actualizaciones.
(Si no establece la resolución explícitamente, se establecerá de forma predeterminada en un nanosegundo y el
la memoria se liberará cuando comience la simulación.)

Las siguientes dos líneas del script se usan para habilitar dos componentes de registro que se construyen
en las aplicaciones Echo Client y Echo Server:

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

Si ha leído la documentación del componente Logging, habrá visto que hay
hay una serie de niveles de detalle/verbosidad de registro que puede habilitar en cada componente.
Estas dos líneas de código habilitan el registro de depuración en el nivel INFO para clientes de eco y
servidores. Esto hará que la aplicación imprima mensajes a medida que se envían los paquetes.
y recibido durante la simulación.

Ahora nos dirigiremos directamente al negocio de crear una topología y ejecutar una simulación.
Usamos los objetos auxiliares de topología para hacer este trabajo lo más fácil posible.

topología Ayudantes
Contenedor de nodo
Las próximas dos líneas de código en nuestra secuencia de comandos en realidad crearán el ns-3 Nodo objetos que
representará a las computadoras en la simulación.

nodos NodeContainer;
nodos.Crear (2);

Busquemos la documentación para el Contenedor de nodo clase antes de continuar. De otra manera
acceder a la documentación de una clase determinada es a través de la Clases pestaña en el Doxygen
paginas Si aún tiene el Doxygen a mano, simplemente desplácese hasta la parte superior de la página y
seleccionar el Clases pestaña. Debería ver aparecer un nuevo conjunto de pestañas, una de las cuales es Clase
Lista. Debajo de esa pestaña, verá una lista de todos los ns-3 clases Desplácese hacia abajo,
buscando ns3::Contenedor de nodo. Cuando encuentre la clase, continúe y selecciónela para ir a
la documentación de la clase.

Puede recordar que una de nuestras abstracciones clave es la Nodo. Esto representa una computadora.
a los que vamos a agregar cosas como pilas de protocolos, aplicaciones y periféricos
tarjetas los Contenedor de nodo El asistente de topología proporciona una manera conveniente de crear, administrar y
acceder a cualquier Nodo objetos que creamos para ejecutar una simulación. La primera línea de arriba
simplemente declara un NodeContainer al que llamamos nodos. La segunda línea llama al Crear
método en el nodos objeto y le pide al contenedor que cree dos nodos. Como se describe en
el Doxygen, el contenedor llama hacia abajo en el ns-3 sistema adecuado para crear dos Nodo
objetos y almacena punteros a esos objetos internamente.

Los nodos tal como están en el script no hacen nada. El siguiente paso en la construcción de un
topología es conectar nuestros nodos en una red. La forma más simple de red que
El soporte es un único enlace punto a punto entre dos nodos. Construiremos uno de esos
enlaces aquí.

Ayudante punto a punto
Estamos construyendo un enlace punto a punto y, en un patrón que será bastante
familiar para usted, usamos un objeto de ayuda de topología para hacer el trabajo de bajo nivel requerido para poner
el enlace juntos. Recuerde que dos de nuestras abstracciones clave son las dispositivo de red y la
Channel. En el mundo real, estos términos corresponden aproximadamente a tarjetas periféricas y
cables de red Por lo general, estas dos cosas están íntimamente unidas y uno no puede
espere intercambiar, por ejemplo, dispositivos Ethernet y canales inalámbricos. Nuestra topología
Los ayudantes siguen este acoplamiento íntimo y, por lo tanto, usarán un solo
Ayudante punto a punto para configurar y conectar ns-3 Dispositivo de red punto a punto y
PuntoAPuntoCanal objetos en este script.

Las siguientes tres líneas en el guión son,

PuntoAPuntoAyudante puntoAPunto;
pointToPoint.SetDeviceAttribute ("Velocidad de datos", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Retraso", StringValue ("2ms"));

La primera linea

PuntoAPuntoAyudante puntoAPunto;

instancia un Ayudante punto a punto objeto en la pila. Desde una perspectiva de alto nivel, la
Proxima linea,

pointToPoint.SetDeviceAttribute ("Velocidad de datos", StringValue ("5Mbps"));

indica al Ayudante punto a punto objeto utilizar el valor "5Mbps" (cinco megabits por segundo) como
el "DataRate" cuando crea un Dispositivo de red punto a punto objeto.

Desde una perspectiva más detallada, la cadena "DataRate" corresponde a lo que llamamos un
Atributo de las Dispositivo de red punto a punto. Si miras el Doxygen para la clase
ns3::Dispositivo de red punto a punto y encontrar la documentación para el ObtenerIdTipo método, lo harás
encontrar una lista de Atributos definido para el dispositivo. Entre estos se encuentra el "DataRate"
Atributo. Más visible para el usuario ns-3 Los objetos tienen listas similares de Atributos. usamos esto
mecanismo para configurar fácilmente simulaciones sin recompilar como verá en un
sección siguiente.

Similar a "DataRate" en el Dispositivo de red punto a punto encontrará un "Retraso" Atributo
asociado con el PuntoAPuntoCanal. la línea final,

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

indica al Ayudante punto a punto usar el valor "2ms" (dos milisegundos) como el valor de la
retardo de transmisión de cada canal punto a punto que crea posteriormente.

NetDeviceContainerNetDeviceContainer
En este punto del guión, tenemos un Contenedor de nodo que contiene dos nodos. Tenemos una
Ayudante punto a punto que está preparado y listo para hacer Dispositivos de red punto a punto y alambre
PuntoAPuntoCanal objetos entre ellos. Así como usamos el Contenedor de nodo topología
objeto auxiliar para crear el Nodes para nuestra simulación, le preguntaremos al Ayudante punto a punto
para hacer el trabajo involucrado en la creación, configuración e instalación de nuestros dispositivos para nosotros. Nosotros
necesitará tener una lista de todos los objetos de NetDevice que se crean, por lo que usamos un
NetDeviceContainer para contenerlos tal como usamos un NodeContainer para contener los nodos que
creado. Las siguientes dos líneas de código,

dispositivos NetDeviceContainer;
dispositivos = pointToPoint.Install (nodos);

terminará de configurar los dispositivos y el canal. La primera línea declara el dispositivo.
contenedor mencionado anteriormente y el segundo hace el trabajo pesado. los Instalar método de
los Ayudante punto a punto toma una Contenedor de nodo como parámetro. Internamente, un
NetDeviceContainerNetDeviceContainer es creado. Para cada nodo en el Contenedor de nodo (debe haber exactamente
dos para un enlace punto a punto) Dispositivo de red punto a punto se crea y se guarda en el dispositivo
envase. A PuntoAPuntoCanal se crea y los dos Dispositivos de red punto a punto están
adjunto. Cuando los objetos son creados por el Ayudante punto a punto, la Atributos previamente
establecidos en el ayudante se utilizan para inicializar el correspondiente Atributos en lo creado
objetos.

Después de ejecutar el pointToPoint.Instalar (nodos) llamada tendremos dos nodos, cada uno con un
dispositivo de red punto a punto instalado y un solo canal punto a punto entre ellos.
Ambos dispositivos estarán configurados para transmitir datos a cinco megabits por segundo en el
canal que tiene un retardo de transmisión de dos milisegundos.

Ayudante de pila de Internet
Ahora tenemos nodos y dispositivos configurados, pero no tenemos ninguna pila de protocolos instalada
en nuestros nodos. Las próximas dos líneas de código se encargarán de eso.

pila InternetStackHelper;
stack.Install (nodos);

Los Ayudante de pila de Internet es un ayudante de topología que es para las pilas de Internet lo que
Ayudante punto a punto es para dispositivos de red punto a punto. los Instalar el método toma un
Contenedor de nodo como parámetro. Cuando se ejecute, instalará una pila de Internet
(TCP, UDP, IP, etc.) en cada uno de los nodos del contenedor de nodos.

Ayudante de direcciones Ipv4
A continuación, debemos asociar los dispositivos en nuestros nodos con direcciones IP. Proporcionamos un
asistente de topología para administrar la asignación de direcciones IP. La única API visible para el usuario es
establecer la dirección IP base y la máscara de red para usar al realizar la dirección real
asignación (que se realiza en un nivel inferior dentro del ayudante).

Las siguientes dos líneas de código en nuestro script de ejemplo, primero.cc,

dirección Ipv4AddressHelper;
dirección.SetBase ("10.1.1.0", "255.255.255.0");

declarar un objeto auxiliar de dirección y decirle que debe comenzar a asignar direcciones IP
de la red 10.1.1.0 utilizando la máscara 255.255.255.0 para definir los bits asignables. Por
por defecto, las direcciones asignadas comenzarán en uno y aumentarán monótonamente, por lo que la primera
dirección asignada desde esta base será 10.1.1.1, seguida de 10.1.1.2, etc. La baja
nivel ns-3 el sistema realmente recuerda todas las direcciones IP asignadas y generará una
error fatal si accidentalmente hace que la misma dirección se genere dos veces (que es un
error muy difícil de depurar, por cierto).

La siguiente línea de código,

Ipv4InterfaceContainer interfaces = dirección. Asignar (dispositivos);

realiza la asignación de dirección real. En ns-3 hacemos la asociación entre una IP
dirección y un dispositivo usando un Interfaz Ipv4 objeto. Así como a veces necesitamos una lista de
dispositivos de red creados por un ayudante para referencia futura, a veces necesitamos una lista de
Interfaz Ipv4 objetos. La Ipv4InterfazContenedor proporciona esta funcionalidad.

Ahora tenemos una red punto a punto construida, con pilas instaladas y direcciones IP
asignado. Lo que necesitamos en este punto son aplicaciones para generar tráfico.

Aplicaciones
Otra de las abstracciones centrales del sistema ns-3 es la Nueva Solicitud de Empleo. En este
guión utilizamos dos especializaciones del núcleo ns-3 clase Nueva Solicitud de Empleo , que son
UdpEchoServerApplicationUdpEchoServerApplication y UdpEchoClientApplicationUdpEchoClientApplication. Tal como lo hemos hecho en nuestro anterior
explicaciones, usamos objetos auxiliares para ayudar a configurar y administrar los objetos subyacentes.
Aquí usamos Ayudante UdpEchoServer y UdpEchoClientHelper objetos para hacernos la vida más fácil.

Ayudante UdpEchoServer
Las siguientes líneas de código en nuestro script de ejemplo, primero.cc, se utilizan para configurar un eco UDP
aplicación de servidor en uno de los nodos que hemos creado previamente.

UdpEchoServerHelper echoServer (9);

ApplicationContainer serverApps = echoServer.Install (nodos.Get (1));
serverApps.Start (Segundos (1.0));
serverApps.Stop (Segundos (10.0));

La primera línea de código en el fragmento anterior declara el Ayudante UdpEchoServer. Como siempre,
esta no es la aplicación en sí, es un objeto que se usa para ayudarnos a crear el
aplicaciones Una de nuestras convenciones es colocar Requisitos Atributos en el ayudante
constructor. En este caso, el ayudante no puede hacer nada útil a menos que esté provisto de
un número de puerto que el cliente también conoce. En lugar de simplemente elegir uno y esperar
todo funciona, requerimos el número de puerto como parámetro para el constructor. los
constructor, a su vez, simplemente hace un Establecer Atributo con el valor pasado. si quieres, tu
puede establecer el "Puerto" Atributo a otro valor más tarde usando Establecer Atributo.

Similar a muchos otros objetos auxiliares, el Ayudante UdpEchoServer el objeto tiene un Instalar
método. Es la ejecución de este método lo que realmente causa el eco subyacente.
aplicación de servidor que se va a instanciar y adjuntar a un nodo. Curiosamente, el Instalar
el método toma un Contenedor de nodo como un parámetro al igual que el otro Instalar métodos que tenemos
visto. Esto es en realidad lo que se pasa al método aunque no lo parezca en
este caso. Hay un C++ implícitamente conversión en el trabajo aquí que toma el resultado de
nodos.Obtener (1) (que devuelve un puntero inteligente a un objeto de nodo --- ptr) y usos que
en un constructor para un sin nombre Contenedor de nodo que luego se pasa a Instalar. Si usted es
nunca en una pérdida para encontrar una firma de método particular en el código C ++ que compila y ejecuta
muy bien, busque este tipo de conversiones implícitas.

Ahora vemos que echoServer.Instalar va a instalar un UdpEchoServerApplicationUdpEchoServerApplication en
nodo encontrado en el índice número uno del Contenedor de nodo solíamos administrar nuestros nodos. Instalar
devolverá un contenedor que contiene punteros a todas las aplicaciones (una en este caso
desde que pasamos un Contenedor de nodo que contiene un nodo) creado por el ayudante.

Las aplicaciones requieren un tiempo para "comenzar" a generar tráfico y pueden tomar un tiempo opcional para
"detener". Proporcionamos ambos. Estos tiempos se configuran mediante el AplicaciónContenedor métodos
Empieza y Parada. Estos métodos toman Hora parámetros En este caso, utilizamos un explícito C + +
secuencia de conversión para tomar el doble 1.0 de C++ y convertirlo en un ns-3 Hora objeto usando
a Segundos emitir. Tenga en cuenta que las reglas de conversión pueden ser controladas por el autor del modelo,
y C++ tiene sus propias reglas, por lo que no siempre puede asumir que los parámetros serán felizmente
convertido para ti. Las dos líneas,

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

hará que la aplicación del servidor de eco Empieza (habilitarse) en un segundo en el
simulación y para Parada (deshabilitarse) a los diez segundos de la simulación. En virtud de
el hecho de que hayamos declarado un evento de simulación (el evento de detención de la aplicación) como
ejecutado a los diez segundos, la simulación durará at menos diez segundos.

UdpEchoClientHelper
La aplicación de cliente de eco está configurada en un método sustancialmente similar al de la
servidor. Hay un subyacente UdpEchoClientApplicationUdpEchoClientApplication que es manejado por un
UdpEchoClientHelper.

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

ApplicationContainer clientApps = echoClient.Install (nodos.Get (0));
clientApps.Start (Segundos (2.0));
clientApps.Stop (Segundos (10.0));

Sin embargo, para el cliente de eco, necesitamos establecer cinco Atributos. Los primeros dos
Atributos se establecen durante la construcción del UdpEchoClientHelper. Pasamos parámetros
que se utilizan (internamente para el ayudante) para configurar "RemoteAddress" y "RemotePort"
Atributos de acuerdo con nuestra convención para hacer requerido Atributos parámetros en el
constructores auxiliares.

Recuerda que usamos un Ipv4InterfazContenedor para realizar un seguimiento de las direcciones IP que
asignado a nuestros dispositivos. La interfaz cero en el las interfaces el contenedor va a
corresponden a la dirección IP del nodo cero en el nodos envase. El primero
interfaz en el las interfaces contenedor corresponde a la dirección IP del primer nodo en
los nodos envase. Entonces, en la primera línea de código (desde arriba), estamos creando el
ayudante y diciéndole que configure la dirección remota del cliente para que sea la dirección IP
asignado al nodo en el que reside el servidor. También le decimos que se encargue de enviar
paquetes al puerto nueve.

Los "paquetes máximos" Atributo le dice al cliente la cantidad máxima de paquetes que le permitimos
enviar durante la simulación. El intervalo" Atributo le dice al cliente cuanto tiempo debe esperar
entre paquetes, y el "PacketSize" Atributo le dice al cliente qué tan grande es su paquete
deberían ser las cargas útiles. Con esta particular combinación de Atributos, le estamos diciendo al
cliente para enviar un paquete de 1024 bytes.

Al igual que en el caso del servidor de eco, le decimos al cliente de eco que Empieza y Parada, pero
aquí iniciamos el cliente un segundo después de que el servidor esté habilitado (a los dos segundos en el
simulación).

Simulador
Lo que tenemos que hacer en este punto es ejecutar la simulación. Esto se hace usando
la funcion mundial Simulador::Ejecutar.

Simulador::Ejecutar ();

Cuando llamamos previamente a los métodos,

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

en realidad programamos eventos en el simulador a 1.0 segundos, 2.0 segundos y dos eventos
a los 10.0 segundos. Cuándo Simulador::Ejecutar se llama, el sistema comenzará a buscar a través de la
lista de eventos programados y ejecutarlos. Primero ejecutará el evento en 1.0 segundos,
que habilitará la aplicación del servidor de eco (este evento puede, a su vez, programar muchos
otros eventos). Luego ejecutará el evento programado para t = 2.0 segundos que comenzará
la aplicación de cliente de eco. Nuevamente, este evento puede programar muchos más eventos. El comienzo
la implementación del evento en la aplicación de cliente de eco comenzará la fase de transferencia de datos de
la simulación enviando un paquete al servidor.

El acto de enviar el paquete al servidor desencadenará una cadena de eventos que serán
programado automáticamente entre bastidores y que realizará la mecánica de la
eco del paquete de acuerdo con los diversos parámetros de temporización que hemos establecido en el script.

Eventualmente, dado que solo enviamos un paquete (recuerde el Paquetes máximos Atributo fue establecido en
uno), la cadena de eventos desencadenada por esa única solicitud de eco del cliente disminuirá y
la simulación quedará inactiva. Una vez que esto suceda, los eventos restantes serán los Parada
eventos para el servidor y el cliente. Cuando se ejecutan estos eventos, no hay
más eventos para procesar y Simulador::Ejecutar devoluciones. Entonces la simulación está completa.

Todo lo que queda es limpiar. Esto se hace llamando a la función global
Simulador::Destruir. A medida que las funciones auxiliares (o de bajo nivel ns-3 código) ejecutado, ellos
lo arregló para que se insertaran ganchos en el simulador para destruir todos los objetos
que fueron creados. No tenías que hacer un seguimiento de ninguno de estos objetos tú mismo ---
todo lo que tenías que hacer era llamar Simulador::Destruir y salir los ns-3 sistema se encargó de
la parte difícil para ti. Las líneas restantes de nuestra primera ns-3 guión, primero.cc, hazlo
que:

Simulador::Destruir ();
0 regresar;
}

Cuándo los simulador will ¿detener?
ns-3 es un simulador de eventos discretos (DE). En tal simulador, cada evento está asociado
con su tiempo de ejecución, y la simulación procede ejecutando eventos en el tiempo
orden de tiempo de simulación. Los eventos pueden hacer que se programen eventos futuros (por ejemplo, una
el temporizador puede reprogramarse para que caduque en el siguiente intervalo).

Los eventos iniciales generalmente son activados por cada objeto, por ejemplo, IPv6 programará el enrutador
Anuncios, Solicitudes de Vecinos, etc., una Solicitud programe el primer paquete
envío de eventos, etc.

Cuando se procesa un evento, puede generar cero, uno o más eventos. como una simulación
se ejecuta, los eventos se consumen, pero se pueden (o no) generar más eventos. los
la simulación se detendrá automáticamente cuando no haya más eventos en la cola de eventos, o cuando
se encuentra un evento Stop especial. El evento Stop se crea a través de la Simulador::Parar
(para el tiempo); función.

Hay un caso típico en el que Simulador::Parar es absolutamente necesario detener la
simulación: cuando hay un evento autosostenible. Eventos autosuficientes (o recurrentes)
son eventos que siempre se reprograman. Como consecuencia, siempre mantienen el evento
cola no vacía.

Hay muchos protocolos y módulos que contienen eventos recurrentes, por ejemplo:

· FlowMonitor - verificación periódica de paquetes perdidos

· RIPng - transmisión periódica de actualización de tablas de enrutamiento

· Etc.

En estos casos, Simulador::Parar es necesario para detener con gracia la simulación. En
Además, cuando ns-3 está en modo de emulación, el Simulador en tiempo real se usa para mantener el
reloj de simulación alineado con el reloj de la máquina, y Simulador::Parar es necesario parar
el proceso.

Muchos de los programas de simulación en el tutorial no llaman explícitamente Simulador::Parar,
ya que la cola de eventos automáticamente se quedará sin eventos. Sin embargo, estos programas se
también aceptar una llamada a Simulador::Parar. Por ejemplo, la siguiente declaración adicional en
el primer programa de ejemplo programará una parada explícita a los 11 segundos:

+ Simulador::Parar (Segundos (11.0));
Simulador::Ejecutar ();
Simulador::Destruir ();
0 regresar;
}

Lo anterior en realidad no cambiará el comportamiento de este programa, ya que este particular
la simulación termina naturalmente después de 10 segundos. Pero si tuviera que cambiar el tiempo de parada en
la declaración anterior de 11 segundos a 1 segundo, notará que la simulación
se detiene antes de que se imprima cualquier salida en la pantalla (ya que la salida ocurre alrededor del tiempo 2
segundos de tiempo de simulación).

Es importante llamar Simulador::Parar antes llamar Simulador::Ejecutar; de otra manera,
Simulador::Ejecutar nunca puede devolver el control al programa principal para ejecutar la parada!

Contruyendo Tu Guión
Hemos hecho que sea trivial construir sus scripts simples. Todo lo que tienes que hacer es dejar tu
script en el directorio temporal y se compilará automáticamente si ejecuta Waf.
Vamos a intentarlo. Dupdo ejemplos/tutorial/first.cc en el rayar directorio después de cambiar
de vuelta al directorio de nivel superior.

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

Ahora crea tu primer script de ejemplo usando waf:

$ ./waf

Debería ver mensajes informando que su mi primer El ejemplo fue construido con éxito.

Waf: Ingresando al directorio `/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: construir/depurar/borrar/miprimero_3.o -> construir/depurar/borrar/miprimero
Waf: Dejando el directorio `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'compilación' finalizada correctamente (2.357 s)

Ahora puede ejecutar el ejemplo (tenga en cuenta que si construye su programa en el directorio temporal
debe ejecutarlo desde el directorio temporal):

$ ./waf --ejecutar cero/miprimero

Deberías ver alguna salida:

Waf: Ingresando al directorio `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Dejando el directorio `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'compilación' finalizada correctamente (0.418 s)
Enviado 1024 bytes a 10.1.1.2
1024 bytes recibidos de 10.1.1.1
1024 bytes recibidos de 10.1.1.2

Aquí puede ver que el sistema de compilación verifica para asegurarse de que el archivo se haya compilado y
luego lo ejecuta. Verá que el componente de registro en el cliente de eco indica que ha enviado
un paquete de 1024 bytes al Echo Server en 10.1.1.2. También verá el componente de registro
en el servidor de eco dice que ha recibido los 1024 bytes de 10.1.1.1. El servidor de eco
hace eco silenciosamente del paquete y ve el registro del cliente de eco que ha recibido su paquete
de regreso del servidor.

Ns-3 Fuente Código
Ahora que ha utilizado algunos de los ns-3 ayudantes es posible que desee echar un vistazo a algunos de los
código fuente que implementa esa funcionalidad. El código más reciente se puede buscar en
nuestro servidor web en el siguiente enlace: http://code.nsnam.org/ns-3-dev. Allí, verás
la página de resumen de Mercurial para nuestro ns-3 árbol de desarrollo

En la parte superior de la página, verá una serie de enlaces,

resumen | bitácora | registro de cambios | gráfico | etiquetas | archivos

Continúe y seleccione el archivos Enlace. Esto es lo que el nivel superior de la mayoría de nuestros
repositorios veré:

drwxr-xr-x [arriba]
drwxr-xr-x vincula archivos python
archivos doc drwxr-xr-x
archivos de ejemplo drwxr-xr-x
archivos drwxr-xr-x ns3
Archivos borradores drwxr-xr-x
Archivos drwxr-xr-x src
Archivos de utilidades drwxr-xr-x
-rw-r--r-- 2009-07-01 12:47 +0200 560 .hgignorar archivo | revisiones | anotar
-rw-r--r-- 2009-07-01 12:47 +0200 1886 archivo .hgtags | revisiones | anotar
-rw-r--r-- 2009-07-01 12:47 +0200 1276 AUTORES archivo | revisiones | anotar
-rw-r--r-- 2009-07-01 12:47 +0200 30961 CAMBIOS.html archivo | revisiones | anotar
-rw-r--r-- 2009-07-01 12:47 +0200 17987 Archivo de LICENCIA | revisiones | anotar
-rw-r--r-- 2009-07-01 12:47 +0200 3742 Archivo LÉAME | revisiones | anotar
-rw-r--r-- 2009-07-01 12:47 +0200 16171 archivo RELEASE_NOTES | revisiones | anotar
-rw-r--r-- 2009-07-01 12:47 +0200 6 VERSIÓN archivo | revisiones | anotar
-rwxr-xr-x 2009-07-01 12:47 +0200 88110 archivo waf | revisiones | anotar
-rwxr-xr-x 2009-07-01 12:47 +0200 28 archivo waf.bat | revisiones | anotar
-rw-r--r-- 2009-07-01 12:47 +0200 35395 archivo wscript | revisiones | anotar
-rw-r--r-- 2009-07-01 12:47 +0200 7673 archivo wutils.py | revisiones | anotar

Nuestros scripts de ejemplo están en el ejemplos directorio. Si hace clic en ejemplos verá
una lista de subdirectorios. Uno de los archivos de tutoriales el subdirectorio es primero.cc. Si tu
hacer clic en primero.cc encontrará el código que acaba de recorrer.

El código fuente se encuentra principalmente en el src directorio. Puede ver el código fuente ya sea por
haciendo clic en el nombre del directorio o haciendo clic en el archivos enlace a la derecha de la
nombre del directorio. Si hace clic en el src directorio, será llevado a la lista de
los src subdirectorios. Si luego hace clic en centro subdirectorio, encontrará una lista de
archivos El primer archivo que encontrará (a partir de este escrito) es abortar.h. Si hace clic en el
abortar.h enlace, se le enviará al archivo de origen para abortar.h que contiene macros útiles
para salir de scripts si se detectan condiciones anormales.

El código fuente de los ayudantes que hemos utilizado en este capítulo se puede encontrar en el
src/aplicaciones/ayudante directorio. Siéntase libre de hurgar en el árbol de directorios para obtener
una idea de lo que hay y el estilo de ns-3 .

AJUSTAR


Gracias a los Inicio de sesión Módulo
Ya hemos echado un breve vistazo a la ns-3 módulo de registro mientras recorre el
primero.cc texto. Ahora vamos a echar un vistazo más de cerca y ver qué tipo de casos de uso el
subsistema de registro fue diseñado para cubrir.

Inicio de sesión Descripción General
Muchos sistemas grandes admiten algún tipo de función de registro de mensajes y ns-3 no es un
excepción. En algunos casos, solo los mensajes de error se registran en la "consola del operador" (que
es típicamente stderr en sistemas basados ​​en Unix). En otros sistemas, los mensajes de advertencia pueden ser
salida, así como mensajes informativos más detallados. En algunos casos, las instalaciones madereras
se utilizan para generar mensajes de depuración que pueden convertir rápidamente la salida en un desenfoque.

ns-3 considera que todos estos niveles de verbosidad son útiles y proporcionamos una
enfoque seleccionable de varios niveles para el registro de mensajes. El registro se puede desactivar por completo,
habilitado componente por componente, o habilitado globalmente; y proporciona seleccionable
niveles de verbosidad. los ns-3 El módulo de registro proporciona un sencillo y relativamente fácil de usar.
manera de obtener información útil de su simulación.

Debe comprender que proporcionamos un mecanismo de propósito general --- rastreo --- para
obtenga datos de sus modelos que deberían preferirse para la salida de simulación (consulte el
sección del tutorial Uso del sistema de rastreo para obtener más detalles sobre nuestro sistema de rastreo).
Se debe preferir el registro para información de depuración, advertencias, mensajes de error o cualquier
tiempo que desea obtener fácilmente un mensaje rápido de sus scripts o modelos.

Actualmente hay siete niveles de mensajes de registro de verbosidad creciente definidos en el
.

· LOG_ERROR --- Registrar mensajes de error (macro asociado: NS_LOG_ERROR);

· LOG_WARN --- Registra mensajes de advertencia (macro asociado: NS_LOG_WARN);

· LOG_DEBUG --- Registra mensajes de depuración ad-hoc relativamente raros (macro asociado:
NS_LOG_DEBUG);

· LOG_INFO --- Registra mensajes informativos sobre el progreso del programa (macro asociado:
NS_LOG_INFO);

· LOG_FUNCTION --- Registra un mensaje que describe cada función llamada (dos macros asociadas:
NS_LOG_FUNCTION, utilizado para funciones miembro, y NS_LOG_FUNCTION_NOARGS, utilizado para estática
funciones);

· LOG_LOGIC -- Mensajes de registro que describen el flujo lógico dentro de una función (macro asociado:
NS_LOG_LOGIC);

· LOG_ALL --- Registra todo lo mencionado anteriormente (sin macro asociada).

Para cada LOG_TYPE también hay LOG_LEVEL_TYPE que, si se usa, permite el registro de todos los
niveles por encima de él además de su nivel. (Como consecuencia de esto, LOG_ERROR y
LOG_LEVEL_ERROR y también LOG_ALL y LOG_LEVEL_ALL son funcionalmente equivalentes.) Para
ejemplo, habilitar LOG_INFO solo habilitará los mensajes proporcionados por la macro NS_LOG_INFO, mientras que
habilitar LOG_LEVEL_INFO también habilitará los mensajes proporcionados por NS_LOG_DEBUG, NS_LOG_WARN
y macros NS_LOG_ERROR.

También proporcionamos una macro de registro incondicional que siempre se muestra, independientemente de
niveles de registro o selección de componentes.

· NS_LOG_UNCOND: registra el mensaje asociado incondicionalmente (sin nivel de registro asociado).

Cada nivel se puede solicitar de forma individual o acumulativa; y el registro se puede configurar usando un
variable de entorno de shell (NS_LOG) o mediante la llamada a la función del sistema de registro. como se vio
anteriormente en el tutorial, el sistema de registro tiene documentación de Doxygen y ahora sería un
buen momento para leer detenidamente la documentación del módulo de registro si aún no lo ha hecho.

Ahora que ha leído la documentación con gran detalle, usemos algo de ese conocimiento
para obtener información interesante de la scratch/miprimero.cc script de ejemplo que tienes
ya construido

Habilitación Inicio de sesión
Usemos la variable de entorno NS_LOG para activar más registros, pero primero, solo para
orientarnos, seguir adelante y ejecutar el último script tal como lo hizo anteriormente,

$ ./waf --ejecutar cero/miprimero

Debería ver la salida ahora familiar de la primera ns-3 programa de ejemplo

$ Waf: Ingresando al directorio `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Dejando el directorio `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'compilación' finalizada correctamente (0.413 s)
Enviado 1024 bytes a 10.1.1.2
1024 bytes recibidos de 10.1.1.1
1024 bytes recibidos de 10.1.1.2

Resulta que los mensajes "Enviados" y "Recibidos" que ve arriba en realidad están registrando
mensajes del UdpEchoClientApplicationUdpEchoClientApplication y UdpEchoServerApplicationUdpEchoServerApplication. podemos preguntarle a
aplicación cliente, por ejemplo, para imprimir más información configurando su nivel de registro
a través de la variable de entorno NS_LOG.

Voy a suponer de ahora en adelante que está usando un shell similar a sh que usa
la sintaxis "VARIABLE=valor". Si está utilizando un shell tipo csh, tendrá que
convertir mis ejemplos a la sintaxis de "valor VARIABLE setenv" requerida por esos shells.

En este momento, la aplicación de cliente de eco UDP está respondiendo a la siguiente línea de código en
scratch/miprimero.cc,

LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);

Esta línea de código permite que el LOG_LEVEL_INFO nivel de registro. Cuando pasamos un registro
indicador de nivel, en realidad estamos habilitando el nivel dado y todos los niveles inferiores. En este caso,
hemos habilitado NS_LOG_INFO, NS_LOG_DEBUG, NS_LOG_WARN y NS_LOG_ERROR. podemos aumentar
el nivel de registro y obtener más información sin cambiar el script y recompilar por
configurando la variable de entorno NS_LOG de esta manera:

$ exportar NS_LOG=UdpEchoClientApplication=level_all

Esto establece la variable de entorno de shell NS_LOG a la cuerda,

UdpEchoClientApplication=nivel_todo

El lado izquierdo de la asignación es el nombre del componente de registro que queremos establecer,
y el lado derecho es la bandera que queremos usar. En este caso, vamos a encender
todos los niveles de depuración de la aplicación. Si ejecuta el script con NS_LOG establecido
de esta manera, el ns-3 el sistema de registro recogerá el cambio y debería ver lo siguiente
salida:

Waf: Ingresando al directorio `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Dejando el directorio `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'compilación' finalizada correctamente (0.404 s)
Aplicación UdpEchoClient:UdpEchoClient()
Aplicación UdpEchoClient:EstablecerTamañoDeDatos(1024)
Aplicación UdpEchoClient: Iniciar aplicación()
Aplicación UdpEchoClient:ScheduleTransmit()
UdpEchoClientApplication:Enviar()
Enviado 1024 bytes a 10.1.1.2
1024 bytes recibidos de 10.1.1.1
UdpEchoClientApplication:HandleRead(0x6241e0, 0x624a20)
1024 bytes recibidos de 10.1.1.2
Aplicación UdpEchoClient:DetenerAplicación()
Aplicación UdpEchoClient:DoDispose()
AplicaciónUdpEchoClient:~UdpEchoClient()

La información de depuración adicional proporcionada por la aplicación proviene de NS_LOG_FUNCTION
nivel. Esto se muestra cada vez que se llama a una función en la aplicación durante el script
ejecución. Generalmente, el uso de (al menos) NS_LOG_FUNCTION(this) en funciones miembro es
privilegiado. Use NS_LOG_FUNCTION_NOARGS() solo en funciones estáticas. Tenga en cuenta, sin embargo, que
no hay requisitos en el ns-3 sistema que los modelos deben soportar cualquier
funcionalidad de registro. La decisión sobre cuánta información se registra se deja a
el desarrollador del modelo individual. En el caso de las aplicaciones de eco, una gran cantidad de registro
la salida está disponible.

Ahora puede ver un registro de las llamadas de función que se realizaron a la aplicación. Si usted
mire de cerca, notará dos puntos entre la cadena UdpEchoClientApplicationUdpEchoClientApplication
y el nombre del método donde podría haber esperado un operador de alcance de C++ (::). Esto es
intencional.

El nombre no es realmente un nombre de clase, es un nombre de componente de registro. cuando hay un
correspondencia uno a uno entre un archivo de origen y una clase, esta será generalmente la
nombre de clase, pero debe comprender que en realidad no es un nombre de clase, y hay un
dos puntos allí en lugar de dos puntos dobles para recordarle de una manera relativamente sutil
separar conceptualmente el nombre del componente de registro del nombre de la clase.

Resulta que, en algunos casos, puede ser difícil determinar qué método realmente
genera un mensaje de registro. Si observa el texto anterior, puede preguntarse dónde está la cadena.
"Recibido 1024 bytes desde 10.1.1.2" viene. Puede resolver esto haciendo OR'ing el
función_prefijo nivel en el NS_LOG Variable ambiental. Intenta hacer lo siguiente,

$ export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func'

Tenga en cuenta que las comillas son obligatorias ya que la barra vertical que usamos para indicar un OR
La operación también es un conector de tubería Unix.

Ahora, si ejecuta el script, verá que el sistema de registro se asegura de que cada
El mensaje del componente de registro dado tiene como prefijo el nombre del componente.

Waf: Ingresando al directorio `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Dejando el directorio `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'compilación' finalizada correctamente (0.417 s)
Aplicación UdpEchoClient:UdpEchoClient()
Aplicación UdpEchoClient:EstablecerTamañoDeDatos(1024)
Aplicación UdpEchoClient: Iniciar aplicación()
Aplicación UdpEchoClient:ScheduleTransmit()
UdpEchoClientApplication:Enviar()
UdpEchoClientApplication:Send(): Envió 1024 bytes a 10.1.1.2
1024 bytes recibidos de 10.1.1.1
UdpEchoClientApplication:HandleRead(0x6241e0, 0x624a20)
UdpEchoClientApplication:HandleRead(): Recibió 1024 bytes de 10.1.1.2
Aplicación UdpEchoClient:DetenerAplicación()
Aplicación UdpEchoClient:DoDispose()
AplicaciónUdpEchoClient:~UdpEchoClient()

Ahora puede ver que todos los mensajes provenientes de la aplicación de cliente de eco UDP están
identificado como tal. El mensaje "Recibido 1024 bytes de 10.1.1.2" ahora es claramente
identificado como procedente de la aplicación de cliente de eco. El mensaje restante debe ser
procedente de la aplicación del servidor de eco UDP. Podemos habilitar ese componente ingresando un
Lista de componentes separados por dos puntos en la variable de entorno NS_LOG.

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

Advertencia: deberá eliminar la nueva línea después de la : en el texto de ejemplo anterior que
solo está allí para fines de formateo de documentos.

Ahora, si ejecuta el script, verá todos los mensajes de registro tanto del cliente de eco
y aplicaciones de servidor. Puede ver que esto puede ser muy útil para depurar problemas.

Waf: Ingresando al directorio `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Dejando el directorio `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'compilación' finalizada correctamente (0.406 s)
Aplicación UdpEchoServer:UdpEchoServer()
Aplicación UdpEchoClient:UdpEchoClient()
Aplicación UdpEchoClient:EstablecerTamañoDeDatos(1024)
Aplicación UdpEchoServer: Iniciar aplicación()
Aplicación UdpEchoClient: Iniciar aplicación()
Aplicación UdpEchoClient:ScheduleTransmit()
UdpEchoClientApplication:Enviar()
UdpEchoClientApplication:Send(): Envió 1024 bytes a 10.1.1.2
UdpEchoServerApplication:HandleRead(): Recibió 1024 bytes de 10.1.1.1
UdpEchoServerApplication:HandleRead(): paquete de eco
Aplicación UdpEchoClient:HandleRead(0x624920, 0x625160)
UdpEchoClientApplication:HandleRead(): Recibió 1024 bytes de 10.1.1.2
Aplicación UdpEchoServer:DetenerAplicación()
Aplicación UdpEchoClient:DetenerAplicación()
Aplicación UdpEchoClient:DoDispose()
Aplicación UdpEchoServer:DoDispose()
AplicaciónUdpEchoClient:~UdpEchoClient()
AplicaciónUdpEchoServer:~UdpEchoServer()

A veces también es útil poder ver el tiempo de simulación en el que aparece un mensaje de registro.
es generado. Puede hacer esto haciendo OR en el bit prefix_time.

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

Nuevamente, deberá eliminar la nueva línea anterior. Si ejecuta el script ahora, debería
ver el siguiente resultado:

Waf: Ingresando al directorio `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Dejando el directorio `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'compilación' finalizada correctamente (0.418 s)
0s Aplicación UdpEchoServer:UdpEchoServer()
0sUdpEchoClientApplication:UdpEchoClient()
0s Aplicación UdpEchoClient:EstablecerTamañoDeDatos(1024)
1s Aplicación UdpEchoServer: Iniciar aplicación()
2s UdpEchoClientApplication:IniciarAplicación()
2s Aplicación UdpEchoClient:ScheduleTransmit()
2s UdpEchoClientApplication:Enviar()
2s UdpEchoClientApplication:Send(): enviado 1024 bytes a 10.1.1.2
2.00369s UdpEchoServerApplication:HandleRead(): Recibió 1024 bytes de 10.1.1.1
2.00369s UdpEchoServerApplication:HandleRead(): paquete de eco
2.00737s UdpEchoClientApplication:HandleRead(0x624290, 0x624ad0)
2.00737s UdpEchoClientApplication:HandleRead(): Recibió 1024 bytes de 10.1.1.2
10s Aplicación UdpEchoServer:DetenerAplicación()
10s UdpEchoClientApplication:DetenerAplicación()
Aplicación UdpEchoClient:DoDispose()
Aplicación UdpEchoServer:DoDispose()
AplicaciónUdpEchoClient:~UdpEchoClient()
AplicaciónUdpEchoServer:~UdpEchoServer()

Puede ver que se llamó al constructor de UdpEchoServer en un tiempo de simulación de
0 segundos Esto realmente está sucediendo antes de que comience la simulación, pero el tiempo es
se muestra como cero segundos. Lo mismo ocurre con el mensaje del constructor UdpEchoClient.

Recuerde que el cero/primero.cc el script inició la aplicación del servidor de eco en un segundo
en la simulación. Ahora puede ver que el Iniciar aplicación el método del servidor es,
de hecho, llamado en un segundo. También puede ver que la aplicación de cliente de eco está
comenzó en un tiempo de simulación de dos segundos como lo solicitamos en el script.

Ahora puede seguir el progreso de la simulación desde el ProgramarTransmitir llamar en el
cliente que llama Enviar En el correo electrónico “Su Cuenta de Usuario en su Nuevo Sistema XNUMXCX”. ManejarLeer devolución de llamada en la aplicación del servidor de eco. Nota
que el tiempo transcurrido para que el paquete se envíe a través del enlace punto a punto es 3.69
milisegundos. Verá que el servidor de eco registra un mensaje que le dice que se ha hecho eco
el paquete y luego, después de otra demora de canal, verá que el cliente de eco recibe el
paquete con eco en su ManejarLeer método.

Hay muchas cosas que están sucediendo bajo las sábanas en esta simulación que no estás
viendo también. Puede seguir muy fácilmente todo el proceso activando todos los
registro de componentes en el sistema. Intenta configurar el NS_LOG variable a lo siguiente,

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

El asterisco de arriba es el comodín del componente de registro. Esto encenderá todos los
registrando todos los componentes usados ​​en la simulación. No reproduciré la salida.
aquí (a partir de este escrito produce 1265 líneas de salida para el eco de un solo paquete) pero
puede redirigir esta información a un archivo y revisarlo con su favorito
editor si quieres,

$ ./waf --ejecutar scratch/myfirst > log.out 2>&1

Yo personalmente uso esta versión extremadamente detallada de registro cuando se me presenta una
problema y no tengo idea de dónde van las cosas mal. Puedo seguir el progreso de la
código con bastante facilidad sin tener que establecer puntos de interrupción y recorrer el código en un depurador.
Puedo simplemente editar la salida en mi editor favorito y buscar las cosas que espero,
y ver cosas que suceden que no espero. Cuando tengo una idea general de lo que es
va mal, hago la transición a un depurador para un examen detallado del problema.
Este tipo de salida puede ser especialmente útil cuando su secuencia de comandos hace algo completamente
inesperado. Si está utilizando un depurador, es posible que se pierda una excursión inesperada
completamente. Registrar la excursión la hace rápidamente visible.

Adición Inicio de sesión a a tu manera Código
Puede agregar un nuevo registro a sus simulaciones haciendo llamadas al componente de registro a través de
varias macros. Hagámoslo en el miprimero.cc guión que tenemos en el rayar directorio.

Recuerde que hemos definido un componente de registro en ese script:

NS_LOG_COMPONENT_DEFINE ("EjemploPrimerScript");

Ahora sabe que puede habilitar todo el registro para este componente configurando el
NS_LOG variable de entorno a los distintos niveles. Avancemos y agreguemos algo de registro a
la secuencia de comandos. La macro utilizada para agregar un mensaje de registro de nivel informativo es NS_LOG_INFO. Ir
adelante y agregue uno (justo antes de que comencemos a crear los nodos) que le diga que el script
es "Creación de topología". Esto se hace como en este fragmento de código,

Abierto scratch/miprimero.cc en su editor favorito y agregue la línea,

NS_LOG_INFO ("Creando Topología");

Justo antes de las líneas,

nodos NodeContainer;
nodos.Crear (2);

Ahora construya el script usando waf y borre el NS_LOG variable para apagar el torrente de
registro que habilitamos previamente:

$ ./waf
$ exportar NS_LOG=

Ahora, si ejecuta el script,

$ ./waf --ejecutar cero/miprimero

usted podrá no ver su nuevo mensaje desde su componente de registro asociado
(PrimerScriptEjemplo) no ha sido habilitado. Para ver tu mensaje tendrás que
habilitar el PrimerScriptEjemplo componente de registro con un nivel mayor o igual a
NS_LOG_INFO. Si solo desea ver este nivel particular de registro, puede habilitarlo
por,

$ exportar NS_LOG=FirstScriptExample=info

Si ahora ejecuta el script, verá su nuevo mensaje de registro "Creando topología",

Waf: Ingresando al directorio `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Dejando el directorio `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'compilación' finalizada correctamente (0.404 s)
Creación de topología
Enviado 1024 bytes a 10.1.1.2
1024 bytes recibidos de 10.1.1.1
1024 bytes recibidos de 10.1.1.2

Gracias a Comando Line Argumentos
Primordial Predeterminado Atributos
Otra forma de cambiar cómo ns-3 los scripts se comportan sin edición y la construcción es a través de
comando línea argumentos Proporcionamos un mecanismo para analizar los argumentos de la línea de comandos y
establece automáticamente variables locales y globales en función de esos argumentos.

El primer paso para usar el sistema de argumentos de línea de comando es declarar la línea de comando
analizador Esto se hace de manera bastante simple (en su programa principal) como en el siguiente código,

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

Línea de comando cmd;
cmd. Parse (argc, argv);

...
}

Este simple fragmento de código de dos líneas es realmente muy útil por sí mismo. Abre la puerta a la
ns-3 variable global y Atributo sistemas Continúe y agregue esas dos líneas de código a
los scratch/miprimero.cc guión al comienzo de principal. Continúe, cree el script y ejecútelo.
pero pídale ayuda al script de la siguiente manera,

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

Esto le pedirá a Waf que ejecute el cero/miprimero script y pasar el argumento de la línea de comando
--ImprimirAyuda al guión. Las comillas son necesarias para determinar qué programa obtiene qué
argumento. El analizador de línea de comando ahora verá el --ImprimirAyuda argumentar y responder con,

Waf: Ingresando al directorio `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Dejando el directorio `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'compilación' finalizada correctamente (0.413 s)
TcpL4Protocolo:TcpStateMachine()
CommandLine:HandleArgument(): Manejar arg name=PrintHelp value=
--PrintHelp: Imprime este mensaje de ayuda.
--PrintGroups: Imprime la lista de grupos.
--PrintTypeIds: Imprime todos los TypeIds.
--PrintGroup=[grupo]: Imprime todos los TypeIds del grupo.
--PrintAttributes=[typeid]: Imprime todos los atributos de typeid.
--PrintGlobals: Imprime la lista de globales.

Centrémonos en el --ImprimirAtributos opción. Ya hemos insinuado la ns-3 Atributo
sistema mientras camina por el primero.cc texto. Nos fijamos en las siguientes líneas de
código,

PuntoAPuntoAyudante puntoAPunto;
pointToPoint.SetDeviceAttribute ("Velocidad de datos", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Retraso", StringValue ("2ms"));

y mencioné que Velocidad de datos era en realidad un Atributo de las Dispositivo de red punto a punto. Vamos
utilice el analizador de argumentos de la línea de comandos para echar un vistazo a la Atributos de las
Dispositivo de red punto a punto. La lista de ayuda dice que debemos proporcionar un ID de tipo. Esto
corresponde al nombre de clase de la clase a la que pertenece el Atributos pertenecer. En este caso
será ns3::Dispositivo de red punto a punto. Sigamos adelante y escribamos,

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

El sistema imprimirá todos los Atributos de este tipo de dispositivo de red. Entre la
Atributos verás en la lista es,

--ns3::PointToPointNetDevice::DataRate=[32768bps]:
La velocidad de datos predeterminada para enlaces punto a punto

Este es el valor predeterminado que se usará cuando un Dispositivo de red punto a punto se crea en el
sistema. Anulamos este valor predeterminado con el Atributo entorno en el Ayudante punto a punto
encima. Usemos los valores predeterminados para los dispositivos y canales punto a punto al
eliminando el Establecer atributo de dispositivo llamar y el Establecer atributo de canal llamar desde el miprimero.cc
tenemos en el directorio temporal.

Su secuencia de comandos ahora debería simplemente declarar el Ayudante punto a punto y no hacer nada para reinventar la industria logística y redefinir las soluciones ecológicas para reinventar la industria logística y redefinir las soluciones ecológicas. operaciones
como en el siguiente ejemplo,

...

nodos NodeContainer;
nodos.Crear (2);

PuntoAPuntoAyudante puntoAPunto;

dispositivos NetDeviceContainer;
dispositivos = pointToPoint.Install (nodos);

...

Continúe y cree el nuevo script con Waf (./waf) y regresemos y habilitemos algunos
iniciar sesión desde la aplicación del servidor de eco UDP y activar el prefijo de tiempo.

$ export 'NS_LOG=UdpEchoServerApplication=level_all|prefix_time'

Si ejecuta el script, ahora debería ver el siguiente resultado,

Waf: Ingresando al directorio `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Dejando el directorio `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'compilación' finalizada correctamente (0.405 s)
0s Aplicación UdpEchoServer:UdpEchoServer()
1s Aplicación UdpEchoServer: Iniciar aplicación()
Enviado 1024 bytes a 10.1.1.2
2.25732s 1024 bytes recibidos de 10.1.1.1
2.25732s Paquete de eco
1024 bytes recibidos de 10.1.1.2
10s Aplicación UdpEchoServer:DetenerAplicación()
Aplicación UdpEchoServer:DoDispose()
AplicaciónUdpEchoServer:~UdpEchoServer()

Recuerde que la última vez que vimos el tiempo de simulación en el que se envió el paquete
recibido por el servidor de eco, fue en 2.00369 segundos.

2.00369s UdpEchoServerApplication:HandleRead(): Recibió 1024 bytes de 10.1.1.1

Ahora está recibiendo el paquete en 2.25732 segundos. Esto se debe a que acabamos de dejar caer el
tasa de datos del Dispositivo de red punto a punto hasta su valor predeterminado de 32768 bits por segundo desde
cinco megabits por segundo.

Si tuviéramos que proporcionar una nueva Velocidad de datos usando la línea de comando, podríamos acelerar nuestra simulación
arriba de nuevo Esto lo hacemos de la siguiente manera, según la fórmula implícita en la ayuda
material:

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

Esto establecerá el valor predeterminado de la Velocidad de datos Atributo volver a cinco megabits por
segundo. ¿Te sorprende el resultado? Resulta que para conseguir el original
comportamiento del script, tendremos que configurar el retraso de la velocidad de la luz del canal
así como. Podemos pedirle al sistema de línea de comando que imprima el Atributos del canal
tal como lo hicimos para el dispositivo de red:

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

Descubrimos el Retrasar Atributo del canal se configura de la siguiente manera:

--ns3::Canalpuntoapunto::Retraso=[0ns]:
Retardo de transmisión a través del canal

Luego podemos establecer estos dos valores predeterminados a través del sistema de línea de comando,

$ ./waf --ejecuta "scratch/myfirst
--ns3::DispositivoPuntoAPuntoRed::VelocidadDeDatos=5Mbps
--ns3::Canalpuntoapunto::Retraso=2ms"

en cuyo caso recuperamos el tiempo que teníamos cuando configuramos explícitamente el Velocidad de datos y Retrasar
en el guión:

Waf: Ingresando al directorio `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Dejando el directorio `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'compilación' finalizada correctamente (0.417 s)
0s Aplicación UdpEchoServer:UdpEchoServer()
1s Aplicación UdpEchoServer: Iniciar aplicación()
Enviado 1024 bytes a 10.1.1.2
2.00369s 1024 bytes recibidos de 10.1.1.1
2.00369s Paquete de eco
1024 bytes recibidos de 10.1.1.2
10s Aplicación UdpEchoServer:DetenerAplicación()
Aplicación UdpEchoServer:DoDispose()
AplicaciónUdpEchoServer:~UdpEchoServer()

Tenga en cuenta que el servidor vuelve a recibir el paquete a los 2.00369 segundos. Pudimos
en realidad establecer cualquiera de los Atributos utilizado en el guión de esta manera. En particular podríamos
establecer el UdpEchoCliente Atributo Paquetes máximos a algún otro valor que uno.

¿Cómo harías eso? Darle una oportunidad. Recuerda que tienes que comentar el lugar
anulamos el valor predeterminado Atributo y establecer explícitamente Paquetes máximos en el guión. Entonces tú
hay que reconstruir el script. También tendrá que encontrar la sintaxis para establecer realmente
el nuevo valor de atributo predeterminado mediante la función de ayuda de la línea de comandos. Una vez que tengas esto
descubrí que debería poder controlar la cantidad de paquetes repetidos desde el comando
línea. Como somos buenas personas, le diremos que su línea de comando debería terminar buscando
algo como,

$ ./waf --ejecuta "scratch/myfirst
--ns3::DispositivoPuntoAPuntoRed::VelocidadDeDatos=5Mbps
--ns3::Canalpuntoapunto::Retraso=2ms
--ns3::UdpEchoClient::Paquetes máximos=2"

Enganche Tu Propia Valores
También puede agregar sus propios ganchos al sistema de línea de comandos. Esto se hace de manera bastante simple por
usando el AddValue método al analizador de línea de comandos.

Usemos esta función para especificar el número de paquetes para hacer eco en una forma completamente diferente
manera. Agreguemos una variable local llamada nPaquetes En el correo electrónico “Su Cuenta de Usuario en su Nuevo Sistema XNUMXCX”. principal función. vamos a inicializar
a uno para que coincida con nuestro comportamiento predeterminado anterior. Para permitir que el analizador de línea de comando
cambie este valor, necesitamos enganchar el valor en el analizador. Hacemos esto agregando una llamada
a AddValue. Adelante, cambia el scratch/miprimero.cc guión para empezar con el
código siguiente,

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

Línea de comando cmd;
cmd.AddValue("nPaquetes", "Número de paquetes para hacer eco", nPaquetes);
cmd. Parse (argc, argv);

...

Desplácese hacia abajo hasta el punto en el script donde configuramos el Paquetes máximos Atributo y cámbialo
para que se establezca en la variable nPaquetes en lugar de la constante 1 como se muestra a continuación.

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

Ahora, si ejecuta el script y proporciona el --ImprimirAyuda argumento, deberías ver tu nuevo
User Argumento aparece en la pantalla de ayuda.

Tratar,

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

Waf: Ingresando al directorio `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Dejando el directorio `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'compilación' finalizada correctamente (0.403 s)
--PrintHelp: Imprime este mensaje de ayuda.
--PrintGroups: Imprime la lista de grupos.
--PrintTypeIds: Imprime todos los TypeIds.
--PrintGroup=[grupo]: Imprime todos los TypeIds del grupo.
--PrintAttributes=[typeid]: Imprime todos los atributos de typeid.
--PrintGlobals: Imprime la lista de globales.
Argumentos del usuario:
--nPackets: número de paquetes para hacer eco

Si desea especificar el número de paquetes para hacer eco, ahora puede hacerlo configurando el
--nPaquetes argumento en la línea de comando,

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

Ahora deberías ver

Waf: Ingresando al directorio `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Dejando el directorio `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'compilación' finalizada correctamente (0.404 s)
0s Aplicación UdpEchoServer:UdpEchoServer()
1s Aplicación UdpEchoServer: Iniciar aplicación()
Enviado 1024 bytes a 10.1.1.2
2.25732s 1024 bytes recibidos de 10.1.1.1
2.25732s Paquete de eco
1024 bytes recibidos de 10.1.1.2
Enviado 1024 bytes a 10.1.1.2
3.25732s 1024 bytes recibidos de 10.1.1.1
3.25732s Paquete de eco
1024 bytes recibidos de 10.1.1.2
10s Aplicación UdpEchoServer:DetenerAplicación()
Aplicación UdpEchoServer:DoDispose()
AplicaciónUdpEchoServer:~UdpEchoServer()

Ahora ha repetido dos paquetes. Bastante fácil, ¿no?

Puedes ver que si eres un ns-3 usuario, puede utilizar el sistema de argumentos de la línea de comandos para
controlar los valores globales y Atributos. Si es un autor modelo, puede agregar nuevos
Atributos para usted Objetos y automáticamente estarán disponibles para ser configurados por su
usuarios a través del sistema de línea de comandos. Si es un autor de guiones, puede agregar nuevos
variables a sus scripts y conéctelos al sistema de línea de comando sin problemas.

Gracias a los Rastreo System
El objetivo de la simulación es generar resultados para su posterior estudio, y el ns-3
sistema de rastreo es un mecanismo principal para esto. Ya que ns-3 es un programa C++, estándar
Se podrían utilizar instalaciones para generar resultados a partir de programas C++:

#incluir
...
int principal ()
{
...
std::cout << "El valor de x es " << x << std::endl;
...
}

Incluso podría usar el módulo de registro para agregar un poco de estructura a su solución. Ahí
Hay muchos problemas bien conocidos generados por tales enfoques, por lo que hemos proporcionado una
subsistema genérico de seguimiento de eventos para abordar los problemas que consideramos importantes.

Los objetivos básicos de la ns-3 sistema de seguimiento son:

· Para tareas básicas, el sistema de seguimiento debe permitir al usuario generar un seguimiento estándar
para fuentes de rastreo populares y para personalizar qué objetos generan el rastreo;

· Los usuarios intermedios deben poder ampliar el sistema de rastreo para modificar el formato de salida
generadas, o para insertar nuevas fuentes de rastreo, sin modificar el núcleo de la
simulador;

· Los usuarios avanzados pueden modificar el núcleo del simulador para agregar nuevas fuentes y sumideros de seguimiento.

Los ns-3 El sistema de rastreo se basa en los conceptos de fuentes de rastreo independientes y
sumideros de rastreo y un mecanismo uniforme para conectar fuentes a sumideros. Las fuentes de rastreo son
entidades que pueden señalar eventos que suceden en una simulación y proporcionar acceso a
datos subyacentes interesantes. Por ejemplo, una fuente de seguimiento podría indicar cuándo se envía un paquete.
recibido por un dispositivo de red y proporciona acceso al contenido del paquete para el seguimiento interesado
se hunde.

Las fuentes de rastreo no son útiles por sí mismas, deben estar "conectadas" a otras piezas de
código que realmente hace algo útil con la información proporcionada por el sumidero. Rastro
Los sumideros son consumidores de los eventos y datos proporcionados por las fuentes de seguimiento. Por ejemplo,
uno podría crear un sumidero de seguimiento que (cuando se conecta a la fuente de seguimiento del
ejemplo anterior) imprimir partes interesantes del paquete recibido.

El fundamento de esta división explícita es permitir a los usuarios adjuntar nuevos tipos de sumideros a
fuentes de rastreo existentes, sin necesidad de editar y volver a compilar el núcleo de la
simulador. Por lo tanto, en el ejemplo anterior, un usuario podría definir un nuevo sumidero de rastreo en su
script y adjúntelo a una fuente de rastreo existente definida en el núcleo de simulación por
editando solo el script de usuario.

En este tutorial, recorreremos algunas fuentes y sumideros predefinidos y mostraremos cómo
se pueden personalizar con poco esfuerzo por parte del usuario. Consulte el manual de ns-3 o las secciones de procedimientos.
para obtener información sobre la configuración de rastreo avanzada, incluida la extensión del rastreo
espacio de nombres y la creación de nuevas fuentes de rastreo.

ASCII Rastreo
ns-3 proporciona una funcionalidad auxiliar que envuelve el sistema de rastreo de bajo nivel para ayudarlo
con los detalles involucrados en la configuración de algunos seguimientos de paquetes fáciles de entender. Si usted
habilite esta funcionalidad, verá la salida en archivos ASCII, de ahí el nombre. Para
aquellos familiarizados con ns-2 salida, este tipo de traza es análoga a la fuera.tr generado
por muchos guiones.

Simplemente entremos y agreguemos algo de salida de rastreo ASCII a nuestro scratch/miprimero.cc
texto. Justo antes de la llamada a Simulador::Ejecutar (), agregue las siguientes líneas de código:

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

Como en muchos otros ns-3 modismos, este código usa un objeto auxiliar para ayudar a crear ASCII
rastros La segunda línea contiene dos llamadas a métodos anidados. El método "adentro",
Crear flujo de archivos() utiliza un idioma de objeto sin nombre para crear un objeto de secuencia de archivos en el
stack (sin un nombre de objeto) y páselo al método llamado. entraremos en esto
más en el futuro, pero todo lo que tienes que saber en este momento es que estás creando un
objeto que representa un archivo llamado "myfirst.tr" y lo pasa a ns-3. Estas diciendo
ns-3 para hacer frente a los problemas de vida del objeto creado y también para hacer frente a los problemas
causado por una limitación poco conocida (intencional) de los objetos ofstream de C++ relacionados con la copia
constructores.

La llamada exterior, a HabilitarAsciiAll(), le dice al ayudante que desea habilitar ASCII
rastreo en todos los dispositivos punto a punto en su simulación; y quieres el (siempre)
sumideros de rastreo para escribir información sobre el movimiento de paquetes en formato ASCII.

Para aquellos familiarizados con ns-2, los eventos rastreados son equivalentes a los puntos de rastreo populares
que registran eventos "+", "-", "d" y "r".

Ahora puede compilar el script y ejecutarlo desde la línea de comando:

$ ./waf --ejecutar cero/miprimero

Tal como lo ha visto muchas veces antes, verá algunos mensajes de Waf y luego
"'construcción' finalizó con éxito" con una cierta cantidad de mensajes del programa en ejecución.

Cuando se ejecutó, el programa habrá creado un archivo llamado miprimero.tr. Por la forma
que Waf funciona, el archivo no se crea en el directorio local, se crea en el
directorio de nivel superior del repositorio de forma predeterminada. Si desea controlar dónde se encuentran las huellas
se guardan puede utilizar el --cwd opción de Waf para especificar esto. No lo hemos hecho, por lo que
necesitamos cambiar al directorio de nivel superior de nuestro repositorio y echar un vistazo al ASCII
archivo de seguimiento miprimero.tr en tu editor favorito.

Parsing ASCII Las huellas
Hay mucha información allí en una forma bastante densa, pero lo primero que debe notar
es que hay varias líneas distintas en este archivo. Puede ser difícil de ver
esto claramente a menos que amplíes tu ventana considerablemente.

Cada línea del archivo corresponde a una rastrear evento. En este caso estamos rastreando eventos en
los transmitir cola presente en cada dispositivo de red punto a punto en la simulación. los
cola de transmisión es una cola a través de la cual cada paquete destinado a un canal punto a punto
debe pasar Tenga en cuenta que cada línea en el archivo de seguimiento comienza con un carácter solitario (tiene un
espacio después de él). Este carácter tendrá el siguiente significado:

· +: Se produjo una operación de puesta en cola en la cola del dispositivo;

· -: Se produjo una operación de eliminación de la cola en la cola del dispositivo;

· d: Se descartó un paquete, normalmente porque la cola estaba llena;

· r: El dispositivo de red recibió un paquete.

Veamos una vista más detallada de la primera línea del archivo de seguimiento. lo desglosaré
en secciones (con sangría para mayor claridad) con un número de referencia en el lado izquierdo:

+
2
/NodeList/0/DeviceList/0/$ns3::PointToPointNetDevice/TxQueue/Enqueue
ns3::PppEncabezado (
Protocolo punto a punto: IP (0x0021))
ns3::Ipv4Encabezado (
tos 0x0 ttl 64 id 0 protocolo 17 compensación 0 indicadores [ninguno]
longitud: 1052 10.1.1.1 > 10.1.1.2)
ns3::UdpEncabezado (
longitud: 1032 49153 > 9)
Carga útil (tamaño = 1024)

La primera sección de este evento de seguimiento ampliado (número de referencia 0) es la operación. Nosotros
tiene un + carácter, por lo que esto corresponde a un En cola operación en la cola de transmisión.
El segundo apartado (referencia 1) es el tiempo de simulación expresado en segundos. Puedes
recuerda que le preguntamos al UdpEchoClientApplicationUdpEchoClientApplication para comenzar a enviar paquetes a los dos segundos.
Aquí vemos la confirmación de que esto, de hecho, está sucediendo.

La siguiente sección del seguimiento de ejemplo (referencia 2) nos dice qué fuente de seguimiento se originó
este evento (expresado en el espacio de nombres de rastreo). Puedes pensar en el espacio de nombres de seguimiento
algo así como lo haría con un espacio de nombres del sistema de archivos. La raíz del espacio de nombres es el
lista de nodos. Corresponde a un contenedor gestionado en el ns-3 código central que contiene todos
de los nodos que se crean en un script. Así como un sistema de archivos puede tener directorios
debajo de la raíz, podemos tener números de nodo en el lista de nodos. La cuerda /ListaNodos/0
por lo tanto, se refiere al nodo cero en el lista de nodos que normalmente consideramos como "nodo
0". En cada nodo hay una lista de dispositivos que se han instalado. Esta lista aparece
siguiente en el espacio de nombres. Puede ver que este evento de seguimiento proviene de Lista de dispositivos/0 cual es
el dispositivo cero instalado en el nodo.

La siguiente cadena, $ns3::DispositivoDeRedPuntoAPunto le dice qué tipo de dispositivo está en el
posición cero de la lista de dispositivos para el nodo cero. Recuerda que la operación + encontrado en
la referencia 00 significaba que se produjo una operación de puesta en cola en la cola de transmisión del dispositivo.
Esto se refleja en los segmentos finales de la "ruta de rastreo" que son TxQueue/Poner en cola.

Las secciones restantes de la traza deberían ser bastante intuitivas. Las referencias 3-4 indican
que el paquete está encapsulado en el protocolo punto a punto. Las referencias 5-7 muestran que
el paquete tiene un encabezado IP versión cuatro y se ha originado en la dirección IP 10.1.1.1 y
está destinado a 10.1.1.2. Las referencias 8-9 muestran que este paquete tiene un encabezado UDP y,
finalmente, la referencia 10 muestra que la carga útil es de los 1024 bytes esperados.

La siguiente línea en el archivo de seguimiento muestra el mismo paquete que se retira de la cola del transmisor
cola en el mismo nodo.

La tercera línea en el archivo de seguimiento muestra el paquete recibido por el dispositivo de red en el
nodo con el servidor de eco. He reproducido ese evento a continuación.

r
2.25732
/NodeList/1/DeviceList/0/$ns3::PointToPointNetDevice/MacRx
ns3::Ipv4Encabezado (
tos 0x0 ttl 64 id 0 protocolo 17 compensación 0 indicadores [ninguno]
longitud: 1052 10.1.1.1 > 10.1.1.2)
ns3::UdpEncabezado (
longitud: 1032 49153 > 9)
Carga útil (tamaño = 1024)

Observe que la operación de rastreo ahora es r y el tiempo de simulación ha aumentado a 2.25732
segundos. Si ha estado siguiendo los pasos del tutorial de cerca, esto significa que ha
dejado el Velocidad de datos de los dispositivos de red y el canal Retrasar establecidos en sus valores predeterminados.
Este tiempo debería resultarte familiar, ya que lo has visto antes en una sección anterior.

La entrada del espacio de nombres de la fuente de rastreo (referencia 02) ha cambiado para reflejar que este evento es
procedente del nodo 1 (/ListaNodos/1) y la fuente de rastreo de recepción de paquetes (/MacRx). Eso
debería ser bastante fácil para usted seguir el progreso del paquete a través de la topología
mirando el resto de las huellas en el archivo.

PCAP Rastreo
Los ns-3 Los asistentes de dispositivos también se pueden usar para crear archivos de seguimiento en el .pcap formato. La
acrónimo pcap (generalmente escrito en minúsculas) significa captura de paquetes, y en realidad es un
API que incluye la definición de un .pcap formato de archivo. El programa más popular que
puede leer y mostrar este formato es Wireshark (anteriormente llamado Ethereal). Sin embargo, hay
Hay muchos analizadores de trazas de tráfico que utilizan este formato de paquete. Animamos a los usuarios a
aproveche las muchas herramientas disponibles para analizar los rastros de pcap. En este tutorial, nosotros
concéntrese en ver los rastros de pcap con tcpdump.

El código utilizado para habilitar el seguimiento de pcap es de una sola línea.

pointToPoint.EnablePcapAll ("miprimero");

Continúe e inserte esta línea de código después del código de seguimiento ASCII que acabamos de agregar a
scratch/miprimero.cc. Observe que solo pasamos la cadena "myfirst", y no
"myfirst.pcap" o algo similar. Esto se debe a que el parámetro es un prefijo, no un
nombre de archivo completo. El ayudante en realidad creará un archivo de seguimiento para cada punto a punto
dispositivo en la simulación. Los nombres de archivo se construirán usando el prefijo, el número de nodo,
el número de dispositivo y un sufijo ".pcap".

En nuestro script de ejemplo, eventualmente veremos archivos llamados "myfirst-0-0.pcap" y
"myfirst-1-0.pcap", que son los seguimientos de pcap para el nodo 0-dispositivo 0 y el nodo 1-dispositivo 0,
respectivamente.

Una vez que haya agregado la línea de código para habilitar el seguimiento de pcap, puede ejecutar el script en el
manera usual:

$ ./waf --ejecutar cero/miprimero

Si observa el directorio de nivel superior de su distribución, ahora debería ver tres registros
archivos: miprimero.tr es el archivo de seguimiento ASCII que hemos examinado anteriormente. miprimero-0-0.pcap
y miprimero-1-0.pcap son los nuevos archivos pcap que acabamos de generar.

Reading salida con tcpdump
Lo más fácil de hacer en este punto será usar tcpdump para mirar el pcap archivos.

$ tcpdump -nn -tt -r miprimero-0-0.pcap
lectura del archivo myfirst-0-0.pcap, tipo de enlace PPP (PPP)
2.000000 IP 10.1.1.1.49153 > 10.1.1.2.9: UDP, longitud 1024
2.514648 IP 10.1.1.2.9 > 10.1.1.1.49153: UDP, longitud 1024

tcpdump -nn -tt -r miprimero-1-0.pcap
lectura del archivo myfirst-1-0.pcap, tipo de enlace PPP (PPP)
2.257324 IP 10.1.1.1.49153 > 10.1.1.2.9: UDP, longitud 1024
2.257324 IP 10.1.1.2.9 > 10.1.1.1.49153: UDP, longitud 1024

Puedes ver en el basurero de miprimero-0-0.pcap (el dispositivo cliente) que el paquete de eco es
enviado a los 2 segundos en la simulación. Si miras el segundo volcado (miprimero-1-0.pcap)
puede ver que el paquete se recibe en 2.257324 segundos. Ves el paquete siendo
repitió a los 2.257324 segundos en el segundo volcado, y finalmente, verá que el paquete se está
recibido en el cliente en el primer volcado en 2.514648 segundos.

Reading salida con Wireshark
Si no está familiarizado con Wireshark, hay un sitio web disponible desde el que puede
descargar programas y documentación: http://www.wireshark.org/.

Wireshark es una interfaz gráfica de usuario que se puede utilizar para mostrar estas trazas
archivos Si tiene Wireshark disponible, puede abrir cada uno de los archivos de rastreo y mostrar
el contenido como si hubieras capturado los paquetes usando un paquete rastreador.

EDIFICIO TOPOLOGÍAS


Contruyendo a Autobús Nuestra red topología
En esta sección vamos a ampliar nuestro dominio de ns-3 dispositivos de red y canales para
cubrir un ejemplo de una red de autobuses. ns-3 proporciona un dispositivo de red y un canal que llamamos CSMA
(El cargador Envia multiples accesos).

Los ns-3 El dispositivo CSMA modela una red simple con el espíritu de Ethernet. Una verdadera Ethernet
utiliza el esquema CSMA/CD (Carrier Sense Multiple Access with Collision Detection) con
aumentando exponencialmente el retroceso para competir por el medio de transmisión compartido. los ns-3
Los modelos de dispositivos y canales CSMA son solo un subconjunto de esto.

Tal como hemos visto objetos auxiliares de topología punto a punto al construir
topologías punto a punto, veremos asistentes de topología CSMA equivalentes en esta sección.
La apariencia y el funcionamiento de estos ayudantes le resultarán bastante familiares.

Proporcionamos un script de ejemplo en nuestro directorio Examples/tutorial}. Este guión se basa en
los primero.cc script y agrega una red CSMA a la simulación punto a punto que ya hemos
consideró. Adelante, abre ejemplos/tutorial/segundo.cc en tu editor favorito. Tú
ya habrá visto suficiente ns-3 código para entender la mayor parte de lo que está pasando en este
ejemplo, pero repasaremos todo el script y examinaremos algunos de los resultados.

Así como en el primero.cc ejemplo (y en todos los ejemplos ns-3) el archivo comienza con emacs
línea de modo y algunos repetitivos GPL.

El código real comienza cargando los archivos de inclusión del módulo tal como se hizo en el primero.cc
ejemplo.

#include "ns3 / core-module.h"
#include "ns3 / network-module.h"
#include "ns3/csma-módulo.h"
#include "ns3 / internet-module.h"
#include "ns3 / módulo-punto-a-punto.h"
#include "ns3 / applications-module.h"
#include "ns3/ipv4-global-routing-helper.h"

Una cosa que puede ser sorprendentemente útil es un pequeño fragmento de arte ASCII que muestra una caricatura
de la topología de red construida en el ejemplo. Encontrará un "dibujo" similar en
la mayoría de nuestros ejemplos.

En este caso, puede ver que vamos a extender nuestro ejemplo punto a punto (el enlace
entre los nodos n0 y n1 a continuación) colgando una red de bus del lado derecho. Aviso
que esta es la topología de red predeterminada ya que en realidad puede variar la cantidad de nodos
creado en la LAN. Si establece nCsma en uno, habrá un total de dos nodos en el
LAN (canal CSMA) --- un nodo requerido y un nodo "extra". Por defecto hay tres
nodos "extra" como se ve a continuación:

// Topología de red predeterminada
//
/ / 10.1.1.0
// n0 -------------- n1 n2 n3 n4
// punto a punto | | | |
// =================
//LAN 10.1.2.0

Entonces el espacio de nombres ns-3 es usado y se define un componente de registro. Todo esto es como
estaba en primero.cc, así que no hay nada nuevo todavía.

usando el espacio de nombres ns3;

NS_LOG_COMPONENT_DEFINE ("SecondScriptExample");

El programa principal comienza con un giro ligeramente diferente. Usamos una bandera detallada para
determinar si la UdpEchoClientApplicationUdpEchoClientApplication y UdpEchoServerApplicationUdpEchoServerApplication registro
los componentes están habilitados. Esta bandera por defecto es verdadera (los componentes de registro están habilitados)
pero nos permite desactivar el registro durante la prueba de regresión de este ejemplo.

Verá un código familiar que le permitirá cambiar la cantidad de dispositivos en el
Red CSMA mediante argumento de línea de comandos. Hicimos algo similar cuando permitimos que el
número de paquetes enviados para cambiar en la sección de argumentos de la línea de comandos. El último
line se asegura de tener al menos un nodo "extra".

El código consta de variaciones de la API cubierta anteriormente, por lo que debe estar completamente
cómodo con el siguiente código en este punto del tutorial.

bool detallado = verdadero;
uint32_t nCsma = 3;

Línea de comando cmd;
cmd.AddValue ("nCsma", "Número de nodos/dispositivos CSMA \"adicionales\", nCsma);
cmd.AddValue ("detallado", "Diga a las aplicaciones de eco que inicien sesión si es verdadero", detallado);

cmd. Parse (argc, argv);

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

nCsma = nCsma == 0 ? 1: nCsma;

El siguiente paso es crear dos nodos que conectaremos a través del enlace punto a punto.
Los Contenedor de nodo se utiliza para hacer esto tal como se hizo en primero.cc.

NodoContenedor p2pNodos;
p2pNodos.Crear (2);

A continuación, declaramos otro Contenedor de nodo para contener los nodos que formarán parte del bus
(CSMA) red. Primero, solo creamos una instancia del objeto contenedor en sí.

NodoContenedor csmaNodes;
csmaNodes.Add (p2pNodes.Get (1));
csmaNodes.Crear (nCsma);

La siguiente línea de código Obtiene el primer nodo (como si tuviera un índice de uno) del
contenedor de nodos punto a punto y lo agrega al contenedor de nodos que obtendrán CSMA
dispositivos. El nodo en cuestión va a terminar con un dispositivo punto a punto y un CSMA
dispositivo. Luego creamos una cantidad de nodos "adicionales" que componen el resto del CSMA
la red. Dado que ya tenemos un nodo en la red CSMA, el que tendrá
tanto un dispositivo de red punto a punto como CSMA, el número de nodos "extra" significa el número
nodos que desee en la sección CSMA menos uno.

El siguiente bit de código ya debería ser bastante familiar. Instanciamos un Ayudante punto a punto
y establezca el valor predeterminado asociado Atributos de modo que creamos cinco megabits por segundo
transmisor en dispositivos creados con el ayudante y un retraso de dos milisegundos en los canales
creado por el ayudante.

PuntoAPuntoAyudante puntoAPunto;
pointToPoint.SetDeviceAttribute ("Velocidad de datos", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Retraso", StringValue ("2ms"));

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

Luego instanciamos un NetDeviceContainerNetDeviceContainer para realizar un seguimiento de los dispositivos de red punto a punto
y nosotros Instalar dispositivos en los nodos punto a punto.

Mencionamos anteriormente que iba a ver un ayudante para dispositivos y canales CSMA, y
las siguientes líneas los presentan. los CsmaHelper funciona como un Ayudante punto a punto, pero
crea y conecta dispositivos y canales CSMA. En el caso de un dispositivo CSMA y
par de canales, observe que la velocidad de datos se especifica mediante un canal Atributo en lugar de un
dispositivo Atributo. Esto se debe a que una red CSMA real no permite que se mezclen, por
ejemplo, dispositivos 10Base-T y 100Base-T en un canal determinado. Primero establecemos la velocidad de datos en
100 megabits por segundo, y luego configure el retraso de la velocidad de la luz del canal en 6560
nanosegundos (elegido arbitrariamente como 1 nanosegundo por pie en un segmento de 100 metros).
Tenga en cuenta que puede establecer un Atributo utilizando su tipo de datos nativo.

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

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

Así como creamos un NetDeviceContainerNetDeviceContainer para contener los dispositivos creados por el
Ayudante punto a punto creamos un NetDeviceContainerNetDeviceContainer para sostener los dispositivos creados por nuestros
CsmaHelper. Llamamos al Instalar método de la CsmaHelper para instalar los dispositivos en el
nodos de la csmaNodos Contenedor de nodo.

Ahora tenemos nuestros nodos, dispositivos y canales creados, pero no tenemos pilas de protocolos.
presente. Así como en el primero.cc script, usaremos el Ayudante de pila de Internet instalar
estas pilas.

pila InternetStackHelper;
pila.Instalar (p2pNodes.Get (0));
pila.Instalar (csmaNodes);

Recuerde que tomamos uno de los nodos de la p2pNodos contenedor y lo agregó al
csmaNodos envase. Por lo tanto, solo necesitamos instalar las pilas en el resto p2pNodos
nodo, y todos los nodos en el csmaNodos contenedor para cubrir todos los nodos en el
simulación.

Así como en el primero.cc script de ejemplo, vamos a utilizar el Ayudante de direcciones Ipv4 a
asignar direcciones IP a nuestras interfaces de dispositivos. Primero usamos la red 10.1.1.0 para crear
las dos direcciones necesarias para nuestros dos dispositivos punto a punto.

dirección Ipv4AddressHelper;
dirección.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer p2pInterfaces;
p2pInterfaces = dirección.Assign (p2pDevices);

Recuerde que guardamos las interfaces creadas en un contenedor para facilitar su extracción.
información de direccionamiento posterior para su uso en la configuración de las aplicaciones.

Ahora necesitamos asignar direcciones IP a nuestras interfaces de dispositivos CSMA. la operacion funciona
tal como lo hizo para el caso de punto a punto, excepto que ahora estamos realizando la operación en
un contenedor que tiene un número variable de dispositivos CSMA --- recuerde que hicimos el número de
Dispositivos CSMA modificables por argumento de línea de comando. Los dispositivos CSMA se asociarán
con direcciones IP del número de red 10.1.2.0 en este caso, como se ve a continuación.

dirección.SetBase ("10.1.2.0", "255.255.255.0");
Ipv4InterfaceContainer csmaInterfaces;
csmaInterfaces = dirección. Asignar (csmaDevices);

Ahora tenemos una topología construida, pero necesitamos aplicaciones. Esta sección va a ser
fundamentalmente similar a la sección de aplicaciones de primero.cc pero vamos a
instanciar el servidor en uno de los nodos que tiene un dispositivo CSMA y el cliente en el
nodo que tiene solo un dispositivo punto a punto.

Primero, configuramos el servidor de eco. Creamos un Ayudante UdpEchoServer y proporcionar un requisito
Atributo valor al constructor que es el número de puerto del servidor. Recuerde que este puerto
se puede cambiar más tarde usando el Establecer Atributo método si lo desea, pero requerimos que sea
proporcionado al constructor.

UdpEchoServerHelper echoServer (9);

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

Recuerde que el csmaNodos Contenedor de nodo contiene uno de los nodos creados para el
red punto a punto y nCsma nodos "adicionales". A lo que queremos llegar es al último de los
nodos "adicionales". La entrada cero del csmaNodos el contenedor será el punto a punto
nodo. Entonces, la manera fácil de pensar en esto es si creamos un nodo CSMA "adicional", entonces
estará en el índice uno de los csmaNodos envase. Por inducción, si creamos nCsma "extra"
nodos el último estará en el índice nCsma. Usted ve esto exhibido en el Get de la primera
línea de código.

La aplicación cliente está configurada exactamente como lo hicimos en el primero.cc guión de ejemplo. Otra vez,
proporcionamos requerido Atributos En el correo electrónico “Su Cuenta de Usuario en su Nuevo Sistema XNUMXCX”. UdpEchoClientHelper en el constructor (en este caso
la dirección remota y el puerto). Le decimos al cliente que envíe paquetes al servidor que acabamos de
instalado en el último de los nodos CSMA "adicionales". Instalamos el cliente en el extremo izquierdo.
nodo punto a punto que se ve en la ilustración de la topología.

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

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

Como en realidad hemos construido una red aquí, necesitamos algún tipo de red
enrutamiento. ns-3 proporciona lo que llamamos enrutamiento global para ayudarlo. Tomas de enrutamiento global
ventaja del hecho de que toda la internetwork es accesible en la simulación y
se ejecuta a través de todos los nodos creados para la simulación --- hace el trabajo duro de
configurar el enrutamiento por usted sin tener que configurar los enrutadores.

Básicamente, lo que sucede es que cada nodo se comporta como si fuera un enrutador OSPF que
se comunica instantánea y mágicamente con todos los demás enrutadores detrás de escena. cada nodo
genera anuncios de enlaces y los comunica directamente a un administrador de rutas global
que utiliza esta información global para construir las tablas de enrutamiento para cada nodo. Ajuste
esta forma de enrutamiento es de una sola línea:

Ipv4GlobalRoutingHelper::PopulateRoutingTables ();

A continuación, habilitamos el seguimiento de pcap. La primera línea de código para habilitar el seguimiento de pcap en el
El ayudante punto a punto ya debería resultarle familiar. La segunda línea habilita pcap
rastreando en el ayudante de CSMA y hay un parámetro adicional que aún no ha encontrado.

pointToPoint.EnablePcapAll ("segundo");
csma.EnablePcap ("segundo", csmaDevices.Get (1), verdadero);

La red CSMA es una red multipunto a punto. Esto significa que pueden (y están en
este caso) múltiples puntos finales en un medio compartido. Cada uno de estos puntos finales tiene una red
dispositivo asociado a él. Hay dos alternativas básicas para recopilar rastros
información de dicha red. Una forma es crear un archivo de seguimiento para cada dispositivo de red.
y almacenar solo los paquetes que son emitidos o consumidos por ese dispositivo de red. De otra manera
es elegir uno de los dispositivos y colocarlo en modo promiscuo. Ese único dispositivo entonces
"olfatea" la red en busca de todos los paquetes y los almacena en un único archivo pcap. Así es como
tcpdump, por ejemplo, funciona. Ese parámetro final le dice al ayudante de CSMA si debe o no
organizar la captura de paquetes en modo promiscuo.

En este ejemplo, vamos a seleccionar uno de los dispositivos en la red CSMA y le preguntaremos
realizar un olfateo promiscuo de la red, emulando así lo que tcpdump haría.
Si estuviera en una máquina Linux, podría hacer algo como tcpdump -i eth0 para obtener el
rastro. En este caso, especificamos el dispositivo usando csmaDispositivos.Obtener(1), que selecciona el
primer dispositivo en el contenedor. Establecer el parámetro final en verdadero habilita promiscuo
capturas

La última sección del código simplemente ejecuta y limpia la simulación al igual que la primero.cc
ejemplo.

Simulador::Ejecutar ();
Simulador::Destruir ();
0 regresar;
}

Para ejecutar este ejemplo, copie el segundo.cc script de ejemplo en el directorio temporal
y use waf para construir tal como lo hizo con el primero.cc ejemplo. si estas en el
directorio de nivel superior del repositorio que acaba de escribir,

$ cp ejemplos/tutorial/segundo.cc scratch/misegundo.cc
$ ./waf

Advertencia: Usamos el archivo segundo.cc como una de nuestras pruebas de regresión para verificar que funciona
exactamente como creemos que debería ser para que su experiencia tutorial sea positiva.
Esto significa que un ejecutable llamado second ya existe en el proyecto. Para evitar cualquier
confusión sobre lo que está ejecutando, cambie el nombre a misegundo.cc sugiere
anterior.

Si está siguiendo el tutorial religiosamente (lo está haciendo, ¿no es así) todavía tendrá
la variable NS_LOG establecida, así que adelante, borre esa variable y ejecute el programa.

$ exportar NS_LOG=
$ ./waf --ejecutar cero/misegundo

Dado que hemos configurado las aplicaciones de eco UDP para iniciar sesión tal como lo hicimos en primero.cc, va a
vea un resultado similar cuando ejecute el script.

Waf: Ingresando al directorio `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Dejando el directorio `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'compilación' finalizada correctamente (0.415 s)
Enviado 1024 bytes a 10.1.2.4
1024 bytes recibidos de 10.1.1.1
1024 bytes recibidos de 10.1.2.4

Recuerde que el primer mensaje, "Sentry 1024 bytes a 10.1.2.4," es el cliente de eco UDP
enviando un paquete al servidor. En este caso, el servidor está en una red diferente
(10.1.2.0). El segundo mensaje, "Recibido 1024 bytes desde 10.1.1.1," es del eco UDP
servidor, generado cuando recibe el paquete de eco. El último mensaje, "Recibido 1024
bytes desde 10.1.2.4," es del cliente de eco, lo que indica que ha recibido su eco
de regreso del servidor.

Si ahora va y busca en el directorio de nivel superior, encontrará tres archivos de rastreo:

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

Tomemos un momento para ver el nombre de estos archivos. Todos tienen la misma forma,
- - .pcap. Por ejemplo, el primer archivo de la lista es
segundo-0-0.pcap que es la traza pcap desde el nodo cero, dispositivo cero. Este es el
dispositivo de red punto a punto en el nodo cero. El archivo segundo-1-0.pcap es la traza pcap para
dispositivo cero en el nodo uno, también un dispositivo de red punto a punto; y el archivo segundo-2-0.pcap is
el seguimiento de pcap para el dispositivo cero en el nodo dos.

Si vuelve a consultar la ilustración de topología al comienzo de la sección, verá
que el nodo cero es el nodo más a la izquierda del enlace punto a punto y el nodo uno es el nodo
que tiene un dispositivo punto a punto y un dispositivo CSMA. Verá que el nodo dos es
el primer nodo "extra" en la red CSMA y su dispositivo cero se seleccionó como el dispositivo
para capturar la traza en modo promiscuo.

Ahora, sigamos el paquete de eco a través de la red. Primero, haga un tcpdump del
archivo de rastreo para el nodo punto a punto más a la izquierda --- nodo cero.

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

Debería ver el contenido del archivo pcap mostrado:

lectura del archivo second-0-0.pcap, tipo de enlace PPP (PPP)
2.000000 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, longitud 1024
2.017607 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, longitud 1024

La primera línea del volcado indica que el tipo de enlace es PPP (punto a punto) que
suponer. Luego verá el paquete de eco que sale del nodo cero a través del dispositivo asociado con IP
la dirección 10.1.1.1 se dirigió a la dirección IP 10.1.2.4 (el nodo CSMA más a la derecha). este paquete
se moverá sobre el enlace punto a punto y será recibido por el dispositivo de red punto a punto en
nodo uno. Vamos a ver:

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

Ahora debería ver la salida de seguimiento de pcap del otro lado del enlace punto a punto:

lectura del archivo second-1-0.pcap, tipo de enlace PPP (PPP)
2.003686 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, longitud 1024
2.013921 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, longitud 1024

Aquí vemos que el tipo de enlace también es PPP como era de esperar. Ves el paquete de IP
dirección 10.1.1.1 (que se envió a los 2.000000 segundos) se dirigió hacia la dirección IP 10.1.2.4
aparecen en esta interfaz. Ahora, internamente a este nodo, el paquete se reenviará a
la interfaz CSMA y deberíamos verlo aparecer en ese dispositivo en dirección a su última
destino.

Recuerde que seleccionamos el nodo 2 como el nodo rastreador promiscuo para la red CSMA, por lo que
luego veamos second-2-0.pcap y veamos si está ahí.

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

Ahora debería ver el volcado promiscuo del nodo dos, dispositivo cero:

lectura del archivo second-2-0.pcap, tipo de enlace EN10MB (Ethernet)
2.007698 ARP, solicitar quién tiene 10.1.2.4 (ff:ff:ff:ff:ff:ff) decir 10.1.2.1, longitud 50
2.007710 ARP, respuesta 10.1.2.4 es a las 00:00:00:00:00:06, longitud 50
2.007803 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, longitud 1024
2.013815 ARP, solicitar quién tiene 10.1.2.1 (ff:ff:ff:ff:ff:ff) decir 10.1.2.4, longitud 50
2.013828 ARP, respuesta 10.1.2.1 es a las 00:00:00:00:00:03, longitud 50
2.013921 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, longitud 1024

Como puede ver, el tipo de enlace ahora es "Ethernet". Sin embargo, ha aparecido algo nuevo. los
necesidades de la red de autobuses ARP, el Protocolo de resolución de direcciones. El nodo uno sabe que necesita enviar
el paquete a la dirección IP 10.1.2.4, pero no conoce la dirección MAC del
nodo correspondiente. Emite en la red CSMA (ff:ff:ff:ff:ff:ff) preguntando por el
dispositivo que tiene dirección IP 10.1.2.4. En este caso, el nodo más a la derecha responde diciéndolo.
está en la dirección MAC 00:00:00:00:00:06. Tenga en cuenta que el nodo dos no está directamente involucrado en este
intercambio, pero está olfateando la red e informando todo el tráfico que ve.

Este intercambio se ve en las siguientes líneas,

2.007698 ARP, solicitar quién tiene 10.1.2.4 (ff:ff:ff:ff:ff:ff) decir 10.1.2.1, longitud 50
2.007710 ARP, respuesta 10.1.2.4 es a las 00:00:00:00:00:06, longitud 50

Luego, el nodo uno, el dispositivo uno continúa y envía el paquete de eco al servidor de eco UDP en
Dirección IP 10.1.2.4.

2.007803 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, longitud 1024

El servidor recibe la solicitud de eco y gira el paquete tratando de enviarlo de vuelta a
la fuente. El servidor sabe que esta dirección está en otra red a la que llega a través de
Dirección IP 10.1.2.1. Esto se debe a que inicializamos el enrutamiento global y ha calculado todo
de esto para nosotros. Pero, el nodo del servidor de eco no conoce la dirección MAC del primer
nodo CSMA, por lo que tiene que ARP para ello al igual que tuvo que hacer el primer nodo CSMA.

2.013815 ARP, solicitar quién tiene 10.1.2.1 (ff:ff:ff:ff:ff:ff) decir 10.1.2.4, longitud 50
2.013828 ARP, respuesta 10.1.2.1 es a las 00:00:00:00:00:03, longitud 50

Luego, el servidor envía el eco de regreso al nodo de reenvío.

2.013921 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, longitud 1024

Mirando hacia atrás al nodo más a la derecha del enlace punto a punto,

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

Ahora puede ver que el paquete repetido regresa al enlace punto a punto como el último
línea del volcado de seguimiento.

lectura del archivo second-1-0.pcap, tipo de enlace PPP (PPP)
2.003686 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, longitud 1024
2.013921 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, longitud 1024

Por último, puede volver a mirar el nodo que originó el eco.

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

y vea que el paquete repetido llega de vuelta a la fuente en 2.007602 segundos,

lectura del archivo second-0-0.pcap, tipo de enlace PPP (PPP)
2.000000 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, longitud 1024
2.017607 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, longitud 1024

Finalmente, recuerde que agregamos la capacidad de controlar la cantidad de dispositivos CSMA en el
simulación por argumento de línea de comando. Puede cambiar este argumento de la misma manera que cuando
buscamos cambiar la cantidad de paquetes repetidos en el primero.cc ejemplo. intenta correr
el programa con el número de dispositivos "extra" establecido en cuatro:

$ ./waf --ejecutar "scratch/misegundo --nCsma=4"

Ahora deberías ver,

Waf: Ingresando al directorio `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Dejando el directorio `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'compilación' finalizada correctamente (0.405 s)
En el momento 2s, el cliente envió 1024 bytes al puerto 10.1.2.5 9
En el momento 2.0118s, el servidor recibió 1024 bytes del puerto 10.1.1.1 49153
En el momento 2.0118s, el servidor envió 1024 bytes al puerto 10.1.1.1 49153
En el momento 2.02461, el cliente recibió 1024 bytes del puerto 10.1.2.5 9

Observe que el servidor de eco ahora se ha reubicado en el último de los nodos CSMA, que es
10.1.2.5 en lugar del caso predeterminado, 10.1.2.4.

Es posible que no esté satisfecho con un archivo de rastreo generado por un transeúnte en
la red CSMA. Es posible que realmente desee obtener un seguimiento de un solo dispositivo y es posible que no
estar interesado en cualquier otro tráfico en la red. Puedes hacer esto con bastante facilidad.

Echemos un vistazo a scratch/misegundo.cc y agregar ese código que nos permita ser más
específico. ns-3 los ayudantes proporcionan métodos que toman un número de nodo y un número de dispositivo como
parámetros Continúe y reemplace el Habilitar Pcap llamadas con las llamadas a continuación.

pointToPoint.EnablePcap ("segundo", p2pNodes.Get (0)->GetId(), 0);
csma.EnablePcap ("segundo", csmaNodes.Get (nCsma)->GetId(), 0, false);
csma.EnablePcap ("segundo", csmaNodes.Get (nCsma-1)->GetId(), 0, false);

Sabemos que queremos crear un archivo pcap con el nombre base "segundo" y también sabemos
que el dispositivo de interés en ambos casos va a ser cero, por lo que esos parámetros no son
muy interesante.

Para obtener el número de nodo, tiene dos opciones: primero, los nodos se numeran en un
aumentando monótonamente la moda a partir de cero en el orden en que se creó
a ellos. Una forma de obtener un número de nodo es averiguar este número "manualmente" por
contemplando el orden de creación de los nodos. Si echa un vistazo a la topología de la red
ilustración al comienzo del archivo, hicimos esto por usted y puede ver que el
el último nodo CSMA será el número de nodo nCsma + 1. Este enfoque puede volverse molesto
difícil en simulaciones más grandes.

Una forma alternativa, que usamos aquí, es darnos cuenta de que el Contenedores de nodos que no contengo
punteros a ns-3 Nodo Objetos. La Nodo El objeto tiene un método llamado Obtener ID que lo hará
devolver la ID de ese nodo, que es el número de nodo que buscamos. Vamos a echar un vistazo a la
doxígeno para el Nodo y ubique ese método, que está más abajo en el ns-3 código central
de lo que hemos visto hasta ahora; pero a veces hay que buscar diligentemente las cosas útiles.

Vaya a la documentación de Doxygen para su versión (recuerde que puede encontrarla en la
sitio web del proyecto). Puedes llegar a la Nodo documentación mirando a través de la
pestaña "Clases" y desplazándose hacia abajo en la "Lista de clases" hasta que encuentre ns3::Nodo. Seleccione
ns3::Nodo y se le llevará a la documentación para el Nodo clase. si tu ahora
desplácese hacia abajo hasta el Obtener ID método y selecciónelo, será llevado al detallado
documentación del método. Utilizando el Obtener ID El método puede determinar los números de nodo.
mucho más fácil en topologías complejas.

Borremos los archivos de seguimiento antiguos del directorio de nivel superior para evitar confusiones sobre
Que esta pasando,

$rm *.pcap
$rm *.tr

Si crea el nuevo script y ejecuta la configuración de simulación nCsma a 100,

$ ./waf --ejecutar "scratch/misegundo --nCsma=100"

verá el siguiente resultado:

Waf: Ingresando al directorio `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Dejando el directorio `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'compilación' finalizada correctamente (0.407 s)
En el momento 2s, el cliente envió 1024 bytes al puerto 10.1.2.101 9
En el momento 2.0068s, el servidor recibió 1024 bytes del puerto 10.1.1.1 49153
En el momento 2.0068s, el servidor envió 1024 bytes al puerto 10.1.1.1 49153
En el momento 2.01761, el cliente recibió 1024 bytes del puerto 10.1.2.101 9

Tenga en cuenta que el servidor de eco ahora se encuentra en 10.1.2.101, lo que corresponde a tener 100
Nodos CSMA "extra" con el servidor de eco en el último. Si enumera los archivos pcap en
el directorio de nivel superior que verá,

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

El archivo de rastreo segundo-0-0.pcap es el dispositivo punto a punto "más a la izquierda" que es el eco
fuente del paquete. El archivo segundo-101-0.pcap corresponde al dispositivo CSMA más a la derecha que
es donde reside el servidor de eco. Es posible que haya notado que el parámetro final en el
la llamada para habilitar el seguimiento de pcap en el nodo del servidor de eco era falsa. Esto significa que la huella
reunidos en ese nodo estaba en modo no promiscuo.

Para ilustrar la diferencia entre trazas promiscuas y no promiscuas, también
solicitó un seguimiento no promiscuo para el penúltimo nodo. Adelante, echa un vistazo a
los tcpdump for segundo-100-0.pcap.

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

Ahora puede ver que el nodo 100 es realmente un espectador en el intercambio de eco. El único
Los paquetes que recibe son las solicitudes ARP que se transmiten a todo el CSMA
red.

lectura del archivo second-100-0.pcap, tipo de enlace EN10MB (Ethernet)
2.006698 ARP, solicitar quién tiene 10.1.2.101 (ff:ff:ff:ff:ff:ff) decir 10.1.2.1, longitud 50
2.013815 ARP, solicitar quién tiene 10.1.2.1 (ff:ff:ff:ff:ff:ff) decir 10.1.2.101, longitud 50

Ahora eche un vistazo a la tcpdump for segundo-101-0.pcap.

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

Ahora puede ver que el nodo 101 es realmente el participante en el intercambio de eco.

lectura del archivo second-101-0.pcap, tipo de enlace EN10MB (Ethernet)
2.006698 ARP, solicitar quién tiene 10.1.2.101 (ff:ff:ff:ff:ff:ff) decir 10.1.2.1, longitud 50
2.006698 ARP, respuesta 10.1.2.101 es a las 00:00:00:00:00:67, longitud 50
2.006803 IP 10.1.1.1.49153 > 10.1.2.101.9: UDP, longitud 1024
2.013803 ARP, solicitar quién tiene 10.1.2.1 (ff:ff:ff:ff:ff:ff) decir 10.1.2.101, longitud 50
2.013828 ARP, respuesta 10.1.2.1 es a las 00:00:00:00:00:03, longitud 50
2.013828 IP 10.1.2.101.9 > 10.1.1.1.49153: UDP, longitud 1024

Modelos, Atributos y Realidad
Este es un lugar conveniente para hacer una pequeña excursión y hacer un punto importante. Puede
o puede no ser obvio para usted, pero cada vez que uno usa una simulación, es importante
entender exactamente qué se está modelando y qué no. Es tentador, por ejemplo,
piense en los dispositivos y canales CSMA utilizados en la sección anterior como si fueran reales
dispositivos Ethernet; y esperar que el resultado de una simulación refleje directamente lo que sucederá
en un Ethernet real. Este no es el caso.

Un modelo es, por definición, una abstracción de la realidad. En última instancia, es responsabilidad
del autor del script de simulación para determinar el llamado "rango de precisión" y "dominio
de aplicabilidad" de la simulación en su conjunto, y por tanto de sus partes constituyentes.

En algunos casos, como csma, puede ser bastante fácil determinar qué es no modelado Por
leyendo la descripción del modelo (csma.h) puede encontrar que no hay detección de colisión
en el modelo CSMA y decidir qué tan aplicable será su uso en su simulación o qué
advertencias que puede querer incluir con sus resultados. En otros casos, puede ser bastante fácil.
para configurar comportamientos que pueden no estar de acuerdo con alguna realidad puedes salir a comprar. Eso
probará que vale la pena pasar algún tiempo investigando algunos de esos casos, y cómo
fácilmente puede desviarse fuera de los límites de la realidad en sus simulaciones.

Como has visto, ns-3 proporciona un Atributos que un usuario puede configurar fácilmente para cambiar el modelo
comportamiento. Considere dos de los Atributos de las Dispositivo CsmaNet: Mtu y
Modo de encapsulación. Mtu atributo indica la Unidad Máxima de Transmisión al
dispositivo. Este es el tamaño de la unidad de datos de protocolo (PDU) más grande que el dispositivo puede
enviar.

La MTU por defecto es de 1500 bytes en el Dispositivo CsmaNet. Este valor predeterminado corresponde a un número
que se encuentra en RFC 894, "Un estándar para la transmisión de datagramas IP a través de Ethernet
Redes." El número se deriva realmente del tamaño máximo de paquete para 10Base5
(Ethernet de especificaciones completas) redes -- 1518 bytes. Si resta la encapsulación DIX
sobrecarga para paquetes Ethernet (18 bytes), terminará con un tamaño de datos máximo posible
(MTU) de 1500 bytes. También se puede encontrar que el MTU para redes IEEE 802.3 es 1492
bytes Esto se debe a que la encapsulación LLC/SNAP agrega ocho bytes adicionales de sobrecarga a
el paquete. En ambos casos, el hardware subyacente solo puede enviar 1518 bytes, pero los datos
el tamaño es diferente

Para establecer el modo de encapsulación, el Dispositivo CsmaNet proporciona un Atributo , que son
Modo de encapsulación que puede tomar los valores Dix or LLC. Estos corresponden a Ethernet
y enmarcado LLC/SNAP respectivamente.

Si uno deja el Mtu a 1500 bytes y cambia el modo de encapsulación a LLC, el resultado
será una red que encapsula PDU de 1500 bytes con tramas LLC/SNAP que dan como resultado
paquetes de 1526 bytes, lo que sería ilegal en muchas redes, ya que pueden transmitir un
máximo de 1518 bytes por paquete. Lo más probable es que esto resulte en una simulación que
bastante sutilmente no refleja la realidad que podrías estar esperando.

Solo para complicar la imagen, existen tramas gigantes (1500 < MTU <= 9000 bytes) y
super-jumbo (MTU > 9000 bytes) tramas que no están sancionadas oficialmente por IEEE pero son
disponible en algunas redes de alta velocidad (Gigabit) y NIC. Uno podría dejar el
modo de encapsulación establecido en Dixy configure el Mtu Atributo en un Dispositivo CsmaNet a 64000 bytes
-- a pesar de que un asociado CsmaCanal Velocidad de datos se fijó en 10 megabits por segundo. Este
esencialmente modelaría un conmutador Ethernet hecho de 1980Base10 al estilo de los años 5.
redes que soportan datagramas super-jumbo. Esto ciertamente no es algo que haya sido
nunca se hizo, ni es probable que se haga nunca, pero es bastante fácil de configurar.

En el ejemplo anterior, usó la línea de comando para crear una simulación que tenía 100
csma nodos. Podría haber creado fácilmente una simulación con 500 nodos. Si usted
en realidad estaban modelando esa red 10Base5 vampire-tap, la longitud máxima de una especificación completa
El cable Ethernet tiene una longitud de 500 metros, con un espacio mínimo entre derivaciones de 2.5 metros. Eso significa que hay
solo podría haber 200 toques en una red real. Podrías haber construido muy fácilmente un ilegal
red de esa manera también. Esto puede o no dar como resultado una simulación significativa.
dependiendo de lo que estés tratando de modelar.

Situaciones similares pueden ocurrir en muchos lugares en ns-3 y en cualquier simulador. Por ejemplo,
es posible que pueda colocar los nodos de tal manera que ocupen el mismo espacio en el
mismo tiempo, o puede configurar amplificadores o niveles de ruido que violen el
leyes básicas de la física.

ns-3 generalmente favorece la flexibilidad, y muchos modelos permitirán establecer libremente Atributos
sin tratar de imponer ninguna consistencia arbitraria o especificación subyacente particular.

Lo que hay que llevarse a casa de esto es que ns-3 va a proporcionar una base súper flexible
para que experimentes. Depende de usted entender lo que le está pidiendo al sistema.
hacer y asegurarse de que las simulaciones que cree tengan algún significado y alguna
conexión con una realidad definida por ti.

Contruyendo a Conectividad Nuestra red topología
En esta sección vamos a ampliar aún más nuestro conocimiento de ns-3 dispositivos de red y
canales para cubrir un ejemplo de una red inalámbrica. ns-3 proporciona un conjunto de modelos 802.11
que intentan proporcionar una implementación precisa de nivel MAC de la especificación 802.11
y un modelo de nivel PHY "no tan lento" de la especificación 802.11a.

Tal como hemos visto objetos auxiliares de topología punto a punto y CSMA cuando
construyendo topologías punto a punto, veremos equivalentes Wifi ayudantes de topología en
esta sección. La apariencia y el funcionamiento de estos ayudantes deben parecer bastante familiares para
usted

Proporcionamos un script de ejemplo en nuestro ejemplos / tutorial directorio. Este guión se basa en
los segundo.cc script y agrega una red Wifi. Adelante, abre
ejemplos/tutorial/tercero.cc en tu editor favorito. ya habrás visto suficiente
ns-3 código para entender la mayor parte de lo que está pasando en este ejemplo, pero hay algunos nuevos
cosas, así que repasaremos todo el guión y examinaremos algunos de los resultados.

Así como en el segundo.cc ejemplo (y en todo ns-3 ejemplos) el archivo comienza con un emacs
línea de modo y algunos repetitivos GPL.

Eche un vistazo al arte ASCII (reproducido a continuación) que muestra la topología de red predeterminada
construido en el ejemplo. Puede ver que vamos a ampliar aún más nuestro ejemplo.
colgando una red inalámbrica del lado izquierdo. Tenga en cuenta que esta es una red predeterminada
topología ya que en realidad puede variar la cantidad de nodos creados en la red cableada e inalámbrica
redes Así como en el segundo.cc caso de guión, si cambia nCsma, te dará un
número de nodos CSMA "adicionales". Del mismo modo, puede configurar Wifi para controlar cuantos STA
(estación) se crean nodos en la simulación. siempre habrá uno AP (punto de acceso)
nodo en la red inalámbrica. Por defecto, hay tres nodos CSMA "adicionales" y tres
sin hilos STA nodos

El código comienza cargando los archivos de inclusión del módulo tal como se hizo en el segundo.cc ejemplo.
Hay un par de novedades incluidas correspondientes al módulo Wifi y la movilidad
módulo del que hablaremos a continuación.

#include "ns3 / core-module.h"
#include "ns3 / módulo-punto-a-punto.h"
#include "ns3 / network-module.h"
#include "ns3 / applications-module.h"
#include "ns3/wifi-módulo.h"
#include "ns3/módulo de movilidad.h"
#include "ns3/csma-módulo.h"
#include "ns3 / internet-module.h"

La ilustración de la topología de red es la siguiente:

// Topología de red predeterminada
//
// Wi-Fi 10.1.3.0
// punto de acceso
// * * * *
// | | | | 10.1.1.0
// n5 n6 n7 n0 -------------- n1 n2 n3 n4
// punto a punto | | | |
// =================
//LAN 10.1.2.0

Puede ver que estamos agregando un nuevo dispositivo de red al nodo en el lado izquierdo de la
enlace punto a punto que se convierte en el punto de acceso a la red inalámbrica. Un numero de
se crean nodos STA inalámbricos para completar la nueva red 10.1.3.0 como se muestra a la izquierda
lado de la ilustración.

Después de la ilustración, el ns-3 el espacio de nombres es usado y se define un componente de registro.
Todo esto debería ser bastante familiar por ahora.

usando el espacio de nombres ns3;

NS_LOG_COMPONENT_DEFINE ("Ejemplo de tercer script");

El programa principal comienza como segundo.cc agregando algunos parámetros de línea de comando para
habilitar o deshabilitar los componentes de registro y cambiar la cantidad de dispositivos creados.

bool detallado = verdadero;
uint32_t nCsma = 3;
uint32_t nWifi = 3;

Línea de comando cmd;
cmd.AddValue ("nCsma", "Número de nodos/dispositivos CSMA \"adicionales\", nCsma);
cmd.AddValue ("nWifi", "Número de dispositivos wifi STA", nWifi);
cmd.AddValue ("detallado", "Diga a las aplicaciones de eco que inicien sesión si es verdadero", detallado);

cmd. Parse (argc, argv);

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

Al igual que en todos los ejemplos anteriores, el siguiente paso es crear dos nodos que vamos a
conectarse a través del enlace punto a punto.

NodoContenedor p2pNodos;
p2pNodos.Crear (2);

A continuación, vemos a un viejo amigo. Instanciamos un Ayudante punto a punto y establecer el asociado
tu préstamo estudiantil Atributos para que creemos un transmisor de cinco megabits por segundo en los dispositivos
creado usando el ayudante y un retraso de dos milisegundos en los canales creados por el ayudante.
Nosotros entonces Instalación los dispositivos en los nodos y el canal entre ellos.

PuntoAPuntoAyudante puntoAPunto;
pointToPoint.SetDeviceAttribute ("Velocidad de datos", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Retraso", StringValue ("2ms"));

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

A continuación, declaramos otro Contenedor de nodo para contener los nodos que formarán parte del bus
(CSMA) red.

NodoContenedor csmaNodes;
csmaNodes.Add (p2pNodes.Get (1));
csmaNodes.Crear (nCsma);

La siguiente línea de código Obtiene el primer nodo (como si tuviera un índice de uno) del
contenedor de nodos punto a punto y lo agrega al contenedor de nodos que obtendrán CSMA
dispositivos. El nodo en cuestión terminará con un dispositivo punto a punto y un CSMA
dispositivo. Luego creamos una cantidad de nodos "adicionales" que componen el resto del CSMA
red.

Luego instanciamos un CsmaHelper y establecer su Atributos como hicimos en el ejemplo anterior.
Creamos un NetDeviceContainerNetDeviceContainer para realizar un seguimiento de los dispositivos de red CSMA creados y luego
Instalar Dispositivos CSMA en los nodos seleccionados.

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

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

A continuación, vamos a crear los nodos que formarán parte de la red Wifi. Estamos
va a crear una serie de nodos de "estación" como se especifica en el argumento de la línea de comando, y
vamos a utilizar el nodo "más a la izquierda" del enlace punto a punto como el nodo para el
punto de acceso.

NodoContenedor wifiStaNodos;
wifiStaNodes.Crear (nWifi);
NodeContainer wifiApNode = p2pNodes.Get (0);

El siguiente bit de código construye los dispositivos wifi y el canal de interconexión entre
estos nodos wifi. Primero, configuramos los ayudantes de canal y PHY:

YansWifiChannelHelper canal = YansWifiChannelHelper::Default ();
YansWifiPhyHelper phy = YansWifiPhyHelper::Predeterminado ();

Para simplificar, este código usa la configuración de capa PHY predeterminada y los modelos de canal
que están documentados en la documentación API doxygen para el
YansWifiChannelHelper::Predeterminado y YansWifiPhyHelper::Predeterminado métodos. Una vez que estos objetos
se crean, creamos un objeto de canal y lo asociamos a nuestro administrador de objetos de capa PHY
para asegurarse de que todos los objetos de la capa PHY creados por el YansWifiPhyHelper compartir la
mismo canal subyacente, es decir, comparten el mismo medio inalámbrico y pueden
comunicación e interferir:

phy.SetChannel (canal.Crear ());

Una vez que se configura el ayudante PHY, podemos centrarnos en la capa MAC. Aquí elegimos trabajar
con MAC que no son Qos, por lo que usamos un objeto NqosWifiMacHelper para configurar los parámetros MAC.

WifiHelper wifi = WifiHelper::Predeterminado ();
wifi.SetRemoteStationManager ("ns3::AarfWifiManager");

NqosWifiMacHelper mac = NqosWifiMacHelper::Predeterminado ();

Los EstablecerRemoteStationManager El método le dice al ayudante el tipo de algoritmo de control de tasa a
usar. Aquí, le está pidiendo al ayudante que use el algoritmo AARF --- los detalles son, por supuesto,
disponible en Doxygen.

A continuación configuramos el tipo de MAC, el SSID de la red de infraestructura que queremos
configure y asegúrese de que nuestras estaciones no realicen un sondeo activo:

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

Este código primero crea un objeto de identificador de conjunto de servicios (SSID) 802.11 que se utilizará
para establecer el valor del "Ssid" Atributo de la implementación de la capa MAC. Lo particular
El tipo de capa MAC que creará el ayudante se especifica mediante Atributo como siendo de
el tipo "ns3::StaWifiMac". El uso de NqosWifiMacAyudante se asegurará de que el
"QosCompatible" Atributo para los objetos MAC creados se establece en falso. La combinación de estos
dos configuraciones significa que la siguiente instancia de MAC que se creará no será QoS ni AP
(STA) en una infraestructura BSS (es decir, un BSS con un AP). Finalmente, el
"Sonda activa" Atributo se establece en falso. Esto significa que las solicitudes de sondeo no serán
enviado por los MAC creados por este ayudante.

Una vez que todos los parámetros específicos de la estación estén completamente configurados, tanto en el MAC como en el PHY
capas, podemos invocar nuestro ahora familiar Instalar método para crear los dispositivos wifi de estos
estaciones:

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

Hemos configurado Wifi para todos nuestros nodos STA, y ahora necesitamos configurar el AP
(punto de acceso) nodo. Comenzamos este proceso cambiando el valor predeterminado Atributos de las
NqosWifiMacAyudante para reflejar los requisitos del AP.

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

En este caso, el NqosWifiMacAyudante va a crear capas MAC de "ns3::ApWifiMac",
este último especificando que se debe crear una instancia MAC configurada como AP, con el
tipo auxiliar, lo que implica que "QosSupported" Atributo debe establecerse en falso - deshabilitar
Compatibilidad con QoS estilo 802.11e/WMM en los puntos de acceso creados.

Las siguientes líneas crean el único AP que comparte el mismo conjunto de nivel PHY Atributos (y
canal) como las estaciones:

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

Ahora, vamos a agregar modelos de movilidad. Queremos que los nodos STA sean móviles, errantes
alrededor dentro de un cuadro delimitador, y queremos que el nodo AP sea estacionario. usamos el
ayudante de movilidad para hacer esto fácil para nosotros. Primero, instanciamos un ayudante de movilidad objeto
y establecer algunos Atributos controlando la funcionalidad "asignador de posición".

MobilityHelper movilidad;

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

Este código le dice al ayudante de movilidad que use una cuadrícula bidimensional para colocar inicialmente el
nodos STA. Siéntase libre de explorar el Doxygen para la clase ns3::Asignador de posición de cuadrícula para ver
exactamente lo que se está haciendo.

Hemos organizado nuestros nodos en una cuadrícula inicial, pero ahora debemos decirles cómo moverse.
Elegimos el Paseo aleatorio2dMovilidadModelo que hace que los nodos se muevan en una dirección aleatoria en
una velocidad aleatoria dentro de un cuadro delimitador.

movilidad.SetMobilityModel ("ns3::RandomWalk2dMobilityModel",
"Límites", RectangleValue (Rectángulo (-50, 50, -50, 50)));

Ahora le decimos a la ayudante de movilidad para instalar los modelos de movilidad en los nodos STA.

movilidad.Instalar (wifiStaNodes);

Queremos que el punto de acceso permanezca en una posición fija durante la simulación. Nosotros
lograr esto estableciendo el modelo de movilidad para que este nodo sea el
ns3::ConstantPositionMobilityModel:

movilidad.SetMobilityModel ("ns3 :: ConstantPositionMobilityModel");
movilidad.Instalar (wifiApNode);

Ya tenemos nuestros nodos, dispositivos y canales creados, y los modelos de movilidad elegidos para el
Nodos wifi, pero no tenemos pilas de protocolos presentes. Tal como hemos hecho anteriormente muchas
veces, usaremos el Ayudante de pila de Internet para instalar estas pilas.

pila InternetStackHelper;
pila.Instalar (csmaNodes);
pila.Instalar (wifiApNode);
pila.Instalar (wifiStaNodes);

Así como en el segundo.cc script de ejemplo, vamos a utilizar el Ayudante de direcciones Ipv4 a
asignar direcciones IP a nuestras interfaces de dispositivos. Primero usamos la red 10.1.1.0 para crear
las dos direcciones necesarias para nuestros dos dispositivos punto a punto. Luego usamos la red 10.1.2.0
para asignar direcciones a la red CSMA y luego asignamos direcciones desde la red 10.1.3.0
tanto a los dispositivos STA como al AP en la red inalámbrica.

dirección Ipv4AddressHelper;

dirección.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer p2pInterfaces;
p2pInterfaces = dirección.Assign (p2pDevices);

dirección.SetBase ("10.1.2.0", "255.255.255.0");
Ipv4InterfaceContainer csmaInterfaces;
csmaInterfaces = dirección. Asignar (csmaDevices);

dirección.SetBase ("10.1.3.0", "255.255.255.0");
dirección.Assign (staDevices);
dirección.Asignar (apDevices);

Colocamos el servidor de eco en el nodo "más a la derecha" en la ilustración al comienzo de la
expediente. Hemos hecho esto antes.

UdpEchoServerHelper echoServer (9);

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

Y colocamos el cliente de eco en el último nodo STA que creamos, apuntándolo al servidor en
la red CSMA. También hemos visto operaciones similares antes.

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

Aplicaciones cliente de ApplicationContainer =
echoClient.Install (wifiStaNodes.Get (nWifi - 1));
clientApps.Start (Segundos (2.0));
clientApps.Stop (Segundos (10.0));

Ya que hemos construido una interconexión de redes aquí, necesitamos habilitar el enrutamiento de interconexión de redes de la misma manera
hicimos en el segundo.cc guión de ejemplo.

Ipv4GlobalRoutingHelper::PopulateRoutingTables ();

Una cosa que puede sorprender a algunos usuarios es el hecho de que la simulación que acabamos de crear
nunca se detendrá "naturalmente". Esto se debe a que le pedimos al punto de acceso inalámbrico que
generar balizas. Generará balizas para siempre, y esto dará como resultado un simulador.
los eventos se programan en el futuro indefinidamente, por lo que debemos decirle al simulador que se detenga
aunque pueda tener programados eventos de generación de balizas. La siguiente línea de código
le dice al simulador que se detenga para que no simulemos balizas para siempre e ingrese lo que es
esencialmente un bucle sin fin.

Simulador::Detener (Segundos (10.0));

Creamos suficiente rastreo para cubrir las tres redes:

pointToPoint.EnablePcapAll ("tercero");
phy.EnablePcap ("tercero", apDevices.Get (0));
csma.EnablePcap ("tercero", csmaDevices.Get (0), verdadero);

Estas tres líneas de código iniciarán el seguimiento de pcap en los dos nodos punto a punto que
sirve como nuestra columna vertebral, iniciará un rastreo de modo promiscuo (monitor) en la red Wifi,
y comenzará un seguimiento promiscuo en la red CSMA. Esto nos permitirá ver todos los
tráfico con un número mínimo de archivos de seguimiento.

Finalmente, ejecutamos la simulación, limpiamos y luego salimos del programa.

Simulador::Ejecutar ();
Simulador::Destruir ();
0 regresar;
}

Para ejecutar este ejemplo, debe copiar el tercero.cc guión de ejemplo en el
directorio temporal y use Waf para construir tal como lo hizo con el segundo.cc ejemplo. Si usted
están en el directorio de nivel superior del repositorio que escribirías,

$ cp ejemplos/tutorial/tercero.cc scratch/mitercero.cc
$ ./waf
$ ./waf --ejecutar cero/mitercero

Una vez más, dado que hemos configurado las aplicaciones de eco UDP tal como lo hicimos en el segundo.cc
script, verá un resultado similar.

Waf: Ingresando al directorio `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Dejando el directorio `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'compilación' finalizada correctamente (0.407 s)
En el momento 2s, el cliente envió 1024 bytes al puerto 10.1.2.4 9
En el momento 2.01796s, el servidor recibió 1024 bytes del puerto 10.1.3.3 49153
En el momento 2.01796s, el servidor envió 1024 bytes al puerto 10.1.3.3 49153
En el momento 2.03364, el cliente recibió 1024 bytes del puerto 10.1.2.4 9

Recuerde que el primer mensaje, Sentry 1024 bytes a 10.1.2.4," es el cliente de eco UDP
enviando un paquete al servidor. En este caso, el cliente está en la red inalámbrica.
(10.1.3.0). El segundo mensaje, "Recibido 1024 bytes desde 10.1.3.3," es del eco UDP
servidor, generado cuando recibe el paquete de eco. El último mensaje, "Recibido 1024
bytes desde 10.1.2.4," es del cliente de eco, lo que indica que ha recibido su eco
de regreso del servidor.

Si ahora va y busca en el directorio de nivel superior, encontrará cuatro archivos de seguimiento de
esta simulación, dos del nodo cero y dos del nodo uno:

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

El archivo "tercero-0-0.pcap" corresponde al dispositivo punto a punto en el nodo cero: el
lado izquierdo de la "columna vertebral". El archivo "tercero-1-0.pcap" corresponde al punto a punto
dispositivo en el nodo uno: el lado derecho de la "columna vertebral". El archivo "tercero-0-1.pcap" será
el seguimiento promiscuo (modo monitor) de la red Wifi y el archivo "tercero-1-1.pcap"
será el rastro promiscuo de la red CSMA. ¿Puede verificar esto inspeccionando
¿el código?

Dado que el cliente de eco está en la red Wifi, comencemos allí. Echemos un vistazo a la
rastro promiscuo (modo monitor) que capturamos en esa red.

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

Deberías ver algunos contenidos de aspecto wifi que no has visto aquí antes:

lectura del archivo tercero-0-1.pcap, tipo de enlace IEEE802_11 (802.11)
0.000025 Baliza (ns-3-ssid) [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS
0.000308 Solicitud asociada (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 Respuesta asociada AYUDA(0) :: Exitoso
0.000546 Acknowledgment RA:00:00:00:00:00:0a
0.000721 Solicitud asociada (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 Respuesta asociada AYUDA(0) :: Exitoso
0.000968 Acknowledgment RA:00:00:00:00:00:0a
0.001134 Solicitud asociada (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 Respuesta asociada AYUDA(0) :: Exitoso
0.001417 Acknowledgment RA:00:00:00:00:00:0a
0.102400 Baliza (ns-3-ssid) [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS
0.204800 Baliza (ns-3-ssid) [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS
0.307200 Baliza (ns-3-ssid) [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS

Puede ver que el tipo de enlace ahora es 802.11 como era de esperar. probablemente puedas
comprenda lo que está sucediendo y encuentre los paquetes de solicitud y respuesta de eco IP en este
rastro. Lo dejamos como ejercicio para analizar completamente el volcado de seguimiento.

Ahora, mire el archivo pcap del lado derecho del enlace punto a punto,

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

Una vez más, debería ver algunos contenidos de aspecto familiar:

lectura del archivo tercero-0-0.pcap, tipo de enlace PPP (PPP)
2.008151 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, longitud 1024
2.026758 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, longitud 1024

Este es el paquete de eco que va de izquierda a derecha (de Wi-Fi a CSMA) y viceversa
el enlace punto a punto.

Ahora, mire el archivo pcap del lado derecho del enlace punto a punto,

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

Una vez más, debería ver algunos contenidos de aspecto familiar:

lectura del archivo tercero-1-0.pcap, tipo de enlace PPP (PPP)
2.011837 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, longitud 1024
2.023072 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, longitud 1024

Este es también el paquete de eco que va de izquierda a derecha (de Wifi a CSMA) y viceversa
a través del enlace punto a punto con tiempos ligeramente diferentes a los esperados.

El servidor de eco está en la red CSMA, veamos el rastro promiscuo allí:

$ tcpdump -nn -tt -r tercero-1-1.pcap

Debería ver algunos contenidos de aspecto familiar:

lectura del archivo tercero-1-1.pcap, tipo de enlace EN10MB (Ethernet)
2.017837 ARP, solicitar quién tiene 10.1.2.4 (ff:ff:ff:ff:ff:ff) decir 10.1.2.1, longitud 50
2.017861 ARP, respuesta 10.1.2.4 es a las 00:00:00:00:00:06, longitud 50
2.017861 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, longitud 1024
2.022966 ARP, solicitar quién tiene 10.1.2.1 (ff:ff:ff:ff:ff:ff) decir 10.1.2.4, longitud 50
2.022966 ARP, respuesta 10.1.2.1 es a las 00:00:00:00:00:03, longitud 50
2.023072 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, longitud 1024

Esto debe entenderse fácilmente. Si lo ha olvidado, regrese y mire la discusión.
in segundo.cc. Esta es la misma secuencia.

Ahora, dedicamos mucho tiempo a configurar modelos de movilidad para la red inalámbrica, por lo que
sería una pena terminar sin siquiera mostrar que los nodos STA se están moviendo
alrededor durante la simulación. Hagámoslo enganchándonos al MovilidadModelo curso
cambiar la fuente de seguimiento. Esto es solo un adelanto de la sección de seguimiento detallada que se encuentra
próximamente, pero este parece un buen lugar para obtener un ejemplo.

Como se mencionó en la sección "Ajustar ns-3", el ns-3 sistema de seguimiento se divide en seguimiento
fuentes y sumideros de rastreo, y proporcionamos funciones para conectar los dos. Usaremos el
modelo de movilidad cambio de curso predefinido fuente de seguimiento para originar los eventos de seguimiento. Nosotros
necesitará escribir un sumidero de seguimiento para conectarse a esa fuente que mostrará algunos bonitos
información para nosotros. A pesar de su reputación de ser difícil, en realidad es bastante simple.
Justo antes del programa principal de la scratch/mitercero.cc guión (es decir, justo después de la
NS_LOG_COMPONENT_DEFINE instrucción), agregue la siguiente función:

vacío
CourseChange (std::string context, Ptr modelo)
{
Posición del vector = modelo->GetPosition ();
NS_LOG_UNCOND (contexto <
" x = " << posición.x << ", y = " << posición.y);
}

Este código simplemente extrae la información de posición del modelo de movilidad y, de manera incondicional,
registra la posición x e y del nodo. Vamos a disponer que esta función sea
se llama cada vez que el nodo inalámbrico con el cliente de eco cambia de posición. Nosotros hacemos esto
usando el Configuración::Conectar función. Agregue las siguientes líneas de código al script solo
antes de Simulador::Ejecutar llamada.

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

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

Lo que hacemos aquí es crear una cadena que contenga la ruta del espacio de nombres de seguimiento del evento.
al que nos queremos conectar. Primero, tenemos que averiguar qué nodo es el que queremos usar
los Obtener ID método como se describió anteriormente. En el caso del número predeterminado de CSMA y
nodos inalámbricos, este resulta ser el nodo siete y la ruta del espacio de nombres de seguimiento al
modelo de movilidad sería,

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

Con base en la discusión en la sección de rastreo, puede inferir que esta ruta de rastreo
hace referencia al séptimo nodo en la NodeList global. Especifica lo que se denomina
objeto agregado de tipo ns3::Modelo de movilidad. El prefijo del signo de dólar implica que el
MobilityModel se agrega al nodo siete. El último componente del camino significa que
se conectan al evento "CourseChange" de ese modelo.

Hacemos una conexión entre la fuente de seguimiento en el nodo siete con nuestro receptor de seguimiento llamando
Configuración::Conectar y pasando esta ruta de espacio de nombres. Una vez hecho esto, cada cambio de rumbo
El evento en el nodo siete se conectará a nuestro sumidero de seguimiento, que a su vez imprimirá el
nueva posición.

Si ahora ejecuta la simulación, verá los cambios de rumbo que se muestran a medida que ocurren.

'compilación' finalizada correctamente (5.989 s)
/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
En el momento 2s, el cliente envió 1024 bytes al puerto 10.1.2.4 9
En el momento 2.01796s, el servidor recibió 1024 bytes del puerto 10.1.3.3 49153
En el momento 2.01796s, el servidor envió 1024 bytes al puerto 10.1.3.3 49153
En el momento 2.03364, el cliente recibió 1024 bytes del puerto 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

RASTREO


Antecedentes
Como se mencionó en Uso del sistema de seguimiento, el objetivo principal de ejecutar un ns-3 la simulación es para
generar salida para el estudio. Tiene dos estrategias básicas para obtener resultados de ns-3:
utilizando mecanismos genéricos de salida masiva predefinidos y analizando su contenido para extraer
información interesante; o de alguna manera desarrollar un mecanismo de salida que transmita exactamente
(y quizás sólo) la información deseada.

El uso de mecanismos de salida masiva predefinidos tiene la ventaja de no requerir ningún cambio en
ns-3, pero puede requerir escribir scripts para analizar y filtrar datos de interés. Con frecuencia,
PCAP o NS_LOG los mensajes de salida se recopilan durante las ejecuciones de simulación y se ejecutan por separado
a través de scripts que utilizan grep, SED or awk para analizar los mensajes y reducir y transformar
los datos a una forma manejable. Los programas deben escribirse para hacer la transformación, por lo que esto
no viene gratis. NS_LOG la salida no se considera parte del ns-3 API, y puede
cambiar sin previo aviso entre lanzamientos. Además, NS_LOG la salida solo está disponible en
compilaciones de depuración, por lo que confiar en él impone una penalización de rendimiento. Por supuesto, si el
información de interés no existe en ninguno de los mecanismos de salida predefinidos, esto
el enfoque falla.

Si necesita agregar un poco de información a los mecanismos masivos predefinidos, esto puede
ciertamente se hará; y si usas uno de los ns-3 mecanismos, puede obtener su código agregado
como aporte.

ns-3 proporciona otro mecanismo, llamado Rastreo, que evita algunos de los problemas inherentes
en los mecanismos de salida a granel. Tiene varias ventajas importantes. Primero, puedes
Reduzca la cantidad de datos que tiene que administrar rastreando solo los eventos que le interesan.
(para simulaciones grandes, volcar todo en el disco para el posprocesamiento puede crear E/S
cuellos de botella). En segundo lugar, si usa este método, puede controlar el formato de la salida
directamente para evitar el paso de posprocesamiento con SED, awk, perl or pitón guiones. Si
que desee, su salida se puede formatear directamente en una forma aceptable por gnuplot, por
ejemplo (ver también GnuplotHelper). Puede agregar ganchos en el núcleo que luego se pueden
accedido por otros usuarios, pero que no producirá información a menos que se le solicite explícitamente
hazlo Por estas razones, creemos que la ns-3 sistema de seguimiento es la mejor manera de obtener
información de una simulación y, por lo tanto, también es uno de los mecanismos más importantes
entender en ns-3.

embotado Instrumentos
Hay muchas formas de obtener información de un programa. La forma más directa es
para simplemente imprimir la información directamente en la salida estándar, como en:

#incluir
...
vacío
alguna función (vacío)
{
uint32_t x = ALGÚN VALOR_INTERESANTE;
...
std::cout << "El valor de x es " << x << std::endl;
...
}

Nadie te va a impedir que te adentres en el núcleo de ns-3 y añadiendo impresión
declaraciones. Esto es increíblemente fácil de hacer y, después de todo, tienes el control total de tu
propia ns-3 rama. Esto probablemente no resultará muy satisfactorio a largo plazo.
término, sin embargo.

A medida que aumenta el número de sentencias de impresión en sus programas, la tarea de tratar con las
gran número de resultados se volverá cada vez más complicado. Eventualmente, usted puede sentir
la necesidad de controlar qué información se está imprimiendo de alguna manera, tal vez encendiendo
y eliminar ciertas categorías de impresiones, o aumentar o disminuir la cantidad de
información que desea. Si continúa por este camino, puede descubrir que tiene
volvió a implementar el NS_LOG mecanismo (ver UsandoLogging). Para evitar eso, uno de
lo primero que podría considerar es usar NS_LOG misma.

Mencionamos anteriormente que una forma de obtener información de ns-3 es analizar lo existente NS_LOG
Salida para información interesante. Si descubre que algún fragmento de información que
necesidad no está presente en la salida de registro existente, puede editar el núcleo de ns-3 y simplemente agrega
su información interesante al flujo de salida. Ahora, esto es ciertamente mejor que
agregando sus propias declaraciones de impresión ya que sigue ns-3 convenciones de codificación y podría
potencialmente ser útil para otras personas como un parche para el núcleo existente.

Escojamos un ejemplo al azar. Si desea agregar más registros a la ns-3 Zócalo TCP
(tcp-socket-base.cc) podría simplemente agregar un nuevo mensaje en la implementación. Aviso
que en TcpSocketBase::RecibidoAck() no hay ningún mensaje de registro para el caso de no ACK. Tú
podría simplemente agregar uno, cambiando el código. Aquí está el original:

/** Procesar el ACK recién recibido */
vacío
TcpSocketBase::ReceivedAck (Ptr paquete, const TcpHeader& tcpHeader)
{
NS_LOG_FUNCTION (este << tcpHeader);

// Recibido ACK. Compare el número de ACK con el número de secuencia más alto sin confirmar
if (0 == (tcpHeader.GetFlags() & TcpHeader::ACK))
{ // Ignorar si no hay bandera ACK
}
...

Para registrar el caso sin ACK, puede agregar un nuevo NS_LOG_LOGIC en la categoría Industrial. if cuerpo de la declaración:

/** Procesar el ACK recién recibido */
vacío
TcpSocketBase::ReceivedAck (Ptr paquete, const TcpHeader& tcpHeader)
{
NS_LOG_FUNCTION (este << tcpHeader);

// Recibido ACK. Compare el número de ACK con el número de secuencia más alto sin confirmar
if (0 == (tcpHeader.GetFlags() & TcpHeader::ACK))
{ // Ignorar si no hay bandera ACK
NS_LOG_LOGIC ("TcpSocketBase" << esto << "sin bandera ACK");
}
...

Esto puede parecer bastante simple y satisfactorio a primera vista, pero algo a considerar es
que escribirá código para agregar NS_LOG declaraciones y también tendrá que escribir
código (como en grep, SED or awk scripts) para analizar la salida del registro con el fin de aislar su
información. Esto se debe a que, aunque tiene cierto control sobre lo que emite el
sistema de registro, solo tiene control hasta el nivel del componente de registro, que normalmente es
un archivo de código fuente completo.

Si está agregando código a un módulo existente, también tendrá que vivir con la salida
que todos los demás desarrolladores han encontrado interesante. Usted puede encontrar que para obtener la
pequeña cantidad de información que necesita, es posible que tenga que navegar a través de grandes cantidades de
mensajes extraños que no son de su interés. Es posible que se vea obligado a guardar un registro enorme
archivos en el disco y procéselos en unas pocas líneas cada vez que quiera hacer algo.

Como no hay garantías en ns-3 sobre la estabilidad de NS_LOG salida, también puede
descubra que las partes de la salida del registro de las que depende desaparecen o cambian entre
comunicados Si depende de la estructura de la salida, es posible que encuentre otros mensajes
agregado o eliminado, lo que puede afectar su código de análisis.

Finalmente, NS_LOG la salida solo está disponible en compilaciones de depuración, no puede obtener la salida del registro de
compilaciones optimizadas, que se ejecutan aproximadamente el doble de rápido. Depender de NS_LOG impone una actuación
multa.

Por estas razones, consideramos las impresiones para std :: cout y NS_LOG mensajes para ser rápido y
Maneras sucias de obtener más información de ns-3, pero no apto para trabajos serios.

Es deseable tener una instalación estable que utilice API estables que permitan llegar a
el sistema central y solo obtener la información requerida. Es deseable poder hacer
esto sin tener que cambiar y recompilar el sistema central. Aún mejor sería un
sistema que notificaba al código de usuario cuando cambiaba un elemento de interés o un evento interesante
sucedió para que el usuario no tenga que hurgar activamente en el sistema buscando
cosas.

Los ns-3 El sistema de seguimiento está diseñado para funcionar en ese sentido y está bien integrado con
el atributo y Config subsistemas que permiten escenarios de uso relativamente simples.

Descripción General
Los ns-3 El sistema de rastreo se basa en los conceptos de fuentes de rastreo independientes y
sumideros de rastreo, junto con un mecanismo uniforme para conectar fuentes a sumideros.

Las fuentes de rastreo son entidades que pueden señalar eventos que suceden en una simulación y proporcionar
acceso a datos subyacentes interesantes. Por ejemplo, una fuente de rastreo podría indicar cuándo un
paquete es recibido por un dispositivo de red y proporciona acceso al contenido del paquete para
sumideros de traza interesados. Una fuente de rastreo también podría indicar cuándo un estado interesante
el cambio ocurre en un modelo. Por ejemplo, la ventana de congestión de un modelo TCP es una primera
candidata a fuente de rastreo. Cada vez que la ventana de congestión cambia la traza conectada
los sumideros se notifican con el valor antiguo y nuevo.

Las fuentes de rastreo no son útiles por sí mismas; deben estar conectados a otras piezas de código
que realmente hacen algo útil con la información proporcionada por la fuente. los
las entidades que consumen información de seguimiento se denominan sumideros de seguimiento. Las fuentes de rastreo son
los generadores de datos y los sumideros de rastreo son consumidores. Esta división explícita permite grandes
número de fuentes de rastreo que se dispersarán por el sistema en lugares que los autores del modelo
cree que puede ser útil. La inserción de orígenes de rastreo introduce una ejecución muy pequeña
gastos generales.

Puede haber cero o más consumidores de eventos de seguimiento generados por un origen de seguimiento. Uno puede
Piense en una fuente de seguimiento como una especie de enlace de información de punto a multipunto. Tu codigo
buscar eventos de rastreo de una parte particular del código central podría coexistir felizmente con
otro código que hace algo completamente diferente a la misma información.

A menos que un usuario conecte un sumidero de rastreo a una de estas fuentes, no se genera nada. Mediante el uso
el sistema de rastreo, tanto usted como otras personas conectadas a la misma fuente de rastreo están recibiendo
exactamente lo que quieren y sólo lo que quieren del sistema. ninguno de ustedes es
impactar a cualquier otro usuario al cambiar la información que genera el sistema. Si usted
agrega una fuente de seguimiento, su trabajo como buen ciudadano de código abierto puede permitir que otros
usuarios para proporcionar nuevas utilidades que quizás sean muy útiles en general, sin hacer ningún
cambios a la ns-3 núcleo.

Fácil Ejemplo
Tomemos unos minutos y analicemos un ejemplo de rastreo simple. vamos a necesitar
un poco de información sobre las devoluciones de llamada para comprender lo que está sucediendo en el ejemplo, por lo que
hay que tomar un pequeño desvío de inmediato.

Devoluciones de llamada
El objetivo del sistema Callback en ns-3 es permitir que una pieza de código llame a una función
(o método en C++) sin ninguna dependencia específica entre módulos. Esto en última instancia significa
necesita algún tipo de direccionamiento indirecto: trata la dirección de la función llamada como un
variable. Esta variable se denomina variable puntero a función. La relación
entre función y puntero a función no es realmente diferente de la de objeto y
puntero a objeto.

En C, el ejemplo canónico de un puntero a función es un
puntero-a-función-retornando-entero (PFI). Para un PFI tomando uno int parámetro, este
podría declararse como,

int(*pfi)(intarg) = 0;

(Pero lea el C ++ - Preguntas frecuentes Sección 33 antes de escribir un código como este!) Lo que obtienes de esto
es una variable nombrada simplemente Pfi que se inicializa con el valor 0. Si desea
inicialice este puntero a algo significativo, debe tener una función con un
firma coincidente. En este caso, podría proporcionar una función que se parezca a:

int MiFunción (int arg) {}

Si tiene este objetivo, puede inicializar la variable para que apunte a su función:

pfi = MiFuncion;

Luego puede llamar a MyFunction indirectamente usando la forma más sugerente de la llamada:

resultado int = (*pfi) (1234);

Esto es sugerente ya que parece que está eliminando la referencia al puntero de función solo
como si quitaras la referencia a cualquier puntero. Por lo general, sin embargo, las personas se aprovechan de la
hecho de que el compilador sabe lo que está pasando y simplemente usará una forma más corta:

resultado int = pfi (1234);

Parece que estás llamando a una función llamada Pfi, pero el compilador es lo suficientemente inteligente como para
saber llamar a través de la variable Pfi indirectamente a la función Mifuncion.

Conceptualmente, así es casi exactamente cómo funciona el sistema de rastreo. Básicamente, un rastro
sink is una devolución de llamada Cuando un sumidero de rastreo expresa interés en recibir eventos de rastreo,
se agrega a sí mismo como una devolución de llamada a una lista de devoluciones de llamada mantenidas internamente por la fuente de seguimiento.
Cuando ocurre un evento interesante, la fuente de rastreo invoca su operador(...) proporcionando
cero o más argumentos. los operador(...) finalmente deambula por el sistema y
hace algo muy parecido a la llamada indirecta que acaba de ver, proporcionando cero o más
parámetros, al igual que la llamada a Pfi anterior pasó un parámetro a la función de destino
Mifuncion.

La diferencia importante que agrega el sistema de rastreo es que para cada fuente de rastreo hay
es una lista interna de devoluciones de llamada. En lugar de solo hacer una llamada indirecta, un rastreo
la fuente puede invocar múltiples devoluciones de llamada. Cuando un sumidero de rastreo expresa interés en
notificaciones de una fuente de rastreo, básicamente se las arregla para agregar su propia función a
la lista de devolución de llamada.

Si está interesado en obtener más detalles sobre cómo se organiza esto realmente en ns-3sentir
libre de leer detenidamente la sección de devolución de llamada de la ns-3 Manual.

Tutorial: cuarto.cc
Hemos proporcionado un código para implementar lo que realmente es el ejemplo más simple de rastreo
que se puede montar. Puede encontrar este código en el directorio de tutoriales como cuarto.cc.
Recorrámoslo:

/ * - * - Modo: C ++; estilo-archivo-c: "gnu"; indent-tabs-mode: nil; - * - * /
/*
* Este programa es software gratuito; puedes redistribuirlo y / o modificarlo
* bajo los términos de la GNU General Public License versión 2 como
* publicado por la Free Software Foundation;
*
* Este programa se distribuye con la esperanza de que sea de utilidad,
* pero SIN NINGUNA GARANTÍA; sin siquiera la garantía implícita de
* COMERCIABILIDAD o APTITUD PARA UN PROPÓSITO PARTICULAR. Ver el
* Licencia pública general GNU para más detalles.
*
* Debería haber recibido una copia de la Licencia Pública General GNU
* junto con este programa; si no, escriba al software libre
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 EE. UU.
*/

#include "ns3/objeto.h"
#incluir "ns3/uinteger.h"
#include "ns3/valor-trazado.h"
#include "ns3/trace-source-accessor.h"

#incluir

usando el espacio de nombres ns3;

La mayor parte de este código debería ser bastante familiar para usted. Como se mencionó anteriormente, el sistema de rastreo
hace un uso intensivo de los sistemas de objetos y atributos, por lo que deberá incluirlos.
Las dos primeras incluyen las declaraciones de esos sistemas de forma explícita. Tú
podría usar el encabezado del módulo central para obtener todo a la vez, pero hacemos las inclusiones
explícitamente aquí para ilustrar lo simple que es todo esto.

El archivo, valor rastreado.h aporta las declaraciones necesarias para el seguimiento de los datos que
obedece a la semántica de valores. En general, la semántica de valores solo significa que puede pasar el
objeto en sí mismo, en lugar de pasar la dirección del objeto. ¿Qué es todo esto realmente?
significa que podrá rastrear todos los cambios realizados en un TracedValue en un
manera simple.

Dado que el sistema de rastreo está integrado con Atributos, y los Atributos funcionan con Objetos,
debe haber un ns-3 Objeto para que viva la fuente de seguimiento. El siguiente fragmento de código
declara y define un objeto simple con el que podemos trabajar.

clase MiObjeto: Objeto público
{
pública:
TypeId estático GetTypeId (vacío)
{
TypeId estático tid = TypeId ("MyObject")
.SetParent (Objeto::GetTypeId ())
.AddConstructor ()
.AddTraceSource ("MiEntero",
"Un valor entero para rastrear.",
MakeTraceSourceAccessor (&MiObjeto::m_miInt),
"ns3::Rastreado::Valor::Int32Devolución de llamada")
;
volver tid;
}

MiObjeto () {}
valor rastreado m_miInt;
};

Las dos líneas de código importantes, arriba, con respecto al rastreo son las .AddTraceSource
y la valor rastreado declaración de m_miInt.

Los .AddTraceSource proporciona los "ganchos" utilizados para conectar la fuente de rastreo al
mundo exterior a través del sistema Config. El primer argumento es un nombre para este rastro.
fuente, que lo hace visible en el sistema Config. El segundo argumento es una cadena de ayuda.
Ahora mire el tercer argumento, de hecho concéntrese en el argumento del tercer argumento:
&MiObjeto::m_myInt. Este es el TracedValue que se agrega a la clase; es
siempre un miembro de datos de clase. (El argumento final es el nombre de un typedef para
tipo TracedValue, como una cadena. Esto se utiliza para generar documentación para la correcta
Firma de función de devolución de llamada, que es útil especialmente para tipos más generales de
devoluciones de llamada).

Los valor rastreado <> declaración proporciona la infraestructura que impulsa la devolución de llamada
proceso. Cada vez que se cambie el valor subyacente, el mecanismo TracedValue proporcionará
tanto el valor antiguo como el nuevo de esa variable, en este caso un int32_t valor. el rastro
la función de sumidero para este TracedValue necesitará la firma

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

Todos los sumideros de seguimiento que conectan este origen de seguimiento deben tener esta firma. Hablaremos a continuación
cómo puede determinar la firma de devolución de llamada requerida en otros casos.

Efectivamente, continuando a través de cuarto.cc vemos:

vacío
IntTrace (int32_t valor anterior, int32_t valor nuevo)
{
std::cout << "Rastreado" << oldValue << " to " << newValue << std::endl;
}

Esta es la definición de un sumidero de rastreo coincidente. Corresponde directamente a la devolución de llamada.
firma de función. Una vez conectado, se llamará a esta función siempre que el
valor rastreado cambios.

Ahora hemos visto el origen del rastro y el sumidero del rastro. Lo que queda es código para conectar el
fuente al sumidero, lo que ocurre en principal:

int
principal (int argc, char * argv [])
{
ptr miObjeto = CrearObjeto ();
myObject->TraceConnectWithoutContext ("MyInteger", MakeCallback(&IntTrace));

miObjeto->m_miInt = 1234;
}

Aquí primero creamos la instancia de MyObject en la que reside el origen de seguimiento.

El siguiente paso, el TraceConnectSinContexto, forma la conexión entre la traza
origen y el sumidero de seguimiento. El primer argumento es solo el nombre de la fuente de rastreo "MyInteger"
vimos arriba. Observe la Hacer devolución de llamada función de plantilla. Esta función hace la magia.
necesarios para crear el subyacente ns-3 objeto de devolución de llamada y asociarlo con la función
IntTrace. TrazaConectar hace la asociación entre su función proporcionada y
sobrecargado operador() en la variable trazada a la que hace referencia el atributo "MyInteger".
Después de realizar esta asociación, la fuente de seguimiento "activará" la devolución de llamada proporcionada.
función.

El código para hacer que todo esto suceda, por supuesto, no es trivial, pero la esencia es que
usted está organizando algo que se parece a la pfi() ejemplo anterior para ser llamado
por la fuente de rastreo. La declaración de la valor rastreado m_miInt; en el objeto
en sí mismo realiza la magia necesaria para proporcionar los operadores de asignación sobrecargados que
utilice el operador() para invocar realmente la devolución de llamada con los parámetros deseados. los
.AddTraceSource realiza la magia para conectar la devolución de llamada al sistema de configuración, y
TraceConnectSinContexto realiza la magia para conectar su función a la traza
origen, que se especifica mediante el nombre de atributo.

Ignoremos la parte sobre el contexto por ahora.

Finalmente, la línea que asigna un valor a m_miInt:

miObjeto->m_miInt = 1234;

debe interpretarse como una invocación de operador = en la variable miembro m_miInt con
el entero 1234 pasado como parámetro.

Since m_miInt es un valor rastreado, este operador está definido para ejecutar una devolución de llamada que
devuelve void y toma dos valores enteros como parámetros --- un valor antiguo y un valor nuevo
para el entero en cuestión. Esa es exactamente la firma de la función para la devolución de llamada.
función que proporcionamos --- IntTrace.

Para resumir, un origen de seguimiento es, en esencia, una variable que contiene una lista de devoluciones de llamada. A
Trace Sink es una función que se utiliza como destino de una devolución de llamada. El atributo y el tipo de objeto
Los sistemas de información se utilizan para proporcionar una forma de conectar las fuentes de seguimiento con los sumideros de seguimiento.
El acto de "golpear" una fuente de rastreo es ejecutar un operador en la fuente de rastreo que
dispara devoluciones de llamada. Esto da como resultado las devoluciones de llamada del sumidero de rastreo que registran interés en el
fuente que se llama con los parámetros proporcionados por la fuente.

Si ahora compila y ejecuta este ejemplo,

$ ./waf --ejecutar cuarto

verá la salida de la IntTrace la función se ejecuta tan pronto como la fuente de rastreo es
pegar:

Trazado de 0 a 1234

Cuando ejecutamos el código, miObjeto->m_myInt = 1234;, la fuente de seguimiento se disparó y
proporcionó automáticamente los valores anteriores y posteriores al receptor de seguimiento. La función
IntTrace luego imprimió esto en la salida estándar.

Conecta con Config
Los TraceConnectSinContexto llamada que se muestra arriba en el ejemplo simple es en realidad muy
rara vez se utiliza en el sistema. Más típicamente, el Config subsistema se utiliza para seleccionar una traza
fuente en el sistema usando lo que se llama un Config camino. Vimos un ejemplo de esto en el
sección anterior donde enganchamos el evento "CourseChange" cuando estábamos experimentando con
tercero.cc.

Recuerde que definimos un sumidero de seguimiento para imprimir información de cambio de curso desde la movilidad
modelos de nuestra simulación. Ahora debería estar mucho más claro para usted qué es esta función
haciendo:

vacío
CourseChange (std::string context, Ptr modelo)
{
Posición del vector = modelo->GetPosition ();
NS_LOG_UNCOND (contexto <
" x = " << posición.x << ", y = " << posición.y);
}

Cuando conectamos la fuente de rastreo "CourseChange" al sumidero de rastreo anterior, usamos un
Ruta de configuración para especificar la fuente cuando organizamos una conexión entre el predefinido
origen de seguimiento y el nuevo sumidero de seguimiento:

estándar::ostringstream oss;
oss << "/ListaNodos/"
<< wifiStaNodes.Get (nWifi - 1)->GetId()
<< "/$ns3::MobilityModel/CourseChange";

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

Intentemos darle sentido a lo que a veces se considera un código relativamente misterioso.
A los efectos de la discusión, suponga que el número de Nodo devuelto por el ObtenerId() is
"7". En este caso, el camino anterior resulta ser

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

El último segmento de una ruta de configuración debe ser un Atributo de una Objeto. De hecho, si tuvieras
un puntero al Objeto que tiene el "Cambio de Curso" Atributo práctico, podrías escribir esto
tal como lo hicimos en el ejemplo anterior. Ya sabe que normalmente almacenamos
punteros a nuestro Nodes en un contenedor de nodos. En el tercero.cc ejemplo, los Nodos de interés
se almacenan en el Wi-FiStaNodes Contenedor de nodo. De hecho, al armar el camino,
usamos este contenedor para obtener un ptr que solíamos llamar ObtenerId(). Nosotros podríamos tener
usé esto ptr para llamar a un método Connect directamente:

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

En Los tercero.cc ejemplo, en realidad queríamos que se entregara un "contexto" adicional junto con
con los parámetros de devolución de llamada (que se explicarán a continuación) para que podamos usar el
siguiente código equivalente:

ptr elObjeto = wifiStaNodes.Get (nWifi - 1);
theObject->TraceConnect ("CourseChange", MakeCallback (&CourseChange));

Resulta que el código interno para Configuración::ConectarSinContexto y Configuración::Conectar
en realidad encontrar un ptr y llame al apropiado TrazaConectar método al mínimo
.

Los Config funciones toman un camino que representa una cadena de Objeto punteros cada segmento
de una ruta corresponde a un atributo de objeto. El último segmento es el Atributo de
interés, y los segmentos anteriores deben escribirse para contener o encontrar Objetos. los Config código
analiza y "recorre" este camino hasta que llega al segmento final del camino. entonces
interpreta el último segmento como un Atributo en el último Objeto que encontró mientras caminaba por el
sendero. los Config entonces llame a la apropiada TrazaConectar or
TraceConnectSinContexto método en el objeto final. A ver que pasa en un rato
más detalle cuando se camina por el camino anterior.

El carácter "/" inicial en la ruta se refiere a un llamado espacio de nombres. Uno de los
espacios de nombres predefinidos en el sistema de configuración es "NodeList", que es una lista de todos los
nodos en la simulación. Los elementos de la lista se refieren mediante índices a la lista, por lo que
"/NodeList/7" se refiere al octavo nodo en la lista de nodos creados durante la simulación
(los índices de recuperación comienzan en 0'). Este referencia is a ``Ptr ` y también lo es un
subclase de un ns3 :: Objeto.

Como se describe en la sección Modelo de objeto del ns-3 Manual, hacemos un uso generalizado de
agregación de objetos. Esto nos permite formar una asociación entre diferentes Objetos.
sin construir un árbol de herencia complicado o predecir qué objetos serán parte
de un Nodo. Cada Objeto en una Agregación puede ser alcanzado desde los otros Objetos.

En nuestro ejemplo, el siguiente segmento de la ruta que se está recorriendo comienza con el carácter "$". Este
indica al sistema de configuración que el segmento es el nombre de un tipo de objeto, por lo que un
Getobjeto se debe llamar buscando ese tipo. resulta que el ayudante de movilidad
utilizado en tercero.cc dispone Agregar, o asociar, un modelo de movilidad a cada uno de los
sin hilos Nodes. Cuando agrega el "$", está solicitando otro Objeto que tiene
presumiblemente ha sido agregado previamente. Puede pensar en esto como cambiar punteros de
el ptr original según lo especificado por "/NodeList/7" a su modelo de movilidad asociado ---
que es de tipo ns3::Modelo de movilidad. Si está familiarizado con Getobjeto, hemos pedido
el sistema para hacer lo siguiente:

ptr modelo de movilidad = nodo->GetObject ()

Ahora estamos en el último Objeto en el camino, por lo que dirigimos nuestra atención a los Atributos de
ese Objeto. los MovilidadModelo class define un atributo llamado "CourseChange". Puedes
vea esto mirando el código fuente en src/mobility/model/mobility-model.cc y
buscando "CourseChange" en su editor favorito. deberías encontrar

.AddTraceSource ("Cambio de curso",
"El valor del vector de posición y/o velocidad cambió",
MakeTraceSourceAccessor (&MobilityModel::m_courseChangeTrace),
"ns3::MobilityModel::CourseChangeCallback")

que debería parecer muy familiar en este punto.

Si busca la declaración correspondiente de la variable rastreada subyacente en
movilidad-modelo.h se encuentra

Devolución de llamada trazada > m_TrazaCambioCurso;

La declaración de tipos Devolución de llamada trazada identifica m_courseChangeTrace como una lista especial de
Devoluciones de llamada que se pueden enganchar usando las funciones de configuración descritas anteriormente. los typedef for
la firma de la función de devolución de llamada también se define en el archivo de encabezado:

typedef void (* CourseChangeCallback)(Ptr * modelo);

Los MovilidadModelo class está diseñado para ser una clase base que proporciona una interfaz común para
todas las subclases específicas. Si busca hasta el final del archivo, verá un
método definido llamado NotificarCambioDeCurso():

vacío
MobilityModel::NotifyCourseChange (nulo) const
{
m_courseChangeTrace(esto);
}

Las clases derivadas llamarán a este método cada vez que hagan un cambio de curso para apoyar
rastreo. Este método invoca operador() en el subyacente m_courseChangeTrace, cual
invocará, a su vez, todas las devoluciones de llamada registradas, llamando a todos los sumideros de seguimiento que
ha registrado interés en el origen de seguimiento llamando a una función de configuración.

Entonces, en el tercero.cc ejemplo que vimos, cada vez que se hace un cambio de rumbo en uno de los
Paseo aleatorio2dMovilidadModelo instancias instaladas, habrá un NotificarCambioDeCurso() llamar al
que llama a la MovilidadModelo clase básica. Como se vio anteriormente, esto invoca operador()
on m_courseChangeTrace, que a su vez llama a cualquier sumidero de seguimiento registrado. En el ejemplo,
el único código que registró interés fue el código que proporcionó la ruta de configuración.
Por lo tanto, la Cambio de curso La función que se enganchó desde el Nodo número siete será la
solo se llamó la devolución de llamada.

La pieza final del rompecabezas es el "contexto". Recuerde que vimos una salida buscando
algo como lo siguiente de tercero.cc:

/NodeList/7/$ns3::MobilityModel/CourseChange x = 7.27897, y =
2.22677

La primera parte de la salida es el contexto. Es simplemente el camino a través del cual el
El código de configuración localizó la fuente de seguimiento. En el caso que hemos estado viendo puede haber
cualquier número de fuentes de rastreo en el sistema correspondiente a cualquier número de nodos con
modelos de movilidad. Tiene que haber alguna manera de identificar qué fuente de rastreo es realmente
el que disparó la devolución de llamada. La manera fácil es conectarse con Configuración::Conectaren cambio
of Configuración::ConectarSinContexto.

Encontrar Fuentes
La primera pregunta que surge inevitablemente para los nuevos usuarios del sistema de seguimiento es: "Okey,
I know que there deben be rastrear fuentes in los simulación núcleo, but how do I find out Lo que
rastrear fuentes están Estar Disponible a ¿yo?"

La segunda pregunta es "Okey, I determinaron  a rastrear fuente, how do I la figura out los Config camino
a use when I se unen a ¿eso?"

La tercera pregunta es, "Okey, I determinaron  a rastrear fuente y los Config camino, how do I la figura
out Lo que los volvemos tipo y formal argumentos of my llamar de vuelta función necesite a ¿ser?"

La cuarta pregunta es, "Okey, I mecanografiado que all in y got este vídeo incredibly extraño error
mensaje, Lo que in los mundo it ¿significar?"

Abordaremos cada uno de estos a su vez.

Disponibles Fuentes
Bueno, I know que there deben be rastrear fuentes in los simulación núcleo, but how do I find
out Lo que rastrear fuentes están Estar Disponible a yo?

La respuesta a la primera pregunta se encuentra en el ns-3 Documentación de la API. si vas a la
sitio web del proyecto, ns-3 Antecedentes, encontrará un enlace a "Documentación" en la navegación
bar. Si selecciona este enlace, será redirigido a nuestra página de documentación. Hay un
enlace a "Última versión" que lo llevará a la documentación de la última versión estable
liberarse de ns-3. Si selecciona el enlace "Documentación API", se le llevará a la
ns-3 Página de documentación de la API.

En la barra lateral debería ver una jerarquía que comienza

· ns-3

· Documentación ns-3

· Todos los TraceSources

· Todos los atributos

· Todos los valores globales

La lista que nos interesa aquí es "Todos los TraceSources". Continúe y seleccione ese enlace.
Verá, quizás no demasiado sorprendentemente, una lista de todas las fuentes de rastreo disponibles
in ns-3.

Como ejemplo, desplácese hacia abajo hasta ns3::Modelo de movilidad. Encontrará una entrada para

CourseChange: El valor de la posición y/o vector de velocidad cambiado

Debe reconocer esto como la fuente de rastreo que usamos en el tercero.cc ejemplo. hojeando
esta lista será útil.

Config Caminos
Bueno, I determinaron  a rastrear fuente, how do I la figura out los Config camino a use when I se unen a
que?

Si sabe qué objeto le interesa, la sección "Descripción detallada" para el
class enumerará todas las fuentes de seguimiento disponibles. Por ejemplo, a partir de la lista de "Todos
TraceSources", haga clic en el ns3::Modelo de movilidad enlace, que le llevará a la
documentación para el MovilidadModelo clase. Casi en la parte superior de la página hay una línea
breve descripción de la clase, terminando en un enlace "Más...". Haga clic en este enlace para saltar
el resumen de la API y vaya a la "Descripción detallada" de la clase. Al final de
descripción será (hasta) tres listas:

· Config Caminos: una lista de rutas de configuración típicas para esta clase.

· Atributos: una lista de todos los atributos proporcionados por esta clase.

· Fuentes de seguimiento: una lista de todos los TraceSources disponibles de esta clase.

Primero discutiremos las rutas de configuración.

Supongamos que acaba de encontrar la fuente de rastreo "CourseChange" en la lista "All
TraceSources" y desea averiguar cómo conectarse a ella. Sabe que está
usando (de nuevo, desde el tercero.cc ejemplo) un ns3::RandomWalk2dMobilityModel. Así que tampoco
haga clic en el nombre de la clase en la lista "All TraceSources", o busque
ns3::RandomWalk2dMobilityModel en la "Lista de clases". De cualquier manera, ahora deberías estar buscando
en la página "ns3::RandomWalk2dMobilityModel Class Reference".

Si ahora se desplaza hacia abajo hasta la sección "Descripción detallada", después de la lista resumida de
métodos y atributos de clase (o simplemente haga clic en el enlace "Más..." al final de la clase
breve descripción en la parte superior de la página) verá la documentación general para el
clase. Continúe desplazándose hacia abajo, busque la lista "Rutas de configuración":
Config Caminos

ns3::RandomWalk2dMobilityModel es accesible a través de las siguientes rutas con
Configuración::Establecer y Configuración::Conectar:

· "/NodeList/[i]/$ns3::MobilityModel/$ns3::RandomWalk2dMobilityModel"

La documentación le indica cómo llegar a la Paseo aleatorio2dMovilidadModelo Objeto. Comparar
la cadena de arriba con la cadena que realmente usamos en el código de ejemplo:

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

La diferencia se debe a que dos Getobjeto las llamadas están implícitas en la cadena encontrada
en la documentación. El primero, por $ns3::Modelo de movilidad consultará la agregación para
la clase básica. El segundo implícito Getobjeto pedir $ns3::RandomWalk2dMobilityModel,
se utiliza para convertir la clase base en la clase de implementación concreta. La documentación
muestra ambas operaciones para usted. Resulta que la fuente de seguimiento real que está
buscando se encuentra en la clase base.

Mire más abajo en la sección "Descripción detallada" para ver la lista de fuentes de seguimiento.
Va a encontrar
No se definen TraceSources para este tipo.

Fuentes de seguimiento se define in con el futuro bebé clase ``ns3::Modelo de movilidad``

· Cambio de curso: El valor del vector de posición y/o velocidad cambió.

Firma de devolución de llamada: ns3::MobilityModel::CourseChangeCallback

Esto es exactamente lo que necesitas saber. La fuente traza de interés se encuentra en
ns3::Modelo de movilidad (que usted sabía de todos modos). Lo interesante de este bit de API
La documentación le dice que no necesita ese lanzamiento adicional en la ruta de configuración anterior para
llegar a la clase concreta, ya que el origen del seguimiento está realmente en la clase base.
Por lo tanto el adicional Getobjeto no es obligatorio y simplemente usa la ruta:

"/NodeList/[i]/$ns3::MobilityModel"

que coincide perfectamente con la ruta de ejemplo:

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

Aparte, otra forma de encontrar la ruta de configuración es grep alrededor en el ns-3 base de código
para alguien que ya lo ha descubierto. Siempre debes tratar de copiar el de otra persona.
código de trabajo antes de empezar a escribir el suyo propio. Prueba algo como:

$ encontrar . -nombre '*.cc' | xargs grep Cambio de curso | grep Conectar

y puede encontrar su respuesta junto con el código de trabajo. Por ejemplo, en este caso,
src/mobility/examples/main-random-topology.cc tiene algo esperando que lo uses:

Config::Connect ("/NodeList/*/$ns3::MobilityModel/CourseChange",
Realizar devolución de llamada (&Cambio de curso));

Volveremos a este ejemplo en un momento.

Devolución de llamada Signatures
Bueno, I determinaron  a rastrear fuente y los Config camino, how do I la figura out Lo que los volvemos tipo
y formal argumentos of my llamar de vuelta función necesite a fuera?

La forma más fácil es examinar la firma de devolución de llamada typedef, que se da en el
"Firma de devolución de llamada" del origen de seguimiento en la "Descripción detallada" de la clase, como
mostrado anteriormente.

Repetición de la entrada de origen de seguimiento "CourseChange" de ns3::RandomWalk2dMobilityModel we
tener:

· Cambio de curso: El valor del vector de posición y/o velocidad cambió.

Firma de devolución de llamada: ns3::MobilityModel::CourseChangeCallback

La firma de devolución de llamada se proporciona como un enlace a la correspondiente typedef, donde encontramos
typedef vacío (* Cambio de cursoDevolución de llamada)(const std :: string contexto, ptr
MovilidadModelo> * modelo);

Devolución de llamada trazada firma para notificaciones de cambio de curso.

Si la devolución de llamada está conectada usando ConectarSinContexto omitir el contexto argumento de
la firma.

parámetros:
[en] contexto La cadena de contexto proporcionada por la fuente de rastreo.
[en] modelo El MobilityModel que está cambiando de rumbo.

Como arriba, para ver esto en uso grep alrededor en el ns-3 base de código para un ejemplo. El ejemplo
arriba, de src/mobility/examples/main-random-topology.cc, conecta el "Cambio de Curso"
rastrear la fuente hasta el Cambio de curso función en el mismo archivo:

hoyo estatico
CourseChange (std::string context, Ptr modelo)
{
...
}

Note que esta función:

· Toma un argumento de cadena de "contexto", que describiremos en un minuto. (Si la devolución de llamada
se conecta mediante el ConectarSinContexto funciona el contexto el argumento será
omitido.)

· Tiene el MovilidadModelo suministrado como último argumento (o único argumento si
ConectarSinContexto se utiliza).

· Devoluciones vacío.

Si, por casualidad, la firma de devolución de llamada no se ha documentado y no hay ejemplos para
trabajo, determinar la firma correcta de la función de devolución de llamada puede ser, bueno, un desafío para
en realidad averiguar a partir del código fuente.

Antes de embarcarme en un recorrido por el código, seré amable y le explicaré una forma sencilla
para resolver esto: el valor de retorno de su devolución de llamada siempre será vacío. El formal
lista de parámetros para un Devolución de llamada trazada se puede encontrar en la lista de parámetros de la plantilla en el
declaración. Recuerde que para nuestro ejemplo actual, esto está en movilidad-modelo.h, donde estamos
han encontrado previamente:

Devolución de llamada trazada > m_TrazaCambioCurso;

Existe una correspondencia uno a uno entre la lista de parámetros de la plantilla en el
declaración y los argumentos formales de la función de devolución de llamada. Aquí hay uno
parámetro de plantilla, que es un ptr MovilidadModelo>. Esto le dice que necesita un
función que devuelve void y toma un ptr MovilidadModelo>. Por ejemplo:

vacío
Cambio de curso (Ptr modelo)
{
...
}

Eso es todo lo que necesitas si quieres Configuración::ConectarSinContexto. Si quieres un contexto,
necesitas Configuración::Conectar y use una función de devolución de llamada que tome un contexto de cadena, luego
los argumentos de la plantilla:

vacío
CourseChange (const std::string context, Ptr modelo)
{
...
}

Si desea asegurarse de que su CursoCambiarDevolución de llamada La función solo es visible en su
archivo local, puede agregar la palabra clave estático y llegar a:

hoyo estatico
CourseChange (const std::string path, Ptr modelo)
{
...
}

que es exactamente lo que usamos en el tercero.cc ejemplo.

Implementación
Esta sección es completamente opcional. Va a ser un viaje lleno de baches, especialmente para aquellos
no está familiarizado con los detalles de las plantillas. Sin embargo, si superas esto, tendrás
un muy buen manejo de muchos de los ns-3 modismos de bajo nivel.

Entonces, nuevamente, averigüemos qué firma de la función de devolución de llamada se requiere para el
Origen de seguimiento "CourseChange". Esto va a ser doloroso, pero solo necesitas hacer esto.
una vez. Después de superar esto, podrá simplemente mirar un Devolución de llamada trazada y
entiendelo.

Lo primero que tenemos que mirar es la declaración de la fuente de rastreo. Recordar que
esto es en movilidad-modelo.h, donde previamente hemos encontrado:

Devolución de llamada trazada > m_TrazaCambioCurso;

Esta declaración es para una plantilla. El parámetro de la plantilla está dentro de los corchetes angulares,
así que estamos realmente interesados ​​en saber qué es eso Devolución de llamada trazada<> es. Si usted tiene
absolutamente ninguna idea de dónde se puede encontrar esto, grep es su amigo.

Probablemente nos va a interesar algún tipo de declaración en el ns-3 fuente, entonces
primer cambio en el src directorio. Entonces, sabemos que esta declaración va a tener que
estar en algún tipo de archivo de encabezado, así que solo grep para ello usando:

$ encontrar . -nombre '*.h' | xargs grep TracedCallback

Verás 303 líneas pasar volando (lo canalicé a través de wc para ver lo mal que estaba). A pesar de que
que puede parecer mucho, en realidad no es mucho. Simplemente canalice la salida a través de Saber más y
comience a escanear a través de él. En la primera página, verás algunos muy sospechosos.
cosas que parecen plantillas.

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 ...

Resulta que todo esto viene del archivo de cabecera rastreado-devolución de llamada.h que suena
muy prometedor. A continuación, puede echar un vistazo a movilidad-modelo.h y ver que hay una linea
lo que confirma esta corazonada:

#include "ns3/traced-callback.h"

Por supuesto, podrías haber abordado esto desde la otra dirección y haber comenzado mirando
el incluye en movilidad-modelo.h y notando la inclusión de rastreado-devolución de llamada.h y
infiriendo que este debe ser el archivo que desea.

En cualquier caso, el siguiente paso es echar un vistazo a src/core/model/traced-callback.h in
su editor favorito para ver lo que está sucediendo.

Verá un comentario en la parte superior del archivo que debería ser reconfortante:
Un ns3::TracedCallback tiene casi exactamente la misma API que un ns3::Callback normal, pero
en lugar de reenviar llamadas a una sola función (como lo hace normalmente ns3::Callback),
reenvía las llamadas a una cadena de ns3::Callback.

Esto debería sonar muy familiar y hacerle saber que está en el camino correcto.

Justo después de este comentario, encontrarás

modelo
nombre de tipo T3 = vacío, nombre de tipo T4 = vacío,
nombre de tipo T5 = vacío, nombre de tipo T6 = vacío,
nombre de tipo T7 = vacío, nombre de tipo T8 = vacío>
clase TracedCallback
{
...

Esto le indica que TracedCallback es una clase con plantilla. Tiene ocho tipos posibles
parámetros con valores predeterminados. Regrese y compare esto con la declaración que está
tratando de entender:

Devolución de llamada trazada > m_TrazaCambioCurso;

Los escribe un nombre T1 en la declaración de clase con plantilla corresponde a la ptr
MovilidadModelo> en la declaración anterior. Todos los demás parámetros de tipo se dejan como
valores predeterminados Mirar al constructor realmente no te dice mucho. El único lugar donde
ha visto que se ha realizado una conexión entre su función de devolución de llamada y el sistema de rastreo
en la categoría Industrial. Conecta y ConectarSinContexto funciones Si se desplaza hacia abajo, verá un
ConectarSinContexto método aquí:

modelo
nombre de tipo T3, nombre de tipo T4,
nombre de tipo T5, nombre de tipo T6,
nombre de tipo T7, nombre de tipo T8>
vacío
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::ConnectWithoutContext ...
{
Callback<void,T1,T2,T3,T4,T5,T6,T7,T8> cb;
cb.Assign (devolución de llamada);
m_callbackList.push_back (cb);
}

Ahora estás en el vientre de la bestia. Cuando se crea una instancia de la plantilla para el
declaración anterior, el compilador reemplazará T1 con ptr MovilidadModelo>.

vacío
Devolución de llamada trazada ::ConectarSinContexto ... cb
{
Llamar de vuelta > cb;
cb.Assign (devolución de llamada);
m_callbackList.push_back (cb);
}

Ya puedes ver la implementación de todo lo que hemos estado hablando. El código
crea una devolución de llamada del tipo correcto y le asigna su función. Este es el
equivalente de la Pfi = Mifuncion discutimos al comienzo de esta sección. El código
luego agrega la devolución de llamada a la lista de devoluciones de llamada para esta fuente. Lo único que queda es
para ver la definición de devolución de llamada. usando el mismo grep truco como solíamos encontrar
Devolución de llamada trazada, podrá encontrar que el archivo ./core/devolución de llamada.h es el que nosotros
hay que mirar

Si mira hacia abajo en el archivo, verá muchas cosas probablemente casi incomprensibles.
código de plantilla. Eventualmente llegará a alguna documentación API para la devolución de llamada
clase de plantilla, sin embargo. Afortunadamente, hay algo de inglés:
Devolución de llamada clase de plantilla.

Esta plantilla de clase implementa el patrón de diseño de Functor. Se utiliza para declarar la
tipo de un Devolución de llamada:

· el primer argumento de plantilla no opcional representa el tipo de devolución de la devolución de llamada.

· los argumentos de plantilla restantes (opcionales) representan el tipo de la subsiguiente
argumentos a la devolución de llamada.

· Se admiten hasta nueve argumentos.

Estamos tratando de averiguar cuál es el

Llamar de vuelta > cb;

medios de declaración. Ahora estamos en condiciones de entender que la primera (no opcional)
argumento de plantilla, vacío, representa el tipo de devolución de la devolución de llamada. El segundo
(opcional) argumento de plantilla, ptr MovilidadModelo> representa el tipo de la primera
argumento a la devolución de llamada.

La devolución de llamada en cuestión es su función para recibir los eventos de seguimiento. De esto puedes
infiere que necesitas una función que devuelva vacío y toma un ptr MovilidadModelo>.
Por ejemplo,

vacío
CourseChangeCallback (Ptr modelo)
{
...
}

Eso es todo lo que necesitas si quieres Configuración::ConectarSinContexto. Si quieres un contexto,
necesitas Configuración::Conectar y use una función de devolución de llamada que tome un contexto de cadena. Este
es porque el Conecta función le proporcionará el contexto. Necesitarás:

vacío
CourseChangeCallback (std::string context, Ptr modelo)
{
...
}

Si desea asegurarse de que su CursoCambiarDevolución de llamada solo es visible en su archivo local,
puedes agregar la palabra clave estático y llegar a:

hoyo estatico
CourseChangeCallback (std::string path, Ptr modelo)
{
...
}

que es exactamente lo que usamos en el tercero.cc ejemplo. Tal vez ahora debería volver atrás y
Vuelva a leer la sección anterior (Confíe en mi palabra).

Si está interesado en obtener más detalles sobre la implementación de Callbacks, no dude en
para echar un vistazo a la ns-3 manual. Son uno de los constructos más utilizados en
las partes de bajo nivel de ns-3. Es, en mi opinión, algo bastante elegante.

Valores rastreados
Anteriormente en esta sección, presentamos un código simple que usaba un
valor rastreado para demostrar los conceptos básicos del código de seguimiento. acabamos de pasar por alto
qué es realmente un TracedValue y cómo encontrar el tipo de retorno y los argumentos formales para
la devolución de llamada.

Como mencionamos, el archivo, valor rastreado.h trae las declaraciones requeridas para el rastreo
de datos que obedecen a la semántica de valores. En general, la semántica de valores solo significa que puedes
pasar el objeto en sí, en lugar de pasar la dirección del objeto. Extendemos
ese requisito para incluir el conjunto completo de operadores de estilo de asignación que son
predefinido para tipos de datos simples antiguos (POD):

-
operador = (tarea) │ │

operador*=operador/=

operador + =operador-=

operador++ (ambos prefijo y │ │
│postfijo) │ │

operador-- (ambos prefijo y │ │
│postfijo) │ │

operador<<=operador>>=

operador&=operador|=

operador%=operador^=
-

Lo que todo esto significa realmente es que podrá rastrear todos los cambios realizados con esos
operadores a un objeto C++ que tiene semántica de valor.

Los valor rastreado <> declaración que vimos arriba proporciona la infraestructura que sobrecarga el
operadores mencionados anteriormente e impulsa el proceso de devolución de llamada. En el uso de cualquiera de los operadores
arriba con un valor rastreado proporcionará tanto el valor antiguo como el nuevo de esa variable,
en este caso un int32_t valor. Por inspección de la valor rastreado declaración, conocemos la
la función de receptor de seguimiento tendrá argumentos (constante int32_t valor antiguo, const int32_t nuevo valor).
El tipo de retorno para un valor rastreado la función de devolución de llamada es siempre vacío, entonces lo esperado
la firma de devolución de llamada será:

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

Los .AddTraceSource en la categoría Industrial. ObtenerIdTipo método proporciona los "ganchos" utilizados para conectar el
rastrear la fuente al mundo exterior a través del sistema Config. Ya discutimos el
los primeros tres agruments a Agregar fuente de seguimiento: el nombre del atributo para el sistema de configuración, una ayuda
cadena y la dirección del miembro de datos de la clase TracedValue.

El argumento de cadena final, "ns3::Traced::Value::Int32" en el ejemplo, es el nombre de un
typedef para la firma de la función de devolución de llamada. Requerimos que estas firmas sean definidas,
y dar el nombre de tipo completo a Agregar fuente de seguimiento, por lo que la documentación de la API puede
vincular un origen de rastreo a la firma de la función. Para TracedValue la firma es
directo; para TracedCallbacks, ya hemos visto que los documentos de la API realmente ayudan.

Historias de Ejemplo
Hagamos un ejemplo tomado de uno de los libros más conocidos sobre TCP. "TCP/IP
Illustrated, Volume 1: The Protocols", de W. Richard Stevens es un clásico. Acabo de voltear
el libro se abrió y se encontró con una bonita trama tanto de la ventana de congestión como de la secuencia
números versus tiempo en la página 366. Stevens llama a esto, "Figura 21.10. Valor de cwnd y
envíe el número de secuencia mientras se transmiten los datos". Vamos a recrear la parte cwnd
de esa parcela en ns-3 utilizando el sistema de seguimiento y parcela gnuplot.

Disponibles Fuentes
Lo primero que hay que pensar es cómo queremos sacar los datos. ¿Qué es lo que nosotros
necesita rastrear? Entonces, consultemos la lista "Todas las fuentes de seguimiento" para ver en qué tenemos que trabajar
con. Recuérdese que esto se encuentra en el ns-3 Documentación API. Si se desplaza por la
lista, eventualmente encontrará:
ns3::TcpNuevoReno

· Ventana de congestión: La ventana de congestión de la conexión TCP

· Umbral de inicio lento: Umbral de inicio lento de TCP (bytes)

Resulta que el ns-3 La implementación de TCP vive (principalmente) en el archivo
src/internet/model/tcp-socket-base.cc mientras que las variantes de control de congestión están en archivos como
as src/internet/modelo/tcp-newreno.cc. si no sabes esto a priori, puedes usar el
recursiva grep truco:

$ encontrar . -nombre '*.cc' | xargs grep -i tcp

Encontrará página tras página de instancias de tcp que lo señalan a ese archivo.

Traer la documentación de la clase para TcpNuevoReno y saltando a la lista de
TraceSources que encontrará
Fuentes de seguimiento

· Ventana de congestión: La ventana de congestión de la conexión TCP

Firma de devolución de llamada: ns3::Rastreado::Valor::Uint322Devolución de llamada

Al hacer clic en la devolución de llamada typedef enlace vemos la firma que ahora sabe esperar:

typedef void(* ns3::Traced::Value::Int32Callback)(const int32_t oldValue, const int32_t newValue)

Ahora debería comprender este código por completo. Si tenemos un puntero a la TcpNuevoReno,
podemos TrazaConectar a la fuente de rastreo "CongestionWindow" si proporcionamos un
objetivo de devolución de llamada. Este es el mismo tipo de fuente de rastreo que vimos en el ejemplo simple
al comienzo de esta sección, excepto que estamos hablando de uint32_t en lugar de
int32_t. Y sabemos que tenemos que proporcionar una función de devolución de llamada con esa firma.

Encontrar Ejemplos
Siempre es mejor tratar de encontrar un código que funcione y que pueda modificar, en lugar de
que empezar de cero. Así que la primera orden del día ahora es encontrar algún código que
ya conecta la fuente de rastreo "CongestionWindow" y mira si podemos modificarla. Como siempre,
grep es tu amigo:

$ encontrar . -nombre '*.cc' | xargs grep Ventana de congestión

Esto señalará un par de candidatos prometedores: ejemplos/tcp/tcp-gran-transferencia.cc
y src/test/ns3tcp/ns3tcp-cwnd-test-suite.cc.

Todavía no hemos visitado ninguno de los códigos de prueba, así que echemos un vistazo allí. Vas a
normalmente encuentra que el código de prueba es bastante mínimo, por lo que esta es probablemente una muy buena apuesta.
Abierto src/test/ns3tcp/ns3tcp-cwnd-test-suite.cc en tu editor favorito y busca
"Ventana de congestión". Usted encontrará,

ns3TcpSocket->TraceConnectWithoutContext ("Ventana de congestión",
MakeCallback (&Ns3TcpCwndTestCase1::CwndChange, esto));

Esto debería parecerte muy familiar. Mencionamos anteriormente que si tuviéramos un puntero a la
TcpNuevoReno, Pudimos TrazaConectar al origen de rastreo "CongestionWindow". Eso es exactamente
lo que tenemos aquí; entonces resulta que esta línea de código hace exactamente lo que queremos.
Avancemos y extraigamos el código que necesitamos de esta función (Ns3TcpCwndTestCase1::DoRun
(vacío)). Si observa esta función, encontrará que se parece a un ns-3
guion. Resulta que eso es exactamente lo que es. Es un script ejecutado por la prueba.
marco, por lo que podemos sacarlo y envolverlo en principal en lugar de en DoRun. Bastante
que recorrer esto, paso a paso, hemos proporcionado el archivo que resulta de la portabilidad
esta prueba de vuelta a un nativo ns-3 guion -- ejemplos/tutorial/quinto.cc.

Dynamic Trace Fuentes
Los quinto.cc ejemplo demuestra una regla extremadamente importante que debe comprender
antes de usar cualquier tipo de fuente de seguimiento: debe asegurarse de que el destino de un
Configuración::Conectar el comando existe antes de intentar usarlo. Esto no es diferente a decir
un objeto debe ser instanciado antes de intentar llamarlo. Aunque esto pueda parecer obvio
cuando se dice de esta manera, hace tropezar a muchas personas que intentan usar el sistema por primera vez.
en las transacciones.

Volvamos a lo básico por un momento. Hay tres fases básicas de ejecución que existen en
any ns-3 guion. La primera fase a veces se denomina "Tiempo de configuración" o "Configuración".
Tiempo", y existe durante el período en que el principal función de su secuencia de comandos se está ejecutando, pero
antes Simulador::Ejecutar se llama. La segunda fase a veces se llama "Tiempo de simulación"
y existe durante el período de tiempo en que Simulador::Ejecutar está ejecutando activamente sus eventos.
Después de que complete la ejecución de la simulación, Simulador::Ejecutar devolverá el control a
los principal función. Cuando esto sucede, el script entra en lo que se puede llamar el "Desmontaje".
Fase", que es cuando las estructuras y los objetos creados durante la instalación se desmontan y
liberado.

Quizás el error más común que se comete al tratar de usar el sistema de rastreo es asumir que
entidades construidas dinámicamente during simulación time están disponibles durante la configuración
tiempo. En particular, un ns-3 Enchufe es un objeto dinámico a menudo creado por Aplicaciones a
comunicarse entre Nodes. Un ns-3 Nueva Solicitud de Empleo siempre tiene una "Hora de inicio" y una "Terminación
Tiempo" asociado con él. En la gran mayoría de los casos, un Nueva Solicitud de Empleo no intentará
para crear un objeto dinámico hasta que su Iniciar aplicación se llama al método en algún "Inicio
Tiempo ". Esto es para garantizar que la simulación esté completamente configurada antes de que la aplicación
intenta hacer cualquier cosa (¿qué pasaría si intentara conectarse a un nodo que no existe?
todavía durante el tiempo de configuración?). Como resultado, durante la fase de configuración no puede
conectar un origen de rastreo a un sumidero de rastreo si uno de ellos se crea dinámicamente durante el
simulación.

Las dos soluciones a este enigma son

1. Cree un evento de simulador que se ejecute después de crear el objeto dinámico y enganche el
rastrear cuándo se ejecuta ese evento; o

2. Cree el objeto dinámico en el momento de la configuración, engánchelo y entregue el objeto a
el sistema a utilizar durante el tiempo de simulación.

Tomamos el segundo enfoque en el quinto.cc ejemplo. Esta decisión nos obligó a crear
los MyApp Nueva Solicitud de Empleo, cuyo objetivo es tomar una Enchufe como un parámetro.

Tutorial: quinto.cc
Ahora, echemos un vistazo al programa de ejemplo que construimos analizando la congestión
prueba de ventana Abierto ejemplos/tutorial/quinto.cc en tu editor favorito. Debería ver
un código de aspecto familiar:

/ * - * - Modo: C ++; estilo-archivo-c: "gnu"; indent-tabs-mode: nil; - * - * /
/*
* Este programa es software gratuito; puedes redistribuirlo y / o modificarlo
* bajo los términos de la GNU General Public License versión 2 como
* publicado por la Free Software Foundation;
*
* Este programa se distribuye con la esperanza de que sea de utilidad,
* pero SIN NINGUNA GARANTÍA; sin siquiera la garantía implícita de
* COMERCIABILIDAD o APTITUD PARA UN PROPÓSITO PARTICULAR. Ver el
* Licencia pública general GNU para más detalles.
*
* Debería haber recibido una copia de la Licencia Pública General GNU
* junto con este programa; si no, escriba al software libre
* Fundación, Incluye., ​​59 Temple Place, Suite 330, Boston, MA 02111-1307 EE. UU.
*/

#incluir
#include "ns3 / core-module.h"
#include "ns3 / network-module.h"
#include "ns3 / internet-module.h"
#include "ns3 / módulo-punto-a-punto.h"
#include "ns3 / applications-module.h"

usando el espacio de nombres ns3;

NS_LOG_COMPONENT_DEFINE ("Ejemplo del Quinto Script");

Todo esto ha sido cubierto, así que no lo repetiremos. Las siguientes líneas de origen son las
ilustración de red y un comentario que aborda el problema descrito anteriormente con Enchufe.

// ================================================ ===========================
//
// nodo 0 nodo 1
// +----------------+ +----------------+
// | TCP ns-3 | | TCP ns-3 |
// +----------------+ +----------------+
// | 10.1.1.1 | | 10.1.1.2 |
// +----------------+ +----------------+
// | punto a punto | | punto a punto |
// +----------------+ +----------------+
// | |
// +-----------------------+
// 5Mbps, 2ms
//
//
// Queremos ver los cambios en la ventana de congestión TCP ns-3. Nosotros necesitamos
// para activar un flujo y enganchar el atributo CongestionWindow en el socket
// del remitente. Normalmente se usaría una aplicación on-off para generar un
// fluye, pero esto tiene un par de problemas. Primero, el zócalo del encendido-apagado
// la aplicación no se crea hasta la hora de inicio de la aplicación, por lo que no estaríamos
// Capaz de conectar el socket (ahora) en el momento de la configuración. En segundo lugar, incluso si nosotros
// podría organizar una llamada después de la hora de inicio, el socket no es público, por lo que
// no pude conseguirlo.
//
// Entonces, podemos preparar una versión simple de la aplicación de encendido y apagado que hace lo que
// queremos. En el lado positivo, no necesitamos toda la complejidad del encendido y apagado
// solicitud. En el lado negativo, no tenemos un ayudante, así que tenemos que conseguir
// un poco más involucrado en los detalles, pero esto es trivial.
//
// Así que primero, creamos un socket y hacemos la conexión de seguimiento en él; luego pasamos
// este socket en el constructor de nuestra aplicación simple que luego
// instalar en el nodo de origen.
// ================================================ ===========================
//

Esto también debería explicarse por sí mismo.

La siguiente parte es la declaración de la MyApp Nueva Solicitud de Empleo que juntamos para permitir
los Enchufe que se creará en el momento de la configuración.

clase MyApp: aplicación pública
{
pública:

MiAplicación ();
virtual ~MiAplicación();

configuración vacía (Ptr socket, dirección de dirección, tamaño de paquete uint32_t,
uint32_t nPaquetes, tasa de datos tasa de datos);

privada:
vacío virtual StartApplication (vacío);
vacío virtual StopApplication (vacío);

anular ScheduleTx (anular);
vacío SendPacket (vacío);

ptr m_zócalo;
Dirección m_peer;
uint32_t m_packetSize;
uint32_t m_nPaquetes;
Tasa de datos m_tasa de datos;
Id. de evento m_sendEvent;
bool m_corriendo;
uint32_t m_paquetes enviados;
};

Puede ver que esta clase hereda de la ns-3 Nueva Solicitud de Empleo clase. Echa un vistazo a
src/red/modelo/aplicación.h si te interesa lo que se hereda. los MyApp
la clase está obligada a anular la Iniciar aplicación y DetenerAplicación métodos. Estas
Los métodos se llaman automáticamente cuando MyApp es necesario para iniciar y detener el envío de datos
durante la simulación.

Arranque / Parada Aplicaciones
Vale la pena dedicar un poco de tiempo a explicar cómo se inician realmente los eventos en el
sistema. Esta es otra explicación bastante profunda y puede ignorarse si no está
planeando aventurarse en las tripas del sistema. Es útil, sin embargo, en que
la discusión toca cómo algunas partes muy importantes de ns-3 trabajo y expone algunos
modismos importantes. Si está planeando implementar nuevos modelos, probablemente quiera
entender esta sección.

La forma más común de iniciar eventos de bombeo es iniciar un Nueva Solicitud de Empleo. Esto se hace como
el resultado de las siguientes (con suerte) líneas familiares de un ns-3 script:

Aplicaciones de contenedor de aplicación = ...
apps.Start (Segundos (1.0));
apps.Stop (Segundos (10.0));

El código del contenedor de la aplicación (ver src/network/helper/aplicación-contenedor.h si usted es
interesado) recorre sus aplicaciones y llamadas contenidas,

aplicación->Establecerhora de inicio (hora de inicio);

como resultado de la aplicaciones.Iniciar llamar y

aplicación->EstablecerStopTime (stopTime);

como resultado de la aplicaciones. Detener llamada.

El resultado final de estas llamadas es que queremos tener el simulador automáticamente
hacer llamadas a nuestro Aplicaciones para decirles cuándo empezar y cuándo parar. En el caso de
MyApp, hereda de la clase Nueva Solicitud de Empleo y anula Iniciar aplicacióny
DetenerAplicación. Estas son las funciones que llamará el simulador en el
tiempo apropiado. En el caso de MyApp encontrarás eso MiAplicación::IniciarAplicación
la inicial aglutinantey Conecta en el socket, y luego comienza el flujo de datos llamando
MiAplicación::EnviarPaquete. MiAplicación::DetenerAplicación deja de generar paquetes al cancelar cualquier
los eventos de envío pendientes cierran el socket.

Una de las cosas buenas de ns-3 es que puedes ignorar completamente la implementación
detalles de cómo su Nueva Solicitud de Empleo es llamado "automágicamente" por el simulador en el momento correcto
tiempo. Pero como ya nos hemos adentrado en lo profundo ns-3 ya, vamos a por ello.

Si nos fijamos en src/red/modelo/aplicación.cc encontrarás que el Establecer hora de inicio Método
de una Nueva Solicitud de Empleo simplemente establece la variable miembro m_horainicio y la Establecer hora de parada Método
solo establece m_stopTime. A partir de ahí, sin algunas pistas, el camino probablemente terminará.

La clave para retomar el rastro es saber que existe una lista global de todos los
nodos en el sistema. Cada vez que crea un nodo en una simulación, un puntero a ese nodo
se agrega al mundial lista de nodos.

Eche un vistazo a src/network/model/node-list.cc y la búsqueda de Lista de nodos::Agregar. El público
la implementación estática llama a una implementación privada llamada NodeListPriv::Añadir. Esto
es un idom relativamente común en ns-3. Entonces, eche un vistazo a NodeListPriv::Añadir. Alli tu
encontrará,

Simulator::ScheduleWithContext (índice, TimeStep (0), &Node::Initialize, node);

Esto le dice que cada vez que se crea un Nodo en una simulación, como efecto secundario, una llamada
a ese nodo Inicializar método está programado para usted que sucede en el momento cero. No
leer demasiado en ese nombre, todavía. No significa que el Nodo vaya a empezar a hacer
cualquier cosa, se puede interpretar como una llamada informativa al Nodo diciéndole que el
ha comenzado la simulación, no un llamado a la acción que le dice al Nodo que comience a hacer algo.

¿Entonces Lista de nodos::Agregar indirectamente programa una llamada para Nodo::Inicializar en el momento cero para avisar a un
nuevo Nodo que ha iniciado la simulación. si miras adentro src/red/modelo/nodo.h usted
sin embargo, no encontrará un método llamado Nodo::Inicializar. resulta que el
Inicializar el método se hereda de la clase Objeto. Todos los objetos en el sistema pueden ser
notificado cuando comienza la simulación, y los objetos de clase Node son solo un tipo de esos
objetos.

Eche un vistazo a src/core/modelo/objeto.cc siguiente y busca Objeto::Inicializar. este codigo
no es tan sencillo como podría haber esperado ya que ns-3 Objetos SOPORTE
agregación. El código en Objeto::Inicializar luego recorre todos los objetos que
han sido agregados y llama a su DoInicializar método. Este es otro modismo
eso es muy común en ns-3, a veces llamado "patrón de diseño de plantilla".: un público
método de API no virtual, que se mantiene constante en todas las implementaciones y que llama a un
método de implementación virtual privado que es heredado e implementado por subclases.
Los nombres suelen ser algo así como Nombre del método para la API pública y HacerNombreMétodo for
la API privada.

Esto nos dice que debemos buscar un Nodo::DoInicializar método en
src/red/modelo/nodo.cc por el método que seguirá nuestro rastro. Si localizas el
código, encontrará un método que recorre todos los dispositivos en el nodo y luego
todas las aplicaciones en el nodo llamando dispositivo->Inicializar y aplicación->Inicializar
respectivamente.

Puede que ya sepas que las clases Device y Nueva Solicitud de Empleo ambos heredan de la clase Objeto
y entonces el próximo paso será ver qué sucede cuando Aplicación::Inicializar is
llamó. Echa un vistazo a src/red/modelo/aplicación.cc y encontrarás:

vacío
Aplicación::DoInitialize (vacío)
{
m_startEvent = Simulator::Schedule (m_startTime, &Application::StartApplication, this);
si (m_stopTime! = TimeStep (0))
{
m_stopEvent = Simulator::Schedule (m_stopTime, &Application::StopApplication, this);
}
Objeto::Inicializar ();
}

Aquí, finalmente llegamos al final del camino. Si lo has mantenido todo en orden, cuando
implementar un ns-3 Nueva Solicitud de Empleo, su nueva aplicación hereda de la clase Nueva Solicitud de Empleo. Usted
anular el Iniciar aplicación y DetenerAplicación métodos y proporcionar mecanismos para
iniciar y detener el flujo de datos de su nuevo Nueva Solicitud de Empleo. Cuando un nodo es
creado en la simulación, se agrega a un global lista de nodos. El acto de agregar un Nodo a
este vídeo lista de nodos hace que se programe un evento de simulador para el tiempo cero que llama al
Nodo::Inicializar método del nodo recién agregado que se llamará cuando comience la simulación.
Dado que un nodo hereda de Objeto, esto llama al Objeto::Inicializar método en el nodo
que, a su vez, llama al DoInicializar métodos en todos los Objetos agregado a la
Nodo (piense en modelos de movilidad). Desde el nodo Objeto ha anulado DoInicializar, Que
se llama al método cuando comienza la simulación. los Nodo::DoInicializar el método llama al
Inicializar métodos de todos los Aplicaciones en el nodo. Ya que Aplicaciones son también
Objetos, esto causa Aplicación::Inicializar ser llamado. Cuando
Aplicación::Inicializar se llama, programa eventos para el Iniciar aplicación y
DetenerAplicación llama al Nueva Solicitud de Empleo. Estas llamadas están diseñadas para iniciar y detener el
flujo de datos de la Nueva Solicitud de Empleo

Este ha sido otro viaje bastante largo, pero solo se tiene que hacer una vez, y ahora
entender otra pieza muy profunda de ns-3.

Los MyApp Nueva Solicitud de Empleo
Los MyApp Nueva Solicitud de Empleo necesita un constructor y un destructor, por supuesto:

MiAplicación::MiAplicación ()
: m_socket (0),
m_peer (),
m_packetSize (0),
m_nPaquetes (0),
m_tasa de datos (0),
m_enviarEvento (),
m_running (falso),
m_paquetes enviados (0)
{
}

MiAplicación::~MiAplicación()
{
m_zócalo = 0;
}

La existencia del siguiente bit de código es la única razón por la que escribimos esto Nueva Solicitud de Empleo in
El primer lugar.

vacío
MiAplicación::Configuración (Ptr socket, dirección de dirección, tamaño de paquete uint32_t,
uint32_t nPaquetes, tasa de datos tasa de datos)
{
m_socket = enchufe;
m_peer = dirección;
m_packetSize = paqueteTamaño;
m_nPaquetes = nPaquetes;
m_tasa de datos = tasa de datos;
}

Este código debería ser bastante autoexplicativo. Solo estamos inicializando variables miembro.
El más importante desde la perspectiva del rastreo es el ptr enchufe el cual nosotros
necesarios para proporcionar a la aplicación durante el tiempo de configuración. Recuerda que vamos
para crear el Enchufe como herramienta de edición del TcpSocket (que es implementado por TcpNuevoReno) y enganche su
origen de seguimiento "CongestionWindow" antes de pasarlo al Preparar método.

vacío
MyApp::StartApplication (vacío)
{
m_corriendo = verdadero;
m_paquetes enviados = 0;
m_socket->Enlazar ();
m_socket->Conectar (m_peer);
EnviarPaquete ();
}

El código anterior es la implementación anulada Aplicación::IniciarAplicación que será
llamado automáticamente por el simulador para iniciar nuestro Nueva Solicitud de Empleo corriendo en el lugar apropiado
tiempo. Puedes ver que hace un Enchufe aglutinante operación. Si está familiarizado con
Berkeley Sockets esto no debería ser una sorpresa. Realiza el trabajo requerido en el local.
lado de la conexión tal como cabría esperar. El seguimiento Conecta hará lo que sea
necesario para establecer una conexión con el TCP en Dirección m_peer. Ahora debería estar claro
por qué necesitamos aplazar mucho de esto al tiempo de simulación, ya que el Conecta va a necesitar
una red en pleno funcionamiento para completar. Después de la Conecta, la Nueva Solicitud de Empleo luego comienza
creando eventos de simulación llamando enviarpaquete.

El siguiente bit de código explica al Nueva Solicitud de Empleo cómo dejar de crear eventos de simulación.

vacío
MyApp::StopApplication (vacío)
{
m_corriendo = falso;

si (m_sendEvent.IsRunning ())
{
Simulador::Cancelar (m_sendEvent);
}

si (m_socket)
{
m_socket->Cerrar ();
}
}

Cada vez que se programa un evento de simulación, Eventos es creado. Si el Eventos pendiente
ejecución o ejecución, su método Isrunning regresará su verdadero. En este código, si
Esta corriendo() devuelve verdadero, nosotros Cancelar el evento que lo elimina del evento del simulador
cola. Al hacer esto, rompemos la cadena de eventos que el Nueva Solicitud de Empleo está usando para mantener
enviando su Paquetes y la Nueva Solicitud de Empleo va en silencio Después de que aquietamos Nueva Solicitud de Empleo we
Cerrar el socket que rompe la conexión TCP.

En realidad, el socket se elimina en el destructor cuando el m_socket = 0 es ejecutado. Esto
elimina la última referencia al Ptr subyacente que provoca el destructor de
ese Objeto a llamar.

Recordar que Iniciar aplicación , que son enviarpaquete para iniciar la cadena de eventos que describe
los Nueva Solicitud de Empleo comportamiento.

vacío
MiAplicación::SendPacket (vacío)
{
ptr paquete = Crear (m_packetSize);
m_socket->Enviar (paquete);

si (++m_paquetesEnviados < m_nPaquetes)
{
Programar Tx ();
}
}

Aqui ves eso enviarpaquete hace justo eso. Crea un Paquete y luego hace un Enviar
que, si conoce Berkeley Sockets, probablemente sea justo lo que esperaba ver.

Es responsabilidad del Nueva Solicitud de Empleo para seguir programando la cadena de eventos, por lo que el
próximas líneas llamar Programar Tx para programar otro evento de transmisión (un enviarpaquete) hasta el
Nueva Solicitud de Empleo decide que ha enviado suficiente.

vacío
MiAplicación::ScheduleTx (vacío)
{
si (m_corriendo)
{
Tiempo tNext (Segundos (m_packetSize * 8 / static_cast (m_dataRate.GetBitRate ())));
m_sendEvent = Simulator::Schedule (tNext, &MyApp::SendPacket, this);
}
}

Aqui ves eso Programar Tx hace exactamente eso. Si el Nueva Solicitud de Empleo está corriendo (si
DetenerAplicación no ha sido llamado) programará un nuevo evento, que llama enviarpaquete
otra vez. El lector alerta detectará algo que también hará tropezar a los nuevos usuarios. la tasa de datos
de una Nueva Solicitud de Empleo es solo eso No tiene nada que ver con la velocidad de datos de un subyacente
Channel. Esta es la tasa a la que el Nueva Solicitud de Empleo produce bits. no toma en
tener en cuenta los gastos generales de los diversos protocolos o canales que utiliza para transportar el
datos. Si establece la velocidad de datos de un Nueva Solicitud de Empleo a la misma velocidad de datos que su subyacente
Channel eventualmente obtendrá un desbordamiento de búfer.

Trace Sumideros
El objetivo de este ejercicio es obtener devoluciones de llamadas de seguimiento de TCP que indiquen el
La ventana de congestión ha sido actualizada. La siguiente pieza de código implementa el correspondiente
sumidero de rastro:

hoyo estatico
CwndChange (uint32_t OldCwnd, uint32_t NewCwnd)
{
NS_LOG_UNCOND (Simulador::Ahora ().GetSeconds () << "\t" << newCwnd);
}

Esto debería ser muy familiar para usted ahora, por lo que no nos detendremos en los detalles. Esta función
simplemente registra el tiempo de simulación actual y el nuevo valor de la ventana de congestión cada
momento en que se cambia. Probablemente puedas imaginar que podrías cargar la salida resultante
en un programa de gráficos (gnuplot o Excel) e inmediatamente verá un bonito gráfico de la
Comportamiento de la ventana de congestión a lo largo del tiempo.

Agregamos un nuevo sumidero de seguimiento para mostrar dónde se descartan los paquetes. vamos a agregar un error
modelo a este código también, así que queríamos demostrar este funcionamiento.

hoyo estatico
RxDrop (Ptr pags)
{
NS_LOG_UNCOND ("RxDrop en " << Simulador::Ahora ().GetSeconds ());
}

Este sumidero de rastreo se conectará a la fuente de rastreo "PhyRxDrop" del punto a punto
Dispositivo de red. Esta fuente de seguimiento se activa cuando la capa física de un paquete descarta un paquete.
dispositivo de red. Si tomas un pequeño desvío a la fuente
(src/punto-a-punto/modelo/punto-a-punto-net-device.cc) verás que este rastro
la fuente se refiere Dispositivo PointToPointNet::m_phyRxDropTrace. Si luego miras hacia adentro
src/punto-a-punto/modelo/punto-a-punto-net-device.h para esta variable miembro, usted
encontrar que se declara como un Devolución de llamada trazada Paquete> >. esto debería decirte
que el destino de la devolución de llamada debe ser una función que devuelve void y toma una sola
parámetro que es un ptr Paquete> (asumiendo que usamos ConectarSinContexto) -- sólo
lo que tenemos arriba.

Main Programa
El siguiente código ya debería resultarte muy familiar:

int
principal (int argc, char * argv [])
{
nodos NodeContainer;
nodos.Crear (2);

PuntoAPuntoAyudante puntoAPunto;
pointToPoint.SetDeviceAttribute ("Velocidad de datos", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Retraso", StringValue ("2ms"));

dispositivos NetDeviceContainer;
dispositivos = pointToPoint.Install (nodos);

Esto crea dos nodos con un canal punto a punto entre ellos, tal como se muestra en la
ilustración al principio del archivo.

Las siguientes líneas de código muestran algo nuevo. Si trazamos una conexión que se comporta
perfectamente, terminaremos con una ventana de congestión que aumenta monótonamente. para ver cualquiera
comportamiento interesante, realmente queremos introducir errores de enlace que descartarán paquetes,
causar ACK duplicados y desencadenar los comportamientos más interesantes de la ventana de congestión.

ns-3 proporciona un Modelo de error objetos a los que se puede unir Canales. estamos usando el
Modelo de error de tasa que nos permite introducir errores en un Channel en un determinado y .

ptr em = CrearObjeto ();
em->SetAttribute ("Tasa de error", DoubleValue (0.00001));
dispositivos.Get (1)->SetAttribute ("ReceiveErrorModel", PointerValue (em));

El código anterior instancia un Modelo de error de tasa Objeto, y establecemos el "ErrorRate" Atributo
al valor deseado. A continuación, establecemos el instanciado resultante Modelo de error de tasa como el error
modelo utilizado por el punto a punto dispositivo de red. Esto nos dará algunas retransmisiones y
hacer nuestra trama un poco más interesante.

pila InternetStackHelper;
stack.Install (nodos);

dirección Ipv4AddressHelper;
dirección.SetBase ("10.1.1.0", "255.255.255.252");
Ipv4InterfaceContainer interfaces = dirección. Asignar (dispositivos);

El código anterior debería ser familiar. Instala pilas de Internet en nuestros dos nodos y
crea interfaces y asigna direcciones IP para los dispositivos punto a punto.

Como estamos usando TCP, necesitamos algo en el nodo de destino para recibir TCP
conexiones y datos. los Disipador de paquetes Nueva Solicitud de Empleo se usa comúnmente en ns-3 para que
propósito.

uint16_t sumideroPort = 8080;
Dirección dirección del receptor (InetSocketAddress (interfaces.GetAddress (1), puerto del receptor));
PacketSinkHelper paqueteSinkHelper ("ns3::TcpSocketFactory",
InetSocketAddress (Ipv4Address::GetAny (), sumideroPort));
ApplicationContainer fregaderoApps = paqueteSinkHelper.Install (nodos.Obtener (1));
fregaderoApps.Inicio (Segundos (0.));
SinkApps.Stop (Segundos (20.));

Todo esto debería ser familiar, con la excepción de,

PacketSinkHelper paqueteSinkHelper ("ns3::TcpSocketFactory",
InetSocketAddress (Ipv4Address::GetAny (), sumideroPort));

Este código instancia un PaqueteSinkHelper y le dice que cree sockets usando la clase
ns3::TcpSocketFactory. Esta clase implementa un patrón de diseño llamado "fábrica de objetos".
que es un mecanismo comúnmente utilizado para especificar una clase utilizada para crear objetos en un
forma abstracta. Aquí, en lugar de tener que crear los objetos en sí, usted proporciona la
PaqueteSinkHelper una cadena que especifica un ID de tipo cadena utilizada para crear un objeto que
luego se puede usar, a su vez, para crear instancias de los Objetos creados por la fábrica.

El parámetro restante le dice al Nueva Solicitud de Empleo qué dirección y puerto debe aglutinante a.

Las próximas dos líneas de código crearán el socket y conectarán la fuente de rastreo.

ptr ns3TcpSocket = Socket::CreateSocket (nodos.Obtener (0),
TcpSocketFactory::GetTypeId());
ns3TcpSocket->TraceConnectWithoutContext ("Ventana de congestión",
Hacer Devolución de Llamada (&CwndChange));

La primera instrucción llama a la función miembro estática Zócalo::CrearSocket y proporciona un
Nodo y un explícito ID de tipo para la fábrica de objetos utilizada para crear el socket. Esto es un
llamada de nivel ligeramente más bajo que el PaqueteSinkHelper llama arriba, y usa un C++ explícito
type en lugar de uno al que hace referencia una cadena. Por lo demás, conceptualmente es lo mismo.
cosa.

Una vez que la TcpSocket se crea y se adjunta al Nodo, podemos usar
TraceConnectSinContexto para conectar el origen de seguimiento de CongestionWindow a nuestro receptor de seguimiento.

Recuerde que codificamos un Nueva Solicitud de Empleo para que podamos tomar eso Enchufe acabamos de hacer (durante
tiempo de configuración) y usarlo en tiempo de simulación. Ahora tenemos que instanciar que
Nueva Solicitud de Empleo. No nos molestamos en crear un ayudante para administrar el Nueva Solicitud de Empleo so
vamos a tener que crearlo e instalarlo "manualmente". Esto es bastante fácil:

ptr aplicación = CreateObject ();
aplicación->Configuración (ns3TcpSocket, dirección del fregadero, 1040, 1000, Velocidad de datos ("1 Mbps"));
nodos.Get (0)->AddApplication (aplicación);
app->Inicio (Segundos (1.));
app->Detener (Segundos (20.));

La primera línea crea un Objeto De tipo MyApp -- nuestro Nueva Solicitud de Empleo. La segunda línea dice
los Nueva Solicitud de Empleo Lo que Enchufe usar, a qué dirección conectarse, cuántos datos enviar a
cada evento de envío, cuántos eventos de envío generar y la velocidad a la que producir datos
de esos eventos.

A continuación, agregamos manualmente el MyApp Nueva Solicitud de Empleo al nodo de origen y llamar explícitamente al
Empieza y Parada métodos en el Nueva Solicitud de Empleo para decirle cuándo empezar y dejar de hacer su
cosa.

Necesitamos hacer la conexión desde el receptor punto a punto dispositivo de red evento de caída
para nuestro RxDrop devolver la llamada ahora.

dispositivos.Get (1)->TraceConnectWithoutContext("PhyRxDrop", MakeCallback (&RxDrop));

Ahora debería ser obvio que estamos recibiendo una referencia a la recepción Nodo dispositivo de red
desde su contenedor y conectando la fuente de rastreo definida por el atributo "PhyRxDrop" en
ese dispositivo al sumidero de rastreo RxDrop.

Finalmente, le decimos al simulador que anule cualquier Aplicaciones y simplemente dejar de procesar
eventos a los 20 segundos de iniciada la simulación.

Simulador::Parar (Segundos(20));
Simulador::Ejecutar ();
Simulador::Destruir ();

0 regresar;
}

Recuerda que tan pronto como Simulador::Ejecutar se llama, el tiempo de configuración finaliza y la simulación
comienza el tiempo. Todo el trabajo que orquestamos al crear el Nueva Solicitud de Empleo y enseñándolo
cómo conectarse y enviar datos realmente sucede durante esta llamada de función.

Tan pronto como Simulador::Ejecutar vuelve, la simulación está completa y entramos en el desmontaje
fase. En este caso, Simulador::Destruir se encarga de los detalles sangrientos y solo regresamos
un código de éxito después de que se complete.

Correr quinto.cc
Ya que hemos proporcionado el archivo quinto.cc para ti, si has construido tu distribución (en
modo de depuración ya que utiliza NS_LOG -- recuerda que las compilaciones optimizadas optimizan NS_LOG) eso
te estará esperando para correr.

$ ./waf --ejecutar quinto
Waf: Ingresando al directorio `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build'
Waf: dejando el directorio `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build'
'compilación' finalizada correctamente (0.684 s)
1 536
1.0093 1072
1.01528 1608
1.02167 2144
...
1.11319 8040
1.12151 8576
1.12983 9112
RxDrop en 1.13696
...

Probablemente pueda ver de inmediato una desventaja de usar impresiones de cualquier tipo en sus huellas.
Recibimos esos mensajes waf extraños impresos en toda nuestra información interesante junto con
con esos mensajes RxDrop. Remediaremos eso pronto, pero estoy seguro de que no puedes esperar a ver
los resultados de todo este trabajo. Redirijamos esa salida a un archivo llamado cwnd.dat:

$ ./waf --ejecutar quinto > cwnd.dat 2>&1

Ahora edite "cwnd.dat" en su editor favorito y elimine el estado de compilación waf y suelte
líneas, dejando sólo los datos trazados (también puede comentar el
TraceConnectWithoutContext("PhyRxDrop", Hacer devolución de llamada (&RxDrop)); en el guión para deshacerse
de la gota se imprime con la misma facilidad.

Ahora puede ejecutar gnuplot (si lo tiene instalado) y decirle que genere algunos
imágenes:

$ gnuplot
gnuplot> establecer terminal png tamaño 640,480
gnuplot> establece la salida "cwnd.png"
gnuplot> trace "cwnd.dat" usando el título 1:2 'Ventana de congestión' con puntos de línea
gnuplot> salir

Ahora debería tener un gráfico de la ventana de congestión versus el tiempo sentado en el archivo
"cwnd.png" loading="lazy" que se ve así:
[imagen]

Gracias a Nivel medio Ayudantes
En la sección anterior, mostramos cómo conectar una fuente de seguimiento y, con suerte, obtener
información interesante de una simulación. Tal vez recordará que llamamos
iniciar sesión en la salida estándar usando std :: cout un "instrumento contundente" mucho antes en este
capítulo. También escribimos sobre cómo era un problema tener que analizar la salida del registro para
para aislar información interesante. Puede que se te haya ocurrido que acabamos de gastar mucho
de tiempo implementando un ejemplo que muestra todos los problemas que pretendemos solucionar con
los ns-3 sistema de seguimiento! Estarías en lo correcto. Pero, tengan paciencia con nosotros. Aún no hemos terminado.

Una de las cosas más importantes que queremos hacer es tener la capacidad de
controlar la cantidad de salida que sale de la simulación; y también queremos salvar esos
datos a un archivo para que podamos consultarlo más tarde. Podemos usar los ayudantes de seguimiento de nivel medio
proporcionada en ns-3 para hacer precisamente eso y completar el cuadro.

Proporcionamos un script que escribe los eventos cwnd change y drop desarrollados en el ejemplo
quinto.cc al disco en archivos separados. Los cambios de cwnd se almacenan como un ASCII separado por tabulaciones
y los eventos de caída se almacenan en un archivo PCAP. Los cambios para que esto suceda son
bastante pequeño.

Tutorial: sexto.cc
Echemos un vistazo a los cambios necesarios para pasar de quinto.cc a sexto.cc. Abierto
ejemplos/tutorial/sexto.cc en tu editor favorito. Puedes ver el primer cambio por
buscando CwndChange. Encontrará que hemos cambiado las firmas para el seguimiento.
sumideros y he agregado una sola línea a cada sumidero que escribe la información rastreada en un
flujo que representa un archivo.

hoyo estatico
CwndChange (Ptr corriente, uint32_t oldCwnd, uint32_t newCwnd)
{
NS_LOG_UNCOND (Simulador::Ahora ().GetSeconds () << "\t" << newCwnd);
*stream->GetStream () << Simulator::Now ().GetSeconds () << "\t" << oldCwnd << "\t" << newCwnd << std::endl;
}

hoyo estatico
RxDrop (Ptr archivo, punto pags)
{
NS_LOG_UNCOND ("RxDrop en " << Simulador::Ahora ().GetSeconds ());
archivo->Escribir(Simulador::Ahora(), p);
}

Hemos agregado un parámetro de "flujo" al CwndCambiar sumidero de rastro. Este es un objeto que
contiene (mantiene vivo de forma segura) un flujo de salida de C++. Resulta que esto es muy simple.
objeto, pero que gestiona los problemas de por vida para la transmisión y resuelve un problema que incluso
se encuentran los usuarios experimentados de C++. Resulta que el constructor de copias para estándar::ostream
está marcado como privado. Esto significa que std::ostreams no obedecen a la semántica de valores y no pueden
utilizarse en cualquier mecanismo que requiera que se copie el flujo. Esto incluye el ns-3
sistema de devolución de llamada, que como recordará, requiere objetos que obedezcan la semántica de valores.
Aviso adicional de que hemos agregado la siguiente línea en el CwndCambiar sumidero de rastro
implementación:

*stream->GetStream () << Simulator::Now ().GetSeconds () << "\t" << oldCwnd << "\t" << newCwnd << std::endl;

Este sería un código muy familiar si reemplazara *flujo->GetStream () con std :: cout, ya que
en:

std::cout << Simulator::Now ().GetSeconds () << "\t" << oldCwnd << "\t" << newCwnd << std::endl;

Esto ilustra que el ptr en realidad solo está cargando un
std :: ofstream para usted, y puede usarlo aquí como cualquier otro flujo de salida.

Una situación similar ocurre en RxDrop excepto que el objeto que se pasa alrededor (un
ptr) representa un archivo PCAP. Hay una sola línea en el sumidero de rastreo para
escriba una marca de tiempo y el contenido del paquete que se coloca en el archivo PCAP:

archivo->Escribir(Simulador::Ahora(), p);

Por supuesto, si tenemos objetos que representan los dos archivos, debemos crearlos en algún lugar
y también hacer que se pasen a los sumideros de rastreo. Si miras en el principal función,
encontrará un nuevo código para hacer precisamente eso:

AsciiTraceHelper asciiTraceHelper;
ptr stream = asciiTraceHelper.CreateFileStream ("sexto.cwnd");
ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow", MakeBoundCallback (&CwndChange, stream));

...

PcapHelperpcapHelper;
ptr archivo = pcapHelper.CreateFile ("sexto.pcap", std::ios::out, PcapHelper::DLT_PPP);
dispositivos.Get (1)->TraceConnectWithoutContext("PhyRxDrop", MakeBoundCallback (&RxDrop, archivo));

En la primera sección del fragmento de código anterior, estamos creando el archivo de rastreo ASCII,
creando un objeto responsable de administrarlo y usando una variante de la devolución de llamada
función de creación para organizar que el objeto se pase al receptor. Nuestro rastro ASCII
Los ayudantes proporcionan un amplio conjunto de funciones para facilitar el uso de archivos de texto (ASCII). Estamos
solo voy a ilustrar el uso de la función de creación de flujo de archivos aquí.

Los Crear flujo de archivos La función básicamente va a instanciar un std :: ofstream objeto y
crear un nuevo archivo (o truncar un archivo existente). Este std :: ofstream está empaquetado en un
ns-3 objeto para la gestión de la vida útil y la resolución de problemas del constructor de copias.

Entonces tomamos esto ns-3 objeto que representa el archivo y pasarlo a HacerBoundCallback().
Esta función crea una devolución de llamada como Hacer devolución de llamada (), pero "vincula" un nuevo valor a
la devolución de llamada Este valor se agrega como primer argumento a la devolución de llamada antes de que sea
llamado.

Esencialmente, MakeBoundCallback(&CwndChange, corriente) hace que el origen de rastreo agregue el
parámetro de "flujo" adicional al frente de la lista de parámetros formales antes de invocar
la devolución de llamada Esto cambia la firma requerida del CwndCambiar lavabo a juego con el
que se muestra arriba, que incluye el parámetro "extra" ptr stream.

En la segunda sección de código del fragmento anterior, creamos una instancia PcapHelper para hacer el
Lo mismo para nuestro archivo de rastreo PCAP que hicimos con el AsciiTraceHelper. la linea de
código,

ptr archivo = pcapHelper.CreateFile ("sexto.pcap",
"w", PcapHelper::DLT_PPP);

crea un archivo PCAP llamado "sixth.pcap" con el modo de archivo "w". Esto significa que el nuevo archivo
se trunca (se elimina el contenido) si se encuentra un archivo existente con ese nombre. El final
El parámetro es el "tipo de enlace de datos" del nuevo archivo PCAP. Estos son los mismos que el PCAP
tipos de enlace de datos de biblioteca definidos en bpf.h si está familiarizado con PCAP. En este caso,
DLT_PPP indica que el archivo PCAP va a contener paquetes con el prefijo point to
encabezados de puntos. Esto es cierto ya que los paquetes provienen de nuestro dispositivo punto a punto.
conductor. Otros tipos de enlace de datos comunes son DLT_EN10MB (Ethernet de 10 MB) apropiado para csma
dispositivos y DLT_IEEE802_11 (IEEE 802.11) apropiado para dispositivos wifi. Estos se definen
in src/network/helper/trace-helper.h si te interesa ver la lista. los
las entradas de la lista coinciden con las de bpf.h pero los duplicamos para evitar una fuente PCAP
dependencia.

A ns-3 el objeto que representa el archivo PCAP se devuelve desde CrearFile y usado en un límite
devolución de llamada exactamente como estaba en el caso ASCII.

Un desvío importante: es importante notar que aunque ambos objetos son
declarado de manera muy similar,

ptr expediente ...
ptr corriente ...

Los objetos subyacentes son completamente diferentes. por ejemplo, el ptr es un
puntero inteligente a un ns-3 Objeto que es una cosa bastante pesada que soporta
Atributos y está integrado en el sistema Config. los ptr, En la
por otro lado, es un puntero inteligente a un objeto contado de referencia que es muy ligero
cosa. Recuerde mirar el objeto al que hace referencia antes de hacer suposiciones.
sobre los "poderes" que ese objeto puede tener.

Por ejemplo, eche un vistazo a src/network/utils/pcap-file-wrapper.h en la distribución y
aviso,

clase PcapFileWrapper: objeto público

esa clase PcapFileWrapper es un ns-3 Objeto en virtud de su herencia. Entonces mira
src/network/model/output-stream-wrapper.h y aviso,

clase OutputStreamWrapper: público
RecuentoRefSimple

que este objeto no es un ns-3 Objeto en absoluto, es "simplemente" un objeto C++ que le sucede a
admitir el conteo de referencias intrusivas.

El punto aquí es que solo porque lees ptr no significa necesariamente
que algo es un ns-3 Objeto en el que se puede colgar ns-3 Atributos, por ejemplo.

Ahora, volvamos al ejemplo. Si compila y ejecuta este ejemplo,

$ ./waf --ejecutar sexto

verá aparecer los mismos mensajes que cuando ejecutó "quinto", pero aparecerán dos archivos nuevos.
aparecer en el directorio de nivel superior de su ns-3 distribución.

sexto.cwnd sexto.pcap

Dado que "sexto.cwnd" es un archivo de texto ASCII, puede verlo con gato o tu archivo favorito
espectador.

1 0 536
1.0093 536 1072
1.01528 1072 1608
1.02167 1608 2144
...
9.69256 5149 5204
9.89311 5204 5259

Tiene un archivo separado por tabulaciones con una marca de tiempo, una ventana de congestión antigua y una nueva
ventana de congestión adecuada para importar directamente a su programa de trazado. No existen
impresiones extrañas en el archivo, no se requiere análisis ni edición.

Dado que "sexto.pcap" es un archivo PCAP, puede verlo con tcpdump.

lectura del archivo sexto.pcap, enlace tipo PPP (PPP)
1.136956 IP 10.1.1.1.49153 > 10.1.1.2.8080: Banderas [.], sec 17177:17681, reconocimiento 1, victoria 32768, opciones [TS val 1133 ecr 1127,eol], longitud 504
1.403196 IP 10.1.1.1.49153 > 10.1.1.2.8080: Banderas [.], sec 33280:33784, reconocimiento 1, victoria 32768, opciones [TS val 1399 ecr 1394,eol], longitud 504
...
7.426220 IP 10.1.1.1.49153 > 10.1.1.2.8080: Banderas [.], sec 785704:786240, reconocimiento 1, victoria 32768, opciones [TS val 7423 ecr 7421,eol], longitud 536
9.630693 IP 10.1.1.1.49153 > 10.1.1.2.8080: Banderas [.], sec 882688:883224, reconocimiento 1, victoria 32768, opciones [TS val 9620 ecr 9618,eol], longitud 536

Tiene un archivo PCAP con los paquetes que se descartaron en la simulación. No existen
otros paquetes presentes en el archivo y no hay nada más presente para hacer la vida
difícil.

Ha sido un largo viaje, pero ahora estamos en un punto en el que podemos apreciar la ns-3
sistema de rastreo. Hemos sacado eventos importantes del medio de una implementación de TCP
y un controlador de dispositivo. Almacenamos esos eventos directamente en archivos utilizables con conocidos
instrumentos. Hicimos esto sin modificar nada del código central involucrado, y lo hicimos en
sólo 18 líneas de código:

hoyo estatico
CwndChange (Ptr corriente, uint32_t oldCwnd, uint32_t newCwnd)
{
NS_LOG_UNCOND (Simulador::Ahora ().GetSeconds () << "\t" << newCwnd);
*stream->GetStream () << Simulator::Now ().GetSeconds () << "\t" << oldCwnd << "\t" << newCwnd << std::endl;
}

...

AsciiTraceHelper asciiTraceHelper;
ptr stream = asciiTraceHelper.CreateFileStream ("sexto.cwnd");
ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow", MakeBoundCallback (&CwndChange, stream));

...

hoyo estatico
RxDrop (Ptr archivo, punto pags)
{
NS_LOG_UNCOND ("RxDrop en " << Simulador::Ahora ().GetSeconds ());
archivo->Escribir(Simulador::Ahora(), p);
}

...

PcapHelperpcapHelper;
ptr archivo = pcapHelper.CreateFile ("sexto.pcap", "w", PcapHelper::DLT_PPP);
dispositivos.Get (1)->TraceConnectWithoutContext("PhyRxDrop", MakeBoundCallback (&RxDrop, archivo));

Trace Ayudantes
Los ns-3 Los ayudantes de seguimiento proporcionan un entorno rico para configurar y seleccionar diferentes
rastrear eventos y escribirlos en archivos. En las secciones anteriores, principalmente
BuildingTopologies, hemos visto varias variedades de los métodos auxiliares de seguimiento diseñados
para usar dentro de otros ayudantes (dispositivos).

Tal vez recuerde haber visto algunas de estas variaciones:

pointToPoint.EnablePcapAll ("segundo");
pointToPoint.EnablePcap ("segundo", p2pNodes.Get (0)->GetId(), 0);
csma.EnablePcap ("tercero", csmaDevices.Get (0), verdadero);
pointToPoint.EnableAsciiAll (ascii.CreateFileStream ("myfirst.tr"));

Sin embargo, lo que puede no ser obvio es que existe un modelo consistente para todos los
métodos relacionados con el rastreo encontrados en el sistema. Ahora nos tomaremos un poco de tiempo y echaremos un vistazo
en el "panorama general".

Actualmente hay dos casos de uso principales de los ayudantes de rastreo en ns-3: ayudantes de dispositivos
y ayudantes de protocolo. Los ayudantes de dispositivos analizan el problema de especificar qué rastros
debe habilitarse a través de un par (nodo, dispositivo). Por ejemplo, es posible que desee especificar
que el rastreo de PCAP debe habilitarse en un dispositivo particular en un nodo específico. Este
se sigue de la ns-3 modelo conceptual del dispositivo, y también los modelos conceptuales del
varios ayudantes de dispositivos. Como consecuencia natural de esto, los archivos creados siguen un
- - convenio de denominación.

Los ayudantes de protocolo analizan el problema de especificar qué seguimientos deben habilitarse a través de
un par de protocolo e interfaz. Esto se sigue de la ns-3 pila de protocolo conceptual
modelo, y también los modelos conceptuales de los asistentes de pila de Internet. Naturalmente, la huella
los archivos deben seguir un - - convenio de denominación.

Por lo tanto, los asistentes de rastreo caen naturalmente en una taxonomía bidimensional. Hay
sutilezas que impiden que las cuatro clases se comporten de manera idéntica, pero nos esforzamos por
hacer que todos funcionen de la manera más similar posible; y siempre que sea posible hay análogos para
todos los métodos en todas las clases.

┌────────────────┬──────┬───────┐
│ │ PCAP │ ASCII │
└────────────────┴──────┴───────┘

│Ayudante del dispositivo │ │ │
├────────────────┼──────┼───────┤
│Ayudante de protocolo │ │ │
└────────────────┴──────┴───────┘

Usamos un enfoque llamado Mixin para agregar la funcionalidad de rastreo a nuestras clases auxiliares. A
Mixin es una clase que proporciona funcionalidad cuando es heredada por una subclase.
Heredar de un mixin no se considera una forma de especialización, pero en realidad es una forma de
recoger la funcionalidad.

Echemos un vistazo rápido a estos cuatro casos y sus respectivos mezclando.

Device Ayudantes
PCAP
El objetivo de estos ayudantes es facilitar la adición de una función de seguimiento de PCAP coherente a un
ns-3 dispositivo. Queremos que todas las variantes del rastreo de PCAP funcionen de la misma manera
todos los dispositivos, por lo que los métodos de estos ayudantes son heredados por los ayudantes de dispositivos. Echar un vistazo
at src/network/helper/trace-helper.h si desea seguir la discusión mientras mira
código real

La clase PcapHelperParaDispositivo es un Mixin proporciona la funcionalidad de alto nivel para usar
Trazado de PCAP en un ns-3 dispositivo. Cada dispositivo debe implementar un solo método virtual
heredado de esta clase.

virtual void EnablePcapInternal (std::string prefijo, Ptr nd, bool promiscuo, bool nombre de archivo explícito) = 0;

La firma de este método refleja la visión centrada en el dispositivo de la situación en este
nivel. Todos los métodos públicos heredados de la clase. PcapUserHelperParaDispositivo reducido a
llamando a este único método de implementación dependiente del dispositivo. Por ejemplo, el nivel más bajo
método PCAP,

void EnablePcap (std::string prefijo, Ptr nd, bool promiscuous = false, bool explicitFilename = false);

llamará al dispositivo implementación de HabilitarPcapInternal directamente. Todos los demás PCAP públicos
Los métodos de seguimiento se basan en esta implementación para proporcionar información adicional a nivel de usuario.
funcionalidad. Lo que esto significa para el usuario es que todos los dispositivos auxiliares del sistema
tener todos los métodos de rastreo de PCAP disponibles; y estos métodos funcionarán todos en el mismo
a través de los dispositivos si el dispositivo implementa HabilitarPcapInternal correctamente.

Métodos
void EnablePcap (std::string prefijo, Ptr nd, bool promiscuous = false, bool explicitFilename = false);
void EnablePcap (std::prefijo de cadena, std::string ndName, bool promiscuous = false, bool explicitFilename = false);
void EnablePcap (std::prefijo de cadena, NetDeviceContainer d, bool promiscuo = false);
void EnablePcap (std::prefijo de cadena, NodeContainer n, bool promiscuo = falso);
void EnablePcap (std::prefijo de cadena, uint32_t nodeid, uint32_t deviceid, bool promiscuous = false);
void EnablePcapAll (std::prefijo de cadena, bool promiscuo = falso);

En cada uno de los métodos que se muestran arriba, hay un parámetro predeterminado llamado promiscuo que
por defecto es false. Este parámetro indica que la traza no debe recopilarse en
modo promiscuo. Si desea que sus seguimientos incluyan todo el tráfico visto por el dispositivo
(y si el dispositivo admite un modo promiscuo) simplemente agregue un parámetro verdadero a cualquiera de los
llamadas arriba. Por ejemplo,

ptr Dakota del Norte;
...
helper.EnablePcap ("prefijo", nd, verdadero);

habilitará capturas de modo promiscuo en el dispositivo de red especificado por nd.

Los dos primeros métodos también incluyen un parámetro predeterminado llamado nombre de archivo explícito con amados villancicos que
ser discutido a continuación.

Le animamos a leer detenidamente la Documentación API para la clase. PcapHelperParaDispositivo para encontrar
los detalles de estos métodos; pero para resumir...

· Puede habilitar el rastreo de PCAP en un par particular de nodo/red-dispositivo al proporcionar un
ptr a una Habilitar Pcap método. los ptr está implícito ya que el dispositivo de red
debe pertenecer exactamente a un Nodo. Por ejemplo,

ptr Dakota del Norte;
...
helper.EnablePcap ("prefijo", nd);

· Puede habilitar el rastreo de PCAP en un par particular de nodo/red-dispositivo al proporcionar un
std :: string que representa una cadena de servicio de nombres de objetos a un Habilitar Pcap método. los
ptr se busca desde la cadena de nombre. Nuevamente, el está implícito ya que
el dispositivo de red nombrado debe pertenecer exactamente a un Nodo. Por ejemplo,

Nombres::Agregar ("servidor" ...);
Nombres::Agregar ("servidor/eth0" ...);
...
helper.EnablePcap ("prefijo", "servidor/ath0");

· Puede habilitar el rastreo de PCAP en una colección de pares de nodo/red-dispositivo proporcionando un
NetDeviceContainerNetDeviceContainer. Para cada dispositivo de red en el contenedor se comprueba el tipo. Para cada
dispositivo del tipo apropiado (el mismo tipo que es administrado por el ayudante del dispositivo), el rastreo es
activado. Nuevamente, el está implícito ya que el dispositivo de red encontrado debe pertenecer a
exactamente un nodo. Por ejemplo,

Contenedor de dispositivo de red d = ...;
...
helper.EnablePcap ("prefijo", d);

· Puede habilitar el rastreo de PCAP en una colección de pares de nodo/red-dispositivo proporcionando un
Contenedor de nodo. Para cada nodo en el Contenedor de nodo esta adjunto Dispositivos de red son iterados.
Para cada uno dispositivo de red adjunto a cada Nodo en el contenedor, el tipo de ese dispositivo es
comprobado. Para cada dispositivo del tipo apropiado (el mismo tipo que es administrado por el dispositivo
ayudante), el rastreo está habilitado.

Contenedor de nodo n;
...
helper.EnablePcap ("prefijo", n);

· Puede habilitar el seguimiento de PCAP sobre la base de la identificación del nodo y la identificación del dispositivo, así como con
explícito ptr. Cada Nodo en el sistema tiene una ID de Nodo entera y cada dispositivo conectado
a un nodo tiene un ID de dispositivo entero.

helper.EnablePcap ("prefijo", 21, 1);

· Finalmente, puede habilitar el rastreo PCAP para todos los dispositivos en el sistema, con el mismo tipo
como el administrado por el ayudante del dispositivo.

helper.EnablePcapAll ("prefijo");

Nombres de archivos
Implícito en las descripciones de métodos anteriores está la construcción de un nombre de archivo completo por
el método de implementación. Por convención, los rastros de PCAP en el ns-3 sistema son de la forma
- identificación>- id>.pcap

Como se mencionó anteriormente, cada nodo en el sistema tendrá una identificación de nodo asignada por el sistema; y
cada dispositivo tendrá un índice de interfaz (también llamado ID de dispositivo) relativo a su nodo.
Por defecto, entonces, un archivo de rastreo PCAP creado como resultado de habilitar el rastreo en el primer
dispositivo del Nodo 21 usando el prefijo "prefijo" sería prefijo-21-1.pcap.

Siempre puedes usar el ns-3 servicio de nombres de objetos para que esto quede más claro. Por ejemplo, si
utiliza el servicio de nombres de objetos para asignar el nombre "servidor" al Nodo 21, el PCAP resultante
el nombre del archivo de rastreo se convertirá automáticamente, prefijo-servidor-1.pcap y si también asignas el
nombre "eth0" al dispositivo, su nombre de archivo PCAP lo recogerá automáticamente y será
, que son prefijo-servidor-eth0.pcap.

Finalmente, dos de los métodos mostrados arriba,

void EnablePcap (std::string prefijo, Ptr nd, bool promiscuous = false, bool explicitFilename = false);
void EnablePcap (std::prefijo de cadena, std::string ndName, bool promiscuous = false, bool explicitFilename = false);

tener un parámetro por defecto llamado nombre de archivo explícito. Cuando se establece en verdadero, este parámetro
desactiva el mecanismo de finalización automática de nombre de archivo y le permite crear un archivo explícito
Nombre del archivo. Esta opción solo está disponible en los métodos que permiten el rastreo de PCAP en un
dispositivo único.

Por ejemplo, para organizar que un asistente de dispositivo cree un solo PCAP promiscuo
archivo de captura de un nombre específico mi-pcap-archivo.pcap en un dispositivo dado, uno podría:

ptr Dakota del Norte;
...
helper.EnablePcap ("my-pcap-file.pcap", nd, true, true);

El Primer su verdadero El parámetro habilita las trazas de modo promiscuo y el segundo le dice al ayudante
para interpretar el prefijo parámetro como un nombre de archivo completo.

ASCII
El comportamiento del ayudante de rastreo ASCII Mixin es sustancialmente similar a la versión PCAP.
Eche un vistazo a src/network/helper/trace-helper.h si quieres seguir la discusión
mientras mira el código real.

La clase AsciiTraceHelperForDevice agrega la funcionalidad de alto nivel para usar ASCII
seguimiento a una clase auxiliar de dispositivo. Como en el caso de PCAP, cada dispositivo debe implementar un
único método virtual heredado de la traza ASCII Mixin.

vacío virtual EnableAsciiInternal (Ptr corriente,
std::prefijo de cadena,
ptr Dakota del Norte,
bool nombre de archivo explícito) = 0;

La firma de este método refleja la visión centrada en el dispositivo de la situación en este
nivel; y también el hecho de que el ayudante puede estar escribiendo en un flujo de salida compartido. Todo
los métodos públicos relacionados con el seguimiento ASCII heredados de la clase AsciiTraceHelperForDevice
reducir a llamar a este único método de implementación dependiente del dispositivo. por ejemplo, el
métodos de rastreo ascii de nivel más bajo,

void EnableAscii (std::string prefijo, Ptr nd, bool nombre de archivo explícito = falso);
void EnableAscii (Ptr corriente, punto Dakota del Norte);

llamará al dispositivo implementación de HabilitarAsciiInterno directamente, proporcionando una
prefijo o flujo válido. Todos los demás métodos de rastreo ASCII públicos se basarán en estos
funciones de bajo nivel para proporcionar funcionalidad adicional a nivel de usuario. Lo que esto significa para
el usuario es que todos los dispositivos auxiliares del sistema tendrán todos los métodos de seguimiento ASCII
disponible; y todos estos métodos funcionarán de la misma manera en todos los dispositivos si los dispositivos
implementar HabilitarAsciiInterno correctamente.

Métodos
void EnableAscii (std::string prefijo, Ptr nd, bool nombre de archivo explícito = falso);
void EnableAscii (Ptr corriente, punto Dakota del Norte);

void EnableAscii (std::prefijo de cadena, std::string ndName, bool explicitFilename = false);
void EnableAscii (Ptr corriente, std::string ndName);

void EnableAscii (std::string prefijo, NetDeviceContainer d);
void EnableAscii (Ptr corriente, NetDeviceContainer d);

void EnableAscii (std::prefijo de cadena, NodeContainer n);
void EnableAscii (Ptr corriente, NodeContainer n);

void EnableAsciiAll (prefijo std::string);
void EnableAsciiAll (Ptr corriente);

void EnableAscii (std::prefijo de cadena, uint32_t nodeid, uint32_t deviceid, bool explicitFilename);
void EnableAscii (Ptr stream, uint32_t id de nodo, uint32_t id de dispositivo);

Le animamos a leer detenidamente la Documentación API para la clase. AsciiTraceHelperForDevice a
encontrar los detalles de estos métodos; pero para resumir...

· Hay el doble de métodos disponibles para el rastreo ASCII que para PCAP
rastreo. Esto se debe a que, además del modelo estilo PCAP en el que los rastros de cada
un par único de nodo/dispositivo se escriben en un archivo único, admitimos un modelo en el que rastrear
la información de muchos pares de nodos/dispositivos se escribe en un archivo común. Esto significa que el
- - El mecanismo de generación de nombres de archivos se reemplaza por un mecanismo para
referirse a un archivo común; y el número de métodos API se duplica para permitir que todos
combinaciones.

· Al igual que en el seguimiento PCAP, puede habilitar el seguimiento ASCII en un determinado (nodo, dispositivo de red)
par proporcionando un ptr a una HabilitarAscii método. los ptr es implícito
ya que el dispositivo de red debe pertenecer exactamente a un Nodo. Por ejemplo,

ptr Dakota del Norte;
...
ayudante.EnableAscii ("prefijo", nd);

· Los primeros cuatro métodos también incluyen un parámetro predeterminado llamado nombre de archivo explícito que
operar de manera similar a los parámetros equivalentes en el caso de PCAP.

En este caso, no se escriben contextos de seguimiento en el archivo de seguimiento ASCII, ya que serían
redundante. El sistema elegirá el nombre del archivo que se creará usando las mismas reglas que
descrito en la sección PCAP, excepto que el archivo tendrá el sufijo tr en lugar de
.pcap.

· Si desea habilitar el seguimiento ASCII en más de un dispositivo de red y enviar todos los seguimientos
a un solo archivo, también puede hacerlo usando un objeto para referirse a un solo archivo.
Ya hemos visto esto en el ejemplo "cwnd" anterior:

ptr nd1;
ptr nd2;
...
ptr stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
...
ayudante.EnableAscii (flujo, nd1);
ayudante.EnableAscii (flujo, nd2);

En este caso, trace contextos están escritos en el archivo de rastreo ASCII ya que son necesarios
para eliminar la ambigüedad de los rastros de los dos dispositivos. Tenga en cuenta que dado que el usuario está completamente
especificando el nombre del archivo, la cadena debe incluir el , tr sufijo para la consistencia.

· Puede habilitar el rastreo ASCII en un par particular (nodo, red-dispositivo) proporcionando un
std :: string que representa una cadena de servicio de nombres de objetos a un Habilitar Pcap método. los
ptr se busca desde la cadena de nombre. Nuevamente, el está implícito ya que
el dispositivo de red nombrado debe pertenecer exactamente a un Nodo. Por ejemplo,

Nombres::Add ("cliente" ...);
Nombres::Add ("cliente/eth0" ...);
Nombres::Agregar ("servidor" ...);
Nombres::Agregar ("servidor/eth0" ...);
...
helper.EnableAscii ("prefijo", "cliente/eth0");
helper.EnableAscii ("prefijo", "servidor/eth0");

Esto daría como resultado dos archivos llamados ``prefix-client-eth0.tr`` y
``prefix-server-eth0.tr`` con rastros para cada dispositivo en el
respectivo archivo de seguimiento. Dado que todas las funciones ``EnableAscii``
están sobrecargados para tomar un contenedor de flujo, puede usar ese formulario como
bien::

Nombres::Add ("cliente" ...);
Nombres::Add ("cliente/eth0" ...);
Nombres::Agregar ("servidor" ...);
Nombres::Agregar ("servidor/eth0" ...);
...
ptr stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
...
ayudante.EnableAscii (flujo, "cliente/eth0");
ayudante.EnableAscii (flujo, "servidor/eth0");

Esto daría como resultado un único archivo de rastreo llamado nombre-de-archivo-de-rastreo.tr que contiene todo
los eventos de rastreo para ambos dispositivos. Los eventos serían desambiguados por contexto de seguimiento
instrumentos de cuerda.

· Puede habilitar el rastreo ASCII en una colección de pares (nodo, red-dispositivo) proporcionando un
NetDeviceContainerNetDeviceContainer. Para cada dispositivo de red en el contenedor se comprueba el tipo. Para cada
dispositivo del tipo apropiado (el mismo tipo que es administrado por el ayudante del dispositivo), el rastreo es
activado. Nuevamente, el está implícito ya que el dispositivo de red encontrado debe pertenecer a
exactamente un nodo. Por ejemplo,

Contenedor de dispositivo de red d = ...;
...
ayudante.EnableAscii ("prefijo", d);

Esto daría como resultado la creación de una serie de archivos de rastreo ASCII,
cada uno de los cuales sigue al `` - - .tr``
convención.

La combinación de todos los rastros en un solo archivo se logra de manera similar a los ejemplos
encima:

Contenedor de dispositivo de red d = ...;
...
ptr stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
...
ayudante.EnableAscii (flujo, d);

· Puede habilitar el rastreo ASCII en una colección de pares (nodo, red-dispositivo) proporcionando un
Contenedor de nodo. Para cada nodo en el Contenedor de nodo esta adjunto Dispositivos de red son iterados.
Para cada uno dispositivo de red adjunto a cada Nodo en el contenedor, el tipo de ese dispositivo es
comprobado. Para cada dispositivo del tipo apropiado (el mismo tipo que es administrado por el dispositivo
ayudante), el rastreo está habilitado.

Contenedor de nodo n;
...
ayudante.EnableAscii ("prefijo", n);

Esto daría como resultado la creación de una serie de archivos de rastreo ASCII, cada uno de los cuales sigue
los - identificación>- id>.tr convención. Combinando todos los rastros en un
el archivo único se logra de manera similar a los ejemplos anteriores.

· Puede habilitar el seguimiento de PCAP sobre la base de la identificación del nodo y la identificación del dispositivo, así como con
explícito ptr. Cada Nodo en el sistema tiene una ID de Nodo entera y cada dispositivo conectado
a un nodo tiene un ID de dispositivo entero.

ayudante.EnableAscii ("prefijo", 21, 1);

Por supuesto, las trazas se pueden combinar en un solo archivo como se muestra arriba.

· Finalmente, puede habilitar el rastreo PCAP para todos los dispositivos en el sistema, con el mismo tipo
como el administrado por el ayudante del dispositivo.

helper.EnableAsciiAll ("prefijo");

Esto daría como resultado la creación de varios archivos de seguimiento ASCII, uno para cada dispositivo.
en el sistema del tipo gestionado por el ayudante. Todos estos archivos seguirán el
- identificación>- id>.tr convención. Combinando todas las trazas en una sola
El archivo se logra de manera similar a los ejemplos anteriores.

Nombres de archivos
Implícito en las descripciones anteriores del método estilo prefijo está la construcción del
nombres de archivo por el método de implementación. Por convención, los trazos ASCII en el ns-3 te
son de la forma - identificación>- id>.tr

Como se mencionó anteriormente, cada nodo en el sistema tendrá una identificación de nodo asignada por el sistema; y
cada dispositivo tendrá un índice de interfaz (también llamado ID de dispositivo) relativo a su nodo.
Por defecto, entonces, un archivo de rastreo ASCII creado como resultado de habilitar el rastreo en el primer
dispositivo del Nodo 21, utilizando el prefijo "prefijo", sería prefijo-21-1.tr.

Siempre puedes usar el ns-3 servicio de nombres de objetos para que esto quede más claro. Por ejemplo, si
utiliza el servicio de nombres de objetos para asignar el nombre "servidor" al Nodo 21, el resultado
El nombre del archivo de seguimiento ASCII se convertirá automáticamente en, prefijo-servidor-1.tr y si también asignas
el nombre "eth0" al dispositivo, su nombre de archivo de seguimiento ASCII lo recogerá automáticamente
y ser llamado prefijo-servidor-eth0.tr.

Varios de los métodos tienen un parámetro predeterminado llamado nombre de archivo explícito. Cuando se establece en
verdadero, este parámetro deshabilita el mecanismo de finalización automática del nombre de archivo y le permite
para crear un nombre de archivo explícito. Esta opción sólo está disponible en los métodos que toman un
prefijo y habilite el rastreo en un solo dispositivo.

Protocolo Ayudantes
PCAP
El objetivo de estos mezclando es facilitar la adición de una función de rastreo PCAP consistente a
protocolos Queremos que todas las variantes del rastreo de PCAP funcionen de la misma manera en todos
protocolos, por lo que los métodos de estos ayudantes son heredados por los ayudantes de pila. Echa un vistazo a
src/network/helper/trace-helper.h si desea seguir la discusión mientras mira
código real

En esta sección, ilustraremos los métodos aplicados al protocolo. Ipv4. Para
especifique trazas en protocolos similares, simplemente sustituya el tipo apropiado. Por ejemplo,
Usar una ptr en lugar de un ptr y llama HabilitarPcapIpv6 en lugar de HabilitarPcapIpv4.

La clase PcapHelperParaIpv4 proporciona la funcionalidad de alto nivel para usar el rastreo PCAP
en la categoría Industrial. Ipv4 protocolo. Cada ayudante de protocolo que habilite estos métodos debe implementar un solo
método virtual heredado de esta clase. Habrá una implementación separada para
Ipv6, por ejemplo, pero la única diferencia estará en los nombres y las firmas de los métodos.
Se requieren diferentes nombres de métodos para desambiguar la clase Ipv4 desde Ipv6 que son ambos
derivado de la clase Objetoy métodos que comparten la misma firma.

virtual void EnablePcapIpv4Internal (std::string prefijo,
ptr ipv4,
interfaz uint32_t,
bool nombre de archivo explícito) = 0;

La firma de este método refleja la vista centrada en el protocolo y la interfaz del
situación a este nivel. Todos los métodos públicos heredados de la clase. PcapHelperParaIpv4
reducir a llamar a este único método de implementación dependiente del dispositivo. por ejemplo, el
método PCAP de nivel más bajo,

void EnablePcapIpv4 (prefijo std::string, Ptr ipv4, interfaz uint4_t, bool explicitFilename = false);

llamará al dispositivo implementación de HabilitarPcapIpv4Interno directamente. Todos los demás públicos
Los métodos de rastreo de PCAP se basan en esta implementación para proporcionar información adicional a nivel de usuario.
funcionalidad. Lo que esto significa para el usuario es que todos los auxiliares de protocolo del sistema
tendrá todos los métodos de rastreo PCAP disponibles; y todos estos métodos funcionarán en el
de la misma manera en todos los protocolos si el ayudante implementa HabilitarPcapIpv4Interno correctamente.

Métodos
Estos métodos están diseñados para estar en correspondencia uno a uno con el Nodo y
dispositivo de red- versiones centradas de las versiones del dispositivo. En lugar de Nodo y dispositivo de red par
restricciones, usamos restricciones de protocolo e interfaz.

Tenga en cuenta que, al igual que en la versión del dispositivo, hay seis métodos:

void EnablePcapIpv4 (prefijo std::string, Ptr ipv4, interfaz uint4_t, bool explicitFilename = false);
void EnablePcapIpv4 (prefijo std::string, std::string ipv4Name, interfaz uint32_t, bool explicitFilename = false);
void EnablePcapIpv4 (prefijo std::string, Ipv4InterfaceContainer c);
void EnablePcapIpv4 (std::prefijo de cadena, NodeContainer n);
void EnablePcapIpv4 (std::prefijo de cadena, uint32_t nodeid, interfaz uint32_t, bool explicitFilename);
void EnablePcapIpv4All (prefijo std::string);

Le animamos a leer detenidamente la Documentación API para la clase. PcapHelperParaIpv4 para encontrar el
detalles de estos métodos; pero para resumir...

· Puede habilitar el rastreo de PCAP en un par de protocolo/interfaz en particular proporcionando un
ptr y interfaz. a una Habilitar Pcap método. Por ejemplo,

ptr ipv4 = nodo->ObtenerObjeto ();
...
helper.EnablePcapIpv4 ("prefijo", ipv4, 0);

· Puede habilitar el rastreo de PCAP en un par particular de nodo/red-dispositivo al proporcionar un
std :: string que representa una cadena de servicio de nombres de objetos a un Habilitar Pcap método. los
ptr se busca desde la cadena de nombre. Por ejemplo,

Nombres::Agregar ("servidorIPv4" ...);
...
helper.EnablePcapIpv4 ("prefijo", "serverIpv4", 1);

· Puede habilitar el rastreo de PCAP en una colección de pares de protocolo/interfaz proporcionando un
Ipv4InterfazContenedor. Para cada Ipv4 /par de interfaz en el contenedor el protocolo
se comprueba el tipo. Para cada protocolo del tipo apropiado (el mismo tipo que es administrado por
el ayudante del dispositivo), el rastreo está habilitado para la interfaz correspondiente. Por ejemplo,

nodos NodeContainer;
...
Dispositivos NetDeviceContainer = deviceHelper.Install (nodos);
...
Ayudante de dirección ipv4 ipv4;
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer interfaces = ipv4.Assign (dispositivos);
...
helper.EnablePcapIpv4 ("prefijo", interfaces);

· Puede habilitar el rastreo de PCAP en una colección de pares de protocolo/interfaz proporcionando un
Contenedor de nodo. Para cada nodo en el Contenedor de nodo se encuentra el protocolo apropiado.
Para cada protocolo, se enumeran sus interfaces y se habilita el rastreo en el resultado
pares Por ejemplo,

Contenedor de nodo n;
...
ayudante.EnablePcapIpv4 ("prefijo", n);

· También puede habilitar el seguimiento de PCAP en función de la ID de nodo y la interfaz. En esto
caso, el ID de nodo se traduce a un ptr y se busca el protocolo adecuado
en el nodo. El protocolo y la interfaz resultantes se utilizan para especificar el resultado.
fuente de rastreo.

helper.EnablePcapIpv4 ("prefijo", 21, 1);

· Por último, puede habilitar el rastreo de PCAP para todas las interfaces del sistema, con
siendo el protocolo del mismo tipo que el administrado por el ayudante del dispositivo.

helper.EnablePcapIpv4All ("prefijo");

Nombres de archivos
Implícita en todas las descripciones de métodos anteriores está la construcción del
nombres de archivo por el método de implementación. Por convención, los seguimientos de PCAP tomados para dispositivos en
los ns-3 sistema son de la forma " - - .pcap". En el caso de
rastros de protocolo, hay una correspondencia uno a uno entre protocolos y Nodes. Esto
es porque el protocolo Objetos se agregan a Nodo Objetos. Como no hay mundial
ID de protocolo en el sistema, usamos la ID de nodo correspondiente en el nombre del archivo. Por lo tanto
existe la posibilidad de colisiones de nombres de archivos en los nombres de archivos de seguimiento elegidos automáticamente.
Por este motivo, la convención de nombres de archivo se cambia para los seguimientos de protocolo.

Como se mencionó anteriormente, cada nodo en el sistema tendrá una identificación de nodo asignada por el sistema.
Dado que existe una correspondencia uno a uno entre las instancias de protocolo y las instancias de nodo
usamos la identificación del nodo. Cada interfaz tiene una identificación de interfaz relativa a su protocolo. Usamos
la Convención " -norte -i .pcap" para la denominación de archivos de seguimiento en
ayudantes de protocolo

Por lo tanto, de forma predeterminada, un archivo de rastreo de PCAP creado como resultado de habilitar el rastreo en
interfaz 1 del protocolo Ipv4 del Nodo 21 utilizando el prefijo "prefijo" sería
"prefijo-n21-i1.pcap".

Siempre puedes usar el ns-3 servicio de nombres de objetos para que esto quede más claro. Por ejemplo, si
utiliza el servicio de nombres de objetos para asignar el nombre "serverIpv4" al Ptr en el nodo
21, el nombre del archivo de rastreo PCAP resultante se convertirá automáticamente en,
"prefijo-nserverIpv4-i1.pcap".

Varios de los métodos tienen un parámetro predeterminado llamado nombre de archivo explícito. Cuando se establece en
verdadero, este parámetro deshabilita el mecanismo de finalización automática del nombre de archivo y le permite
para crear un nombre de archivo explícito. Esta opción sólo está disponible en los métodos que toman un
prefijo y habilite el rastreo en un solo dispositivo.

ASCII
El comportamiento de los asistentes de rastreo ASCII es sustancialmente similar al caso de PCAP. Tomar un
mirar src/network/helper/trace-helper.h si quieres seguir la discusión mientras
mirando código real.

En esta sección, ilustraremos los métodos aplicados al protocolo. Ipv4. Para
especifique trazas en protocolos similares, simplemente sustituya el tipo apropiado. Por ejemplo,
Usar una ptr en lugar de un ptr y llama HabilitarAsciiIpv6 en lugar de
HabilitarAsciiIpv4.

La clase AsciiTraceHelperParaIpv4 agrega la funcionalidad de alto nivel para usar ASCII
seguimiento a un ayudante de protocolo. Cada protocolo que habilite estos métodos debe implementar un
único método virtual heredado de esta clase.

vacío virtual EnableAsciiIpv4Internal (Ptr corriente,
std::prefijo de cadena,
ptr ipv4,
interfaz uint32_t,
bool nombre de archivo explícito) = 0;

La firma de este método refleja la visión centrada en el protocolo y la interfaz del
situación a este nivel; y también el hecho de que el ayudante puede estar escribiendo a un
salida de corriente. Todos los métodos públicos heredados de la clase.
PcapAndAsciiTraceHelperParaIpv4 reducir a llamar a este único dispositivo dependiente
método de implementación. Por ejemplo, los métodos de rastreo ASCII de nivel más bajo,

void EnableAsciiIpv4 (prefijo std::string, Ptr ipv4, interfaz uint4_t, bool explicitFilename = false);
anular EnableAsciiIpv4 (Ptr corriente, punto ipv4, interfaz uint4_t);

llamará al dispositivo implementación de HabilitarAsciiIpv4Interno directamente, proporcionando
el prefijo o la secuencia. Todos los demás métodos de rastreo ASCII públicos se basarán en estos
funciones de bajo nivel para proporcionar funcionalidad adicional a nivel de usuario. Lo que esto significa para
el usuario es que todos los dispositivos auxiliares del sistema tendrán todos los métodos de seguimiento ASCII
disponible; y todos estos métodos funcionarán de la misma manera en todos los protocolos si el
implementar protocolos HabilitarAsciiIpv4Interno correctamente.

Métodos
void EnableAsciiIpv4 (prefijo std::string, Ptr ipv4, interfaz uint4_t, bool explicitFilename = false);
anular EnableAsciiIpv4 (Ptr corriente, punto ipv4, interfaz uint4_t);

void EnableAsciiIpv4 (prefijo std::string, std::string ipv4Name, interfaz uint32_t, bool explicitFilename = false);
anular EnableAsciiIpv4 (Ptr stream, std::string ipv4Name, interfaz uint32_t);

void EnableAsciiIpv4 (std::prefijo de cadena, Ipv4InterfaceContainer c);
anular EnableAsciiIpv4 (Ptr flujo, Ipv4InterfaceContainer c);

void EnableAsciiIpv4 (std::prefijo de cadena, NodeContainer n);
anular EnableAsciiIpv4 (Ptr corriente, NodeContainer n);

void EnableAsciiIpv4All (prefijo std::string);
void EnableAsciiIpv4All (Ptr arroyo);

void EnableAsciiIpv4 (std::prefijo de cadena, uint32_t nodeid, uint32_t deviceid, bool explicitFilename);
anular EnableAsciiIpv4 (Ptr stream, uint32_t nodeid, interfaz uint32_t);

Le animamos a leer detenidamente la Documentación API para la clase. PcapAndAsciiHelperParaIpv4 a
encontrar los detalles de estos métodos; pero para resumir...

· Hay el doble de métodos disponibles para el rastreo ASCII que para PCAP
rastreo. Esto se debe a que, además del modelo estilo PCAP en el que los rastros de cada
un par protocolo/interfaz único se escriben en un archivo único, admitimos un modelo en el que
la información de rastreo para muchos pares de protocolo/interfaz se escribe en un archivo común. Este
significa que el -norte - El mecanismo de generación de nombres de archivo es
reemplazado por un mecanismo para referirse a un archivo común; y el número de métodos API es
duplicado para permitir todas las combinaciones.

· Al igual que en el rastreo PCAP, puede habilitar el rastreo ASCII en un protocolo/interfaz en particular
par proporcionando un ptr y una interfaz. a una HabilitarAscii método. Por ejemplo,

ptr ipv4;
...
ayudante.EnableAsciiIpv4 ("prefijo", ipv4, 1);

En este caso, no se escriben contextos de seguimiento en el archivo de seguimiento ASCII, ya que serían
redundante. El sistema elegirá el nombre del archivo que se creará usando las mismas reglas que
descrito en la sección PCAP, excepto que el archivo tendrá el sufijo ".tr" en su lugar
de ".pcap".

· Si desea habilitar el seguimiento ASCII en más de una interfaz y enviar todos los seguimientos
a un solo archivo, también puede hacerlo usando un objeto para referirse a un solo archivo.
Ya tenemos algo similar a esto en el ejemplo "cwnd" anterior:

ptr protocolo4 = nodo1->GetObject ();
ptr protocolo4 = nodo2->GetObject ();
...
ptr stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
...
ayudante.EnableAsciiIpv4 (flujo, protocolo1, 1);
ayudante.EnableAsciiIpv4 (flujo, protocolo2, 1);

En este caso, los contextos de seguimiento se escriben en el archivo de seguimiento ASCII, ya que son necesarios.
para eliminar la ambigüedad de los rastros de las dos interfaces. Tenga en cuenta que dado que el usuario está completamente
especificando el nombre del archivo, la cadena debe incluir ",tr" para mantener la coherencia.

· Puede habilitar el rastreo ASCII en un protocolo particular al proporcionar un std :: string
que representa una cadena de servicio de nombres de objetos a un Habilitar Pcap método. los ptr is
levantó la vista de la cadena de nombres. los en los nombres de archivo resultantes está implícito ya que
existe una correspondencia uno a uno entre instancias de protocolo y nodos, por ejemplo,

Nombres::Agregar ("nodo1Ipv4" ...);
Nombres::Agregar ("nodo2Ipv4" ...);
...
helper.EnableAsciiIpv4 ("prefijo", "nodo1Ipv4", 1);
helper.EnableAsciiIpv4 ("prefijo", "nodo2Ipv4", 1);

Esto daría como resultado dos archivos llamados "prefix-nnode1Ipv4-i1.tr" y
"prefix-nnode2Ipv4-i1.tr" con rastros para cada interfaz en el archivo de rastro respectivo.
Dado que todas las funciones EnableAscii están sobrecargadas para tomar un contenedor de flujo, puede
Usa esa forma también:

Nombres::Agregar ("nodo1Ipv4" ...);
Nombres::Agregar ("nodo2Ipv4" ...);
...
ptr stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
...
ayudante.EnableAsciiIpv4 (flujo, "node1Ipv4", 1);
ayudante.EnableAsciiIpv4 (flujo, "node2Ipv4", 1);

Esto daría como resultado un único archivo de rastreo llamado "trace-file-name.tr" que contiene todos
de los eventos de rastreo para ambas interfaces. Los eventos serían desambiguados por trace
cadenas de contexto.

· Puede habilitar el rastreo ASCII en una colección de pares de protocolo/interfaz proporcionando un
Ipv4InterfazContenedor. Para cada protocolo del tipo apropiado (el mismo tipo que es
administrado por el ayudante del dispositivo), el rastreo está habilitado para la interfaz correspondiente.
Una vez más, la está implícito ya que hay una correspondencia uno a uno entre cada
protocolo y su nodo. Por ejemplo,

nodos NodeContainer;
...
Dispositivos NetDeviceContainer = deviceHelper.Install (nodos);
...
Ayudante de dirección ipv4 ipv4;
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer interfaces = ipv4.Assign (dispositivos);
...
...
helper.EnableAsciiIpv4 ("prefijo", interfaces);

Esto daría como resultado la creación de una serie de archivos de rastreo ASCII, cada uno de los cuales sigue
la -norte -i convención .tr. Combinando todos los rastros en un
el archivo único se logra de manera similar a los ejemplos anteriores:

nodos NodeContainer;
...
Dispositivos NetDeviceContainer = deviceHelper.Install (nodos);
...
Ayudante de dirección ipv4 ipv4;
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer interfaces = ipv4.Assign (dispositivos);
...
ptr stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
...
helper.EnableAsciiIpv4 (flujo, interfaces);

· Puede habilitar el rastreo ASCII en una colección de pares de protocolo/interfaz proporcionando un
Contenedor de nodo. Para cada nodo en el Contenedor de nodo se encuentra el protocolo apropiado.
Para cada protocolo, se enumeran sus interfaces y se habilita el rastreo en el resultado
pares Por ejemplo,

Contenedor de nodo n;
...
ayudante.EnableAsciiIpv4 ("prefijo", n);

Esto daría como resultado la creación de una serie de archivos de rastreo ASCII, cada uno de los cuales sigue
la - - convención .tr. Combinando todos los rastros en un
el archivo único se logra de manera similar a los ejemplos anteriores.

· También puede habilitar el seguimiento de PCAP en función de la identificación del nodo y la identificación del dispositivo. En esto
caso, el ID de nodo se traduce a un ptr y se busca el protocolo adecuado
en el nodo. El protocolo y la interfaz resultantes se utilizan para especificar el resultado.
fuente de rastreo.

ayudante.EnableAsciiIpv4 ("prefijo", 21, 1);

Por supuesto, las trazas se pueden combinar en un solo archivo como se muestra arriba.

· Por último, puede habilitar el rastreo ASCII para todas las interfaces del sistema, con
siendo el protocolo del mismo tipo que el administrado por el ayudante del dispositivo.

helper.EnableAsciiIpv4All ("prefijo");

Esto daría como resultado la creación de varios archivos de rastreo ASCII, uno para cada
interfaz en el sistema relacionado con un protocolo del tipo gestionado por el ayudante. Todo
estos archivos seguirán el -norte -i
todos los rastros en un solo archivo se logra de manera similar a los ejemplos anteriores.

Nombres de archivos
Implícito en las descripciones anteriores del método estilo prefijo está la construcción del
nombres de archivo por el método de implementación. Por convención, los trazos ASCII en el ns-3 te
son de la forma " - - .tr"

Como se mencionó anteriormente, cada nodo en el sistema tendrá una identificación de nodo asignada por el sistema.
Dado que existe una correspondencia uno a uno entre los protocolos y los nodos, usamos node-id
para identificar la identidad del protocolo. Cada interfaz en un protocolo dado tendrá un
índice de interfaz (también llamado simplemente interfaz) relativo a su protocolo. Por defecto,
luego, un archivo de rastreo ASCII creado como resultado de habilitar el rastreo en el primer dispositivo de
El nodo 21, usando el prefijo "prefijo", sería "prefijo-n21-i1.tr". Usa el prefijo para
eliminar la ambigüedad de múltiples protocolos por nodo.

Siempre puedes usar el ns-3 servicio de nombres de objetos para que esto quede más claro. Por ejemplo, si
utiliza el servicio de nombres de objetos para asignar el nombre "serverIpv4" al protocolo en Node
21, y también especifique la interfaz uno, el nombre del archivo de seguimiento ASCII resultante se
convertirse en "prefijo-nserverIpv4-1.tr".

Varios de los métodos tienen un parámetro predeterminado llamado nombre de archivo explícito. Cuando se establece en
verdadero, este parámetro deshabilita el mecanismo de finalización automática del nombre de archivo y le permite
para crear un nombre de archivo explícito. Esta opción sólo está disponible en los métodos que toman un
prefijo y habilite el rastreo en un solo dispositivo.

Resum
ns-3 incluye un entorno extremadamente rico que permite a los usuarios en varios niveles personalizar
los tipos de información que se pueden extraer de las simulaciones.

Hay funciones auxiliares de alto nivel que permiten a los usuarios controlar simplemente la recopilación de
salidas predefinidas a una granularidad fina. Hay funciones auxiliares de nivel medio para permitir
usuarios más sofisticados para personalizar cómo se extrae y guarda la información; y ahí
son funciones básicas de bajo nivel que permiten a los usuarios expertos modificar el sistema para presentar nuevos y
información previamente no exportada de una manera que será inmediatamente accesible para los usuarios en
Niveles más altos.

Este es un sistema muy completo, y nos damos cuenta de que es mucho para digerir, especialmente
para nuevos usuarios o aquellos que no están íntimamente familiarizados con C++ y sus modismos. consideramos
el sistema de rastreo es una parte muy importante de ns-3 por lo que recomiendo familiarizarse tanto como
posible con eso. Probablemente sea el caso que entender el resto de la ns-3 te
será bastante simple una vez que haya dominado el sistema de rastreo

DATOS COLLECTION


Nuestro capítulo final del tutorial presenta algunos componentes que se agregaron a ns-3 en versión
3.18, y que aún están en desarrollo. Esta sección del tutorial también es una
trabajar en curso.

Necesidades
Uno de los puntos principales de ejecutar simulaciones es generar datos de salida, ya sea para
fines de investigación o simplemente para aprender sobre el sistema. En el capítulo anterior, nos
presentó el subsistema de rastreo y el ejemplo sexto.cc. a partir del cual traza PCAP o ASCII
se generan los archivos. Estos rastros son valiosos para el análisis de datos usando una variedad de
herramientas externas, y para muchos usuarios, tales datos de salida son un medio preferido para recopilar
datos (para análisis por herramientas externas).

Sin embargo, también hay casos de uso para más que la generación de archivos de seguimiento, incluido el
siguientes:

· generación de datos que no se asignan bien a trazas PCAP o ASCII, como no paquetes
datos (por ejemplo, transiciones de máquina de estado de protocolo),

· Grandes simulaciones para las cuales los requisitos de E/S de disco para generar archivos de rastreo son
prohibitivo o engorroso, y

· la necesidad de en línea reducción o cálculo de datos, durante el transcurso de la simulación.
Un buen ejemplo de esto es definir una condición de terminación para la simulación, decir
cuándo detenerse cuando ha recibido suficientes datos para formar una confianza lo suficientemente limitada
intervalo alrededor de la estimación de algún parámetro.

Los ns-3 marco de recopilación de datos está diseñado para proporcionar estas capacidades adicionales
más allá de la salida basada en trazas. Recomendamos al lector interesado en este tema consultar
los ns-3 Manual para un tratamiento más detallado de este marco; aquí, resumimos con
un programa de ejemplo algunas de las capacidades de desarrollo.

Ejemplo Código
El ejemplo del tutorial ejemplos/tutorial/séptimo.cc se asemeja a la sexto.cc ejemplo nosotros
previamente revisado, excepto por algunos cambios. En primer lugar, se ha habilitado para IPv6
soporte con una opción de línea de comandos:

Línea de comando cmd;
cmd.AddValue ("useIpv6", "Usar Ipv6", useV6);
cmd. Parse (argc, argv);

Si el usuario especifica usarIpv6, opción, el programa se ejecutará utilizando IPv6 en lugar de IPv4.
Los ayuda opcional, disponible en todos ns-3 programas que admiten el objeto CommandLine como
que se muestra arriba, se puede invocar de la siguiente manera (tenga en cuenta el uso de comillas dobles):

./waf --ejecutar "séptimo --ayuda"

que produce:

ns3-dev-seventh-debug [Argumentos del programa] [Argumentos generales]

Argumentos del programa:
--useIpv6: Usar Ipv6 [falso]

Argumentos generales:
--PrintGlobals: Imprime la lista de globales.
--PrintGroups: Imprime la lista de grupos.
--PrintGroup=[grupo]: Imprime todos los TypeIds del grupo.
--PrintTypeIds: Imprime todos los TypeIds.
--PrintAttributes=[typeid]: Imprime todos los atributos de typeid.
--PrintHelp: Imprime este mensaje de ayuda.

Este valor predeterminado (uso de IPv4, ya que useIpv6 es falso) se puede cambiar alternando el valor booleano
valor de la siguiente manera:

./waf --ejecutar "séptimo --useIpv6=1"

y eche un vistazo al pcap generado, como con tcpdump:

tcpdump -r séptimo.pcap -nn -tt

Esta ha sido una breve digresión sobre el soporte de IPv6 y la línea de comandos, que también fue
introducido anteriormente en este tutorial. Para ver un ejemplo dedicado del uso de la línea de comandos,
por favor mira src/core/examples/command-line-example.cc.

Ahora volvamos a la recopilación de datos. En el ejemplos/tutorial/ directorio, escriba lo siguiente
mando: diff -u sexto.cc séptimo.cc, y examine algunas de las nuevas líneas de este diff:

+ std::string tipo de sonda;
+ std::string ruta de seguimiento;
+ si (usar V6 == falso)
+ {
...
+ probeType = "ns3::Ipv4PacketProbe";
+ tracePath = "/NodeList/*/$ns3::Ipv4L3Protocol/Tx";
+ }
+ más
+ {
...
+ probeType = "ns3::Ipv6PacketProbe";
+ tracePath = "/NodeList/*/$ns3::Ipv6L3Protocol/Tx";
+ }
...
+ // Usa GnuplotHelper para trazar el conteo de bytes del paquete a lo largo del tiempo
+ GnuplotHelper plotHelper;
+
+ // Configurar la trama. El primer argumento es el prefijo del nombre del archivo.
+ // para los archivos de salida generados. La segunda, tercera y cuarta
+ // los argumentos son, respectivamente, el título de la trama, el eje x y las etiquetas del eje y
+ plotHelper.ConfigurePlot ("recuento de bytes del séptimo paquete",
+ "Recuento de bytes de paquetes frente a tiempo",
+ "Tiempo (segundos)",
+ "Recuento de bytes del paquete");
+
+ // Especifique el tipo de sonda, la ruta de origen del seguimiento (en el espacio de nombres de configuración) y
+ // sondear la fuente de rastreo de salida ("OutputBytes") para trazar. El cuarto argumento
+ // especifica el nombre de la etiqueta de la serie de datos en el gráfico. El último
+ // El argumento da formato al gráfico especificando dónde debe colocarse la clave.
+ plotHelper.PlotProbe (tipo de sonda,
+ trazarRuta,
+ "Bytes de salida",
+ "Recuento de bytes del paquete",
+ Agregador de Gnuplot::KEY_BELOW);
+
+ // Use FileHelper para escribir el conteo de bytes del paquete a lo largo del tiempo
+ Ayudante de archivos Ayudante de archivos;
+
+ // Configure el archivo que se escribirá y el formato de los datos de salida.
+ fileHelper.ConfigureFile ("recuento de bytes del séptimo paquete",
+ FileAgregator::FORMATEADO);
+
+ // Establecer las etiquetas para este archivo de salida formateado.
+ fileHelper.Set2dFormat ("Tiempo (segundos) = %.3e\tRecuento de bytes de paquetes = %.0f");
+
+ // Especifique el tipo de sonda, la ruta de la sonda (en el espacio de nombres de configuración) y
+ // fuente de rastreo de salida de la sonda ("OutputBytes") para escribir.
+ fileHelper.WriteProbe (tipo de sonda,
+ trazarRuta,
+ "Bytes de salida");
+
Simulador::Detener (Segundos (20));
Simulador::Ejecutar ();
Simulador::Destruir ();

El lector cuidadoso habrá notado, al probar el atributo de línea de comando IPv6 anterior,
que séptimo.cc había creado una serie de nuevos archivos de salida:

séptimo-paquete-byte-count-0.txt
séptimo-paquete-byte-count-1.txt
séptimo-paquete-byte-count.dat
séptimo-paquete-byte-count.plt
séptimo-paquete-byte-count.png
séptimo-paquete-byte-count.sh

Estos fueron creados por las declaraciones adicionales introducidas anteriormente; en particular, por un
GnuplotHelper y FileHelper. Estos datos se produjeron conectando la recopilación de datos
componentes a ns-3 rastrear fuentes y ordenar los datos en un formato parcela gnuplot y
en un archivo de texto formateado. En las siguientes secciones, revisaremos cada uno de estos.

Ayudante de Gnuplot
El GnuplotHelper es un ns-3 objeto auxiliar destinado a la producción de parcela gnuplot parcelas con
la menor cantidad posible de declaraciones, para casos comunes. engancha ns-3 rastrear fuentes con datos
tipos admitidos por el sistema de recopilación de datos. No todo ns-3 los tipos de datos de orígenes de seguimiento son
compatible, pero muchos de los tipos de seguimiento comunes lo son, incluidos TracedValues ​​con
tipos de datos (POD).

Veamos la salida producida por este ayudante:

séptimo-paquete-byte-count.dat
séptimo-paquete-byte-count.plt
séptimo-paquete-byte-count.sh

El primero es un archivo de datos gnuplot con una serie de marcas de tiempo y paquetes delimitados por espacios.
recuentos de bytes. Cubriremos cómo se configuró esta salida de datos en particular a continuación, pero
continuar con los archivos de salida. El archivo séptimo-paquete-byte-count.plt es un diagrama de gnuplot
archivo, que se puede abrir desde dentro de gnuplot. Los lectores que entienden la sintaxis de gnuplot pueden
vea que esto producirá un archivo PNG de salida formateado llamado
séptimo-paquete-byte-count.png. Finalmente, un pequeño script de shell
séptimo-paquete-byte-count.sh ejecuta este archivo de trazado a través de gnuplot para producir el deseado
PNG (que se puede ver en un editor de imágenes); es decir, el comando:

sh séptimo-paquete-byte-count.sh

rendirá séptimo-paquete-byte-count.png. ¿Por qué no se produjo este PNG en la primera
¿lugar? La respuesta es que al proporcionar el archivo plt, el usuario puede configurar manualmente el
resultado si lo desea, antes de producir el PNG.

El título de la imagen PNG indica que este gráfico es un gráfico de "Recuento de bytes de paquetes frente a tiempo" y
que está trazando los datos sondeados correspondientes a la ruta de la fuente de seguimiento:

/NodeList/*/$ns3::Ipv6L3Protocol/Tx

Tenga en cuenta el comodín en la ruta de seguimiento. En resumen, lo que está capturando esta trama es la trama
de bytes de paquete observados en la fuente de rastreo de transmisión del objeto Ipv6L3Protocol;
en gran parte segmentos TCP de 596 bytes en una dirección y acuses de recibo TCP de 60 bytes en la otra (dos
los orígenes de seguimiento del nodo coincidieron con este origen de seguimiento).

¿Cómo se configuró esto? Se deben proporcionar algunas declaraciones. Primero, el GnuplotHelper
El objeto debe ser declarado y configurado:

+ // Usa GnuplotHelper para trazar el conteo de bytes del paquete a lo largo del tiempo
+ GnuplotHelper plotHelper;
+
+ // Configurar la trama. El primer argumento es el prefijo del nombre del archivo.
+ // para los archivos de salida generados. La segunda, tercera y cuarta
+ // los argumentos son, respectivamente, el título de la trama, el eje x y las etiquetas del eje y
+ plotHelper.ConfigurePlot ("recuento de bytes del séptimo paquete",
+ "Recuento de bytes de paquetes frente a tiempo",
+ "Tiempo (segundos)",
+ "Recuento de bytes del paquete");

Hasta este punto, se ha configurado una parcela vacía. El prefijo del nombre de archivo es el primero
argumento, el título de la trama es el segundo, la etiqueta del eje x el tercero y la etiqueta del eje y
el cuarto argumento.

El siguiente paso es configurar los datos, y aquí es donde se engancha la fuente de seguimiento.
Primero, tenga en cuenta que arriba en el programa declaramos algunas variables para su uso posterior:

+ std::string tipo de sonda;
+ std::string ruta de seguimiento;
+ probeType = "ns3::Ipv6PacketProbe";
+ tracePath = "/NodeList/*/$ns3::Ipv6L3Protocol/Tx";

Los usamos aquí:

+ // Especifique el tipo de sonda, la ruta de origen del seguimiento (en el espacio de nombres de configuración) y
+ // sondear la fuente de rastreo de salida ("OutputBytes") para trazar. El cuarto argumento
+ // especifica el nombre de la etiqueta de la serie de datos en el gráfico. El último
+ // El argumento da formato al gráfico especificando dónde debe colocarse la clave.
+ plotHelper.PlotProbe (tipo de sonda,
+ trazarRuta,
+ "Bytes de salida",
+ "Recuento de bytes del paquete",
+ Agregador de Gnuplot::KEY_BELOW);

Los dos primeros argumentos son el nombre del tipo de sonda y la ruta del origen del seguimiento. Estas
dos son probablemente los más difíciles de determinar cuando intenta usar este marco para trazar otros
rastros El rastro de la sonda aquí es el Tx rastrear la fuente de la clase Protocolo Ipv6L3. Cuando nosotros
examinar esta implementación de clase (src/internet/modelo/ipv6-l3-protocolo.cc) podemos observar:

.AddTraceSource ("Tx", "Enviar paquete IPv6 a la interfaz de salida.",
MakeTraceSourceAccessor (&Ipv6L3Protocol::m_txTrace))

Esto dice que Tx es un nombre para la variable m_txTrace, que tiene una declaración de:

/ **
* \brief Callback para rastrear paquetes TX (transmisión).
*/
Devolución de llamada trazada , Punto , uint6_t> m_txTrace;

Resulta que esta firma de fuente de seguimiento específica es compatible con una clase Probe (qué
necesitamos aquí) de clase Ipv6PacketProbe. ver los archivos
src/internet/model/ipv6-packet-probe.{h,cc}.

Entonces, en la instrucción PlotProbe anterior, vemos que la instrucción está enganchando el seguimiento
origen (identificado por cadena de ruta) con una coincidencia ns-3 Tipo de sonda de Sonda de paquetes Ipv6. Si
no admitimos este tipo de sonda (firma de fuente de seguimiento coincidente), no podríamos haberlo
usó esta declaración (aunque algunas declaraciones más complicadas de nivel inferior podrían haber sido
utilizado, como se describe en el manual).

El Ipv6PacketProbe exporta, en sí mismo, algunas fuentes de rastreo que extraen los datos del
Objeto de paquete sondeado:

ID de tipo
Ipv6PacketProbe :: GetTypeId ()
{
estático TypeId tid = TypeId ("ns3 :: Ipv6PacketProbe")
.SetParent ()
.AddConstructor ()
.AddTraceSource ("Salida",
"El paquete más su objeto IPv6 y la interfaz que sirven como salida para esta sonda",
MakeTraceSourceAccessor (& Ipv6PacketProbe :: m_output))
.AddTraceSource ("OutputBytes",
"El número de bytes en el paquete",
MakeTraceSourceAccessor (& Ipv6PacketProbe :: m_outputBytes))
;
volver tid;
}

El tercer argumento de nuestra instrucción PlotProbe especifica que estamos interesados ​​en el
número de bytes en este paquete; específicamente, la fuente de rastreo "OutputBytes" de
Ipv6PacketProbe. Finalmente, los dos últimos argumentos de la declaración proporcionan la leyenda de la trama.
para esta serie de datos ("Recuento de bytes de paquetes") y una instrucción de formato gnuplot opcional
(GnuplotAggregator::KEY_BELOW) que queremos que la clave de la trama se inserte debajo de la trama.
Otras opciones incluyen NO_KEY, KEY_INSIDE y KEY_ABOVE.

Soportado Trace Tipos
Los siguientes valores rastreados son compatibles con las sondas a partir de este escrito:

" ────────────────────┐
│Tipo TracedValue │ Tipo de sonda │ Archivo │
" ────────────────────┤
│doble │ DoubleProbe │ stats/model/double-probe.h │
" ────────────────────┤
│uint8_t │ Uinteger8Probe │ estadísticas/modelo/uinteger-8-probe.h │
" ────────────────────┤
│uint16_t │ Uinteger16Probe │ estadísticas/modelo/uinteger-16-probe.h │
" ────────────────────┤
│uint32_t │ Uinteger32Probe │ estadísticas/modelo/uinteger-32-probe.h │
" ────────────────────┤
│bool │ BooleanProbe │ stats/model/uinteger-16-probe.h │
" ────────────────────┤
│ns3::Time │ TimeProbe │ estadísticas/modelo/time-probe.h │
" ────────────────────┘

Los siguientes tipos de TraceSource son compatibles con las sondas a partir de este escrito:

" ──────ella razón ──────────┐
" ──────ella razón ──────────┤
" ──────ella razón ──────────┤
" ──────ella razón ──────────┤
" ──────ella razón ──────────┤
" ──────ella razón ──────────┤
" ──────ella razón ──────────┘

Como puede verse, solo se admiten unas pocas fuentes de seguimiento y todas están orientadas hacia
salida del tamaño del paquete (en bytes). Sin embargo, la mayoría de los tipos de datos fundamentales
disponible como TracedValues ​​se puede admitir con estos ayudantes.

Ayudante de archivo
La clase FileHelper es solo una variación del ejemplo anterior de GnuplotHelper. los
El programa de ejemplo proporciona una salida formateada de los mismos datos con marca de tiempo, como la siguiente:

Tiempo (segundos) = 9.312e + 00 Recuento de bytes del paquete = 596
Tiempo (segundos) = 9.312e + 00 Recuento de bytes del paquete = 564

Se proporcionan dos archivos, uno para el nodo "0" y otro para el nodo "1" como se puede ver en el
nombres de archivo Veamos el código pieza por pieza:

+ // Use FileHelper para escribir el conteo de bytes del paquete a lo largo del tiempo
+ Ayudante de archivos Ayudante de archivos;
+
+ // Configure el archivo que se escribirá y el formato de los datos de salida.
+ fileHelper.ConfigureFile ("recuento de bytes del séptimo paquete",
+ FileAgregator::FORMATEADO);

El prefijo del archivo del asistente de archivo es el primer argumento y, a continuación, un especificador de formato. Alguno
otras opciones de formato incluyen SPACE_SEPARATED, COMMA_SEPARATED y TAB_SEPARATED.
Los usuarios pueden cambiar el formato (si se especifica FORMATTED) con una cadena de formato
como sigue:

+
+ // Establecer las etiquetas para este archivo de salida formateado.
+ fileHelper.Set2dFormat ("Tiempo (segundos) = %.3e\tRecuento de bytes de paquetes = %.0f");

Finalmente, la fuente de seguimiento de interés debe estar enganchada. De nuevo, probeType y tracePath
se utilizan las variables de este ejemplo y el origen de seguimiento de salida de la sonda "OutputBytes" es
enganchado:

+
+ // Especifique el tipo de sonda, la ruta de origen del seguimiento (en el espacio de nombres de configuración) y
+ // fuente de rastreo de salida de la sonda ("OutputBytes") para escribir.
+ fileHelper.WriteProbe (tipo de sonda,
+ trazarRuta,
+ "Bytes de salida");
+

Los campos comodín en este especificador de origen de seguimiento coinciden con dos orígenes de seguimiento. A diferencia del
Ejemplo de GnuplotHelper, en el que se superpusieron dos series de datos en el mismo gráfico, aquí, dos
los archivos separados se escriben en el disco.

Resum
El soporte de recopilación de datos es nuevo a partir de ns-3.18 y soporte básico para proporcionar series temporales
Se ha agregado la salida. El patrón básico descrito anteriormente se puede replicar dentro del
alcance del soporte de las sondas existentes y las fuentes de seguimiento. Más capacidades que incluyen
el procesamiento de estadísticas se agregará en versiones futuras.

CONCLUSIÓN


Futuros
Este documento pretende ser un documento vivo. Esperamos y esperamos que crezca con el tiempo.
para cubrir más y más de las tuercas y tornillos de ns-3.

Escribir capítulos de manuales y tutoriales no es algo que nos entusiasme a todos, pero es
muy importante para el proyecto. Si eres un experto en una de estas áreas, por favor
considerar contribuir a ns-3 proporcionando uno de estos capítulos; o cualquier otro capitulo que tu
puede pensar que es importante.

Cierre
ns-3 es un sistema grande y complicado. Es imposible cubrir todas las cosas que
necesitará saber en un pequeño tutorial. Se anima a los lectores que deseen obtener más información a
lea la siguiente documentación adicional:

· Los ns-3 manual

· Los ns-3 documentación de la biblioteca modelo

· Los ns-3 Doxygen (documentación de la API)

· Los ns-3 wiki

-- Los ns-3 Equipo de desarrollo.

Use ns-3-tutorial en línea usando los servicios de onworks.net


Servidores y estaciones de trabajo gratuitos

Descargar aplicaciones de Windows y Linux

  • 1
    Cargador USBGX
    Cargador USBGX
    USBLoaderGX es una GUI para
    Cargador USB de Waninkoko, basado en
    libwiigui. Permite listar y
    lanzar juegos de Wii, juegos de Gamecube y
    homebrew en Wii y WiiU...
    Descargar USB Loader GX
  • 2
    Firebird
    Firebird
    Firebird RDBMS ofrece funciones ANSI SQL
    y se ejecuta en Linux, Windows y
    varias plataformas Unix. Características
    excelente concurrencia y rendimiento
    & energía...
    Descargar pájaro de fuego
  • 3
    KompoZer
    KompoZer
    KompoZer es un editor HTML wysiwyg que utiliza
    el código base de Mozilla Composer. Como
    El desarrollo de Nvu se ha detenido.
    en 2005, KompoZer corrige muchos errores y
    agrega una f...
    Descargar KompoZer
  • 4
    Descargador gratuito de manga
    Descargador gratuito de manga
    Free Manga Downloader (FMD) es un
    aplicación de código abierto escrita en
    Object-Pascal para gestionar y
    descargar manga de varios sitios web.
    esto es un espejo...
    Descargar descargador de manga gratuito
  • 5
    UNetbootin
    UNetbootin
    UNetbootin le permite crear booteables
    Unidades USB en vivo para Ubuntu, Fedora y
    otras distribuciones de Linux sin
    quemando un CD. Se ejecuta en Windows, Linux,
    y ...
    Descargar UNetbootin
  • 6
    Dolibarr ERP-CRM
    Dolibarr ERP-CRM
    Dolibarr ERP - CRM es un fácil de usar
    Paquete de software de código abierto ERP y CRM
    (ejecutar con un servidor web php o como
    software independiente) para empresas,
    cimientos...
    Descargar Dolibarr ERP - CRM
  • Descargar la aplicación Windows Presentation Foundation para Linux" href="/es/software/linux/app-windows-presentation-foundation">Descargar la GUI de Transmission Remote para Linux, MacOS y Windows. La aplicación principal...
    Descargar trasero (transmitir usando esta herramienta)
  • Más "

Comandos de Linux

Ad