Tutorial del simulador de red ns-3. Capítulo 4

Tutorial del simulador de red ns-3. Capítulo 4
Capítulo 1,2
capitulo 3

4 Descripción general del concepto
4.1 Abstracciones clave
4.1.1 Nodo
4.1.2 Aplicación
4.1.3 Canal
4.1.4 Dispositivo de red
4.1.5 Asistentes topológicos
4.2 Primer script ns-3
4.2.1 Código repetitivo
4.2.2 Complementos
4.2.3 espacio de nombres ns3
4.2.4 Registro
4.2.5 Función principal
4.2.6 Uso de asistentes de topología
4.2.7 Uso de la aplicación
4.2.8 Simulador
4.2.9 Construyendo tu guión
4.3 Código fuente ns-3

Capítulo 4

Descripción general del concepto

Lo primero que debemos hacer antes de comenzar a aprender o escribir código ns-3 es explicar algunos conceptos básicos y abstracciones del sistema. Gran parte de esto puede parecer obvio para algunos, pero recomendamos tomarse el tiempo de leer esta sección para asegurarse de comenzar con una base sólida.

4.1 Abstracciones clave

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

4.1.1 Nodo

En la jerga de Internet, un dispositivo informático que se conecta a una red se denomina host o, a veces, sistema final. Debido a que ns-3 es un simulador de red y no un simulador de Internet, deliberadamente no utilizamos el término host, ya que está estrechamente relacionado con Internet y sus protocolos. En su lugar, utilizamos un término más general, también utilizado por otros simuladores, que se origina en la teoría de grafos: nodo (nodo).

En ns-3, la abstracción subyacente de un dispositivo informático se denomina nodo. Esta abstracción está representada en C++ por la clase Node. Clase NodoNodo (nodo) proporciona métodos para manipular representaciones de dispositivos informáticos en simulaciones.

Debes entender Nodo como una computadora a la que le agregas funcionalidad. Agregará cosas como aplicaciones, pilas de protocolos y tarjetas periféricas con controladores que permitan a la computadora realizar un trabajo útil. Usamos el mismo modelo básico en ns-3.

4.1.2 Aplicación

Generalmente, el software informático se divide en dos grandes clases. El software del sistema organiza diversos recursos informáticos, como memoria, ciclos de procesador, disco, red, etc., según algún modelo informático. El software del sistema normalmente no utiliza estos recursos para realizar tareas que beneficien directamente al usuario. Normalmente, un usuario ejecuta una aplicación para lograr un objetivo específico, que obtiene y utiliza recursos controlados por el software del sistema.

A menudo, la línea de separación entre el sistema y el software de la aplicación se traza en los cambios de nivel de privilegios que ocurren en las trampas del sistema operativo. ns-3 no tiene un concepto real de sistema operativo y, por lo tanto, no tiene ningún concepto de niveles de privilegio o llamadas al sistema. Sin embargo, tenemos una idea para una aplicación. Así como en el “mundo real” las aplicaciones de software se ejecutan en computadoras para realizar tareas, las aplicaciones ns-3 se ejecutan en nodos ns-3 para controlar simulaciones en el mundo simulado.

En ns-3, la abstracción básica de un programa de usuario que genera alguna actividad para modelar es una aplicación. Esta abstracción está representada en C++ por la clase Aplicación. La clase Aplicación proporciona métodos para manipular vistas de nuestra versión de aplicaciones a nivel de usuario en simulaciones. Se espera que los desarrolladores especialicen la clase Aplicación en un sentido de programación orientada a objetos para crear nuevas aplicaciones. En este tutorial, usaremos especializaciones de la clase Aplicación llamada UdpEchoClientApplicationUdpEchoClientApplication и UdpEchoServerApplicationUdpEchoServerApplication. Como es de esperar, estas aplicaciones constituyen un conjunto de aplicaciones cliente/servidor que se utilizan para generar y hacer eco de paquetes de red.

4.1.3 Canal

En el mundo real, puedes conectar una computadora a una red. A menudo, los medios por los que se transmiten los datos en estas redes se denominan canales. Cuando conecta un cable Ethernet a un tomacorriente de pared, está conectando su computadora a un enlace Ethernet. En el mundo simulado de ns-3, un nodo está conectado 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á representada en C++ por la clase Canal.

clase CanalCanal proporciona métodos para gestionar la interacción de objetos de subred y conectar nodos a ellos. Los desarrolladores también pueden especializar los canales en un sentido de programación orientada a objetos. La especialización de canales puede modelar algo tan simple como un cable. Un canal dedicado también puede modelar cosas complejas como un gran conmutador Ethernet o un espacio tridimensional lleno de obstáculos en el caso de redes inalámbricas.

Usaremos versiones especializadas del canal en este tutorial llamado Canal CsmaCanal Csma, PuntoAPuntoCanalPuntoAPuntoCanal и Canal WifiCanal Wifi. CsmaCanal, por ejemplo, modela una versión de una subred de comunicaciones que implementa un entorno de comunicaciones de acceso múltiple con detección de operador. Esto nos brinda una funcionalidad similar a Ethernet.

4.1.4 Dispositivo de red

Solía ​​ser que si querías conectar una computadora a una red, tenías que comprar un cable de red específico y un dispositivo de hardware llamado (en terminología de PC) tarjeta periférica que debía instalarse en la computadora. Si una tarjeta periférica implementaba algunas funciones de red, se las denominaba tarjetas de interfaz de red o tarjetas de red. Hoy en día, la mayoría de las computadoras vienen con hardware de interfaz de red integrado y los usuarios no las ven como dispositivos separados.

Una tarjeta de red no funcionará sin un controlador de software que controle su hardware. En Unix (o Linux), un equipo periférico se clasifica como dispositivo. Los dispositivos se administran mediante controladores de dispositivos y los dispositivos de red (NIC) se administran mediante controladores de dispositivos de red (controladores de dispositivos de red) y se denominan colectivamente dispositivos de red (dispositivos netos). En Unix y Linux, los dispositivos de red se refieren a nombres como eth0.

En ns-3, la abstracción del dispositivo de red cubre tanto el controlador de software como el hardware que se modela. En la simulación, se "instala" un dispositivo de red en un nodo para permitirle comunicarse con otros nodos a través de canales. Al igual que una computadora real, un nodo se puede conectar a múltiples canales a través de múltiples dispositivos. Dispositivos de red.

La abstracción de red de un dispositivo está representada en C++ por la clase dispositivo de red... Clase dispositivo de red proporciona métodos para gestionar conexiones a objetos Nodo y Canal; y los desarrolladores pueden especializarlo en el sentido de programación orientada a objetos. En este tutorial usaremos varias versiones especializadas de NetDevice llamadas Dispositivo CsmaNet, Dispositivo de red punto a punto и WifiRedDispositivo. Al igual que un adaptador de red Ethernet está diseñado para funcionar con una red Ethernet, Dispositivo CsmaNet diseñado para trabajar con CsmaCanal, Dispositivo de red punto a punto diseñado para trabajar con PuntoAPuntoCanalY WifiRedDispositivo - diseñado para trabajar con Canal Wifi.

4.1.5 Asistentes topológicos

En una red real, encontrará computadoras host con tarjetas de red agregadas (o integradas). En ns-3 diríamos que verá nodos con NetDevices conectados. En una gran red simulada, necesitarás organizar conexiones entre muchos objetos. Nodo, dispositivo de red и Channel.

Desde conectar NetDevices a nodos, NetDevices a enlaces, asignar direcciones IP, etc. en ns-3 son una tarea común; para que esto sea lo más fácil posible, proporcionamos los llamados ayudantes de topología. Por ejemplo, para crear un NetDevice, debe realizar muchas operaciones del kernel ns-3, agregar una dirección MAC, instalar el dispositivo de red en Node, configurar la pila de protocolos del nodo y luego conectar el NetDevice al canal. Se requerirá aún más trabajo para conectar múltiples dispositivos a enlaces multipunto y luego conectar las redes individuales a una red Internetworks. Proporcionamos objetos auxiliares de topología que combinan estas numerosas operaciones en un modelo fácil de usar para su comodidad.

4.2 Primer script ns-3

Si instaló el sistema como se sugirió anteriormente, tendrá la versión ns-3 en un directorio llamado repos en su directorio de inicio. Ir al directorio ,

Si no tiene dicho directorio, significa que no especificó el directorio de salida al compilar la versión de lanzamiento de ns-3, compílelo así:
$ ./waf configurar —build-profile=liberación —out=compilación/liberación,
$ ./waf compilación

allí deberías ver una estructura de directorios similar a la siguiente:

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

Ir al directorio ejemplos / tutorial. Deberías ver un archivo ubicado allí llamado primero.cc. Este es un script que creará una conexión punto a punto simple entre dos nodos y transmitirá un paquete entre los nodos. Veamos este script línea por línea; para hacer esto, abra first.cc en su editor favorito.

4.2.1 Código repetitivo
La primera línea del archivo es la línea del modo editor. emacs. Le informa a emacs sobre las convenciones de formato (estilo de codificación) que usamos en nuestro código fuente.

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

Este es siempre un tema bastante controvertido, por lo que debemos dejar las cosas claras para eliminarlo de inmediato. El proyecto ns-3, como la mayoría de los proyectos grandes, ha adoptado un estilo de codificación al que todo el código aportado debe ajustarse. Si desea contribuir con su código al proyecto, eventualmente tendrá que cumplir con el estándar de codificación ns-3, como se describe en el archivo. doc / codingstd.txt o mostrado en la página web del proyecto: https://www.nsnam.org/develop/contributing-code/coding-style/.

Le recomendamos que se acostumbre a la apariencia del código ns-3 y aplique este estándar siempre que trabaje con nuestro código. Todo el equipo de desarrollo y los contribuyentes estuvieron de acuerdo con esto después de algunas quejas. La línea de modo emacs anterior facilita el formato correcto si está utilizando el editor de emacs.

El simulador ns-3 tiene licencia de uso Licencia Pública General de GNU. Verá el encabezado legal GNU apropiado en cada archivo de distribución ns-3. A menudo verá un aviso de derechos de autor de una de las instituciones participantes en el proyecto ns-3 encima del texto y el autor de la GPL, que se muestran a continuación.

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

4.2.2 Complementos

El código en sí comienza con una serie de declaraciones de inclusión (incluir).

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

Para ayudar a nuestros usuarios de secuencias de comandos de alto nivel a lidiar con la gran cantidad de archivos de encabezado presentes en el sistema, los agrupamos según su uso en módulos grandes. Proporcionamos un único archivo de encabezado que cargará recursivamente todos los archivos de encabezado utilizados en un módulo determinado. En lugar de tener que buscar exactamente el encabezado que necesita y posiblemente obtener la lista correcta de dependencias, le brindamos la posibilidad de descargar un grupo de archivos con gran granularidad. No es el enfoque más eficiente, pero ciertamente facilita mucho la escritura de guiones.

Cada uno de los archivos de inclusión de ns-3 se coloca en un directorio llamado ns3 (subdirectorio de compilación) para evitar conflictos de nombres de archivos durante el proceso de compilación. Archivo ns3 / core-module.h corresponde al módulo ns-3, que encontrarás en el directorio src / core en la versión que instaló. En el listado de este directorio encontrará una gran cantidad de archivos de encabezado. Cuando hagas el montaje, Waf coloca los archivos de encabezado públicos en el directorio ns3 en un subdirectorio construir / depurar

Si no tiene dicho directorio, significa que no especificó el directorio de salida al compilar la versión de lanzamiento de ns-3, compílelo así:
$ ./waf configurar --build-profile=debug --out=build/debug
$ ./waf compilación
o
$ ./waf configurar --build-profile=optimizado --out=build/optimizado
$ ./waf compilación

o construir / optimizado, dependiendo de su configuración. Waf También generará automáticamente un archivo de inclusión de módulo para cargar todos los archivos de encabezado públicos. Como por supuesto estás siguiendo esta guía religiosamente, ya lo has hecho.

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

para configurar el proyecto para ejecutar compilaciones de depuración que incluyan ejemplos y pruebas. tu también lo hiciste

$ ./waf

para armar el proyecto. Entonces ahora cuando miras en el directorio ../../construir/depurar/ns3, luego allí encontrarás, entre otros, los archivos de encabezado de los cuatro módulos mostrados arriba. Puede observar el contenido de estos archivos y descubrir que incluyen todos los archivos públicos utilizados por los módulos correspondientes.

4.2.3 espacio de nombres ns3

Siguiente línea en el script primero.cc es una declaración de espacio de nombres.

using namespace ns3;

El proyecto ns-3 se implementa en un espacio de nombres de C++ llamado ns3. Esto agrupa todas las declaraciones relacionadas con ns-3 en un ámbito fuera del espacio de nombres global, lo que se espera ayude con la integración con otro código. El uso del operador C++ introduce el espacio de nombres ns-3 en la región declarativa actual (global). Esta es una forma elegante de decir que después de esta declaración, no necesitará escribir el operador de permiso ns3::scope antes de todo el código ns-3 para usarlo. Si no está familiarizado con los espacios de nombres, consulte casi cualquier tutorial de C++ y compare el espacio de nombres ns3 utilizando la declaración y el espacio de nombres estándar. using namespace std; en ejemplos de trabajo con el operador de salida cout y arroyos.

4.2.4 Registro

La siguiente línea del guión es:

NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");

Usaremos esta declaración como un lugar conveniente para discutir nuestro sistema de documentación. Doxygen. Si consulta el sitio web del proyecto ns-3, encontrará un enlace de Documentación en la barra de navegación. Si hace clic en este enlace, accederá a nuestra página de documentación. Hay un enlace "Última versión" que lo llevará a la documentación de la última versión estable de ns-3. Si selecciona el enlace "Documentación de API", accederá a la página de documentación de API de ns-3.

En el lado izquierdo de la página encontrará una representación gráfica de la estructura de la documentación. Un buen lugar para comenzar es el "libro" de Módulos ns-3 en el árbol de navegación de ns-3. si revelas Módulos, verá una lista de documentación de los módulos ns-3. Como se mencionó anteriormente, el concepto de módulo aquí está directamente relacionado con los archivos incluidos en el módulo anterior. El subsistema de registro ns-3 se analiza en la sección Usando el módulo de registro, así que volveremos a ello más adelante en este tutorial, pero puedes aprender sobre la declaración anterior mirando el módulo Corey luego abriendo el libro Herramientas de depuracióny luego seleccionando la página Inicio de sesión. Haga clic en Inicio de sesión.

Ahora deberías revisar la documentación. Doxygen para módulo Inicio de sesión. En la lista de macros en la parte superior de la página, verá una entrada para NS_LOG_COMPONENT_DEFINE. Antes de hacer clic en el enlace, asegúrese de consultar la "Descripción detallada" del módulo de registro para comprender cómo funciona en general. Para hacer esto, puede desplazarse hacia abajo o seleccionar "Más..." debajo del gráfico.

Una vez que tenga una idea general de lo que está sucediendo, continúe y consulte la documentación del NS_LOG_COMPONENT_DEFINE específico. No duplicaré la documentación aquí, pero para resumir, esta línea declara un componente de registro llamado PrimerScriptEjemplo, que le permite habilitar o deshabilitar el registro de mensajes de la consola por referencia a un nombre.

4.2.5 Función principal

En las siguientes líneas del script verá,

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

Esto es simplemente una declaración de la función principal de su programa (script). Como con cualquier programa C++, es necesario definir una función principal, que se ejecuta primero. No hay nada especial aquí. Su script ns-3 es solo un programa C++. La siguiente línea establece la resolución de tiempo en 1 nanosegundo, que es el valor predeterminado:

Time::SetResolution (Time::NS);

La resolución de tiempo, o simplemente resolución, es el valor de tiempo más pequeño que se puede utilizar (la diferencia más pequeña representable entre dos tiempos). Puedes cambiar la resolución exactamente una vez. El mecanismo que proporciona esta flexibilidad consume memoria, por lo que una vez que se establece explícitamente la resolución, liberamos la memoria, evitando futuras actualizaciones. (Si no establece la resolución explícitamente, la resolución predeterminada será de un nanosegundo y la memoria se liberará cuando comience la simulación).

Las siguientes dos líneas de script se utilizan para habilitar dos componentes de registro integrados en las aplicaciones. Cliente eco и servidor eco:

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

Si lee la documentación del componente Registro, verá que hay varios niveles de registro/granularidad que puede habilitar en cada componente. Estas dos líneas de código permiten el registro de depuración en el nivel INFO para clientes y servidores de eco. En este nivel, la aplicación imprimirá mensajes a medida que envía y recibe paquetes durante la simulación.

Ahora nos ocuparemos de crear la topología y ejecutar la simulación. Usamos objetos auxiliares de topología para hacer este trabajo lo más fácil posible.

4.2.6 Uso de asistentes de topología

Las siguientes dos líneas de código en nuestro script crearán los objetos Node ns-3 que representarán las computadoras en la simulación.

NodeContainer nodes;
nodes.Create (2);

Antes de continuar, busquemos la documentación de la clase. Contenedor de nodo. Otra forma de acceder a la documentación de una clase determinada es a través de la pestaña Clases en las paginas Doxygen. Si ya tiene Doxygen abierto, simplemente desplácese hasta la parte superior de la página y seleccione la pestaña Clases. Deberías ver un nuevo conjunto de pestañas, una de las cuales es una lista de clases. Debajo de esta pestaña verá una lista de todas las clases de ns-3. Desplácese hacia abajo para ns3::Contenedor de nodos. Cuando encuentre una clase, selecciónela para ir a la documentación de la clase.

Como recordamos, una de nuestras abstracciones clave es el nodo. Representa la computadora a la que vamos a agregar cosas como pilas de protocolos, aplicaciones y tarjetas periféricas. Asistente de topología Contenedor de nodo proporciona una manera conveniente de crear, administrar y acceder a cualquier objeto Nodo, que creamos para ejecutar la simulación. La primera línea de arriba simplemente declara Contenedor de nodo, que llamamos nodos. La segunda línea llama al método Create en el objeto de nodos y le pide al contenedor que cree dos nodos. Como se describe en Doxygen, el contenedor solicita al sistema ns-3 que cree dos objetos Nodo y almacena punteros a estos objetos internamente.

Los nodos creados en el script todavía no hacen nada. El siguiente paso en la construcción de la topología es conectar nuestros nodos a la red. La forma más simple de red que admitimos es una conexión punto a punto entre dos nodos. Ahora crearemos dicha conexión.

Ayudante punto a punto

Creamos una conexión punto a punto usando un patrón familiar, usando un objeto auxiliar de topología para realizar el trabajo de bajo nivel requerido para la conexión. Recuerde que nuestras dos abstracciones clave dispositivo de red и Channel. En el mundo real, estos términos corresponden aproximadamente a tarjetas periféricas y cables de red. Normalmente, estas dos cosas están estrechamente relacionadas entre sí y nadie puede contar con compartir, por ejemplo, dispositivos. Ethernet a través de un canal inalámbrico. Nuestros ayudantes de topología siguen esta estrecha relación y, por lo tanto, utilizará un solo objeto en este escenario. Ayudante punto a punto para configurar y conectar objetos ns-3 Dispositivo de red punto a punto и PuntoAPuntoCanal. Las siguientes tres líneas del guión:

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

Primera linea,

PointToPointHelper pointToPoint;

crea una instancia de un objeto en la pila Ayudante punto a punto. Desde un punto de vista de alto nivel, la siguiente línea,

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

le dice al objeto Ayudante punto a punto utilice el valor "5 Mbit/s" (cinco megabits por segundo) como "Velocidad de datos".

Desde un punto de vista más específico, la cadena "DataRate" corresponde a lo que llamamos un atributo Dispositivo de red punto a punto. Si miras Doxygen para clase ns3::Dispositivo de red punto a punto y en la documentación del método ObtenerIdTipo Encontrará una lista de atributos definidos para el dispositivo. Entre ellos estará el atributo “Velocidad de datos" La mayoría de los objetos ns-3 visibles para el usuario tienen listas de atributos similares. Usamos este mecanismo para configurar fácilmente la simulación sin tener que volver a compilarla, como verá en la siguiente sección.

Similar a "Velocidad de datos" en PointToPointNetDevice, encontrará el atributo "Retraso" asociado con PointToPointChannel. la linea final

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

dice Ayudante punto a punto utilice el valor "2 ms" (dos milisegundos) como valor de retardo de propagación para el enlace punto a punto que crea posteriormente.

NetDeviceContainerNetDeviceContainer

Por el momento tenemos en el guión. Contenedor de nodo, que contiene dos nodos. Tenemos Ayudante punto a punto, que está preparado para crear objetos. Dispositivos de red punto a punto y conectarlos usando un objeto PointToPointChannel. Así como usamos el objeto auxiliar de topología NodeContainer para crear nodos, le preguntaremos Ayudante punto a punto realizar trabajos para nosotros relacionados con la creación, configuración e instalación de nuestros dispositivos. Necesitamos una lista de todos los objetos creados. dispositivo de red, entonces usamos NetDeviceContainerNetDeviceContainer para almacenarlos de la misma manera que usamos Contenedor de nodo para almacenar los nodos que creamos. Las siguientes dos líneas de código,

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

configuración completa del dispositivo y canal. La primera línea declara el contenedor del dispositivo mencionado anteriormente y la segunda hace el trabajo principal. Método Instalar un objeto Ayudante punto a punto toma Contenedor de nodo como parámetro. Adentro NetDeviceContainerNetDeviceContainer para cada nodo ubicado en Contenedor de nodo se crea (para la comunicación punto a punto debe haber exactamente dos de ellos) Dispositivo de red punto a punto se crea y guarda en el contenedor del dispositivo. PuntoAPuntoCanal se crea y se le adjuntan dos Dispositivos de red punto a punto. Después de crear objetos, los atributos almacenados en Ayudante punto a punto, se utilizan para inicializar los atributos correspondientes en los objetos creados.

Después de hacer una llamada pointToPoint.Install (nodos) Tendremos dos nodos, cada uno con un dispositivo de red punto a punto instalado y un enlace punto a punto entre ellos. Ambos dispositivos estarán configurados para transmitir datos a una velocidad de cinco megabits por segundo con un retraso de transmisión de dos milisegundos a través del canal.

Ayudante de pila de Internet

Ahora tenemos nodos y dispositivos configurados, pero nuestros nodos no tienen pilas de protocolos instaladas. Las siguientes dos líneas de código se encargarán de esto.

InternetStackHelper stack;
stack.Install (nodes);

Ayudante de pila de Internet - es un asistente de topología para pilas de Internet, similar a PointToPointHelper para dispositivos de red punto a punto. Método Instalar toma NodeContainer como parámetro. Cuando se ejecute, instalará la pila de Internet (TCP, UDP, IP, etc.) en cada nodo contenedor.

Ayudante de direcciones Ipv4

Luego necesitamos asociar nuestros dispositivos con direcciones IP. Proporcionamos un asistente de topología para gestionar la asignación de direcciones IP. La única API visible para el usuario es configurar la dirección IP base y la máscara de red que se usarán al realizar la distribución de direcciones real (esto se hace en un nivel inferior dentro del asistente). Las siguientes dos líneas de código en nuestro script de ejemplo primero.cc,

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

declare el objeto auxiliar de dirección y dígale que debe comenzar a asignar direcciones IP desde la red 10.1.1.0, usando la máscara de bits 255.255.255.0 para determinar. De forma predeterminada, 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, luego 10.1.1.2, etc. En realidad, en un nivel bajo, el sistema ns-3 recuerda todas las direcciones IP asignadas y genera un error fatal si accidentalmente crea una situación en la que se genera la misma dirección dos veces (por cierto, este error es difícil de depurar).

La siguiente línea de código,

Ipv4InterfaceContainer interfaces = address.Assign (devices);

realiza la asignación de dirección real. En ns-3 establecemos una conexión entre una dirección IP y un dispositivo usando el objeto Interfaz Ipv4. Así como a veces necesitamos una lista de dispositivos de red creados por el asistente para su uso posterior, a veces necesitamos una lista de objetos Interfaz Ipv4. Ipv4InterfazContenedor proporciona esta funcionalidad.

Construimos una red punto a punto, con pilas instaladas y direcciones IP asignadas. Ahora necesitamos aplicaciones en cada nodo para generar tráfico.

4.2.7 Uso de la aplicación

Otra de las principales abstracciones del sistema ns-3 es Aplicación (solicitud). En este escenario estamos utilizando dos especializaciones de clase base. Aplicación ns-3 llamado UdpEchoServerApplicationUdpEchoServerApplication и UdpEchoClientApplicationUdpEchoClientApplication. Como en casos anteriores, utilizamos objetos auxiliares para configurar y gestionar los objetos base. aquí usamos Ayudante UdpEchoServer и UdpEchoClientAyudar objetos para hacernos la vida más fácil.

Ayudante UdpEchoServer

Las siguientes líneas de código en nuestro script de ejemplo first.cc se utilizan para configurar una aplicación de servidor de eco UDP en uno de los nodos que creamos anteriormente.

UdpEchoServerHelper echoServer (9);

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

La primera línea de código en el fragmento anterior crea Ayudante UdpEchoServer. Como es habitual, esta no es una aplicación en sí, es un objeto que nos ayuda a crear aplicaciones reales. Una de nuestras convenciones es pasar los atributos requeridos al constructor del objeto auxiliar. En este caso, el asistente no puede hacer nada útil a menos que se le proporcione el número de puerto en el que el servidor escuchará los paquetes; este número también debe ser conocido por el cliente. En este caso, pasamos el número de puerto al constructor auxiliar. El constructor, a su vez, simplemente hace Establecer Atributo con el valor pasado. Más adelante, si lo desea, puede utilizar SetAttribute para establecer un valor diferente para el atributo Puerto.

Como muchos otros objetos auxiliares, el objeto Ayudante UdpEchoServer tiene un método Instalar. La ejecución de este método crea efectivamente una aplicación de servidor de eco básica y la vincula al host. Curiosamente, el método Instalar toma Contenedor de nodo como parámetro al igual que los demás Instalar métodos que hemos visto.

La conversión implícita de C++ que funciona aquí toma el resultado del método. nodo.Get(1) (que devuelve un puntero inteligente al objeto de nodo - Ptr ) y lo usa en el constructor del objeto anónimo Contenedor de nodoque luego se pasa al método Instalar. Si no puede determinar en el código C++ qué firma de método se compila y ejecuta, busque entre las conversiones implícitas.

Ahora vemos que echoServer.Instalar a punto de instalar la aplicación UdpEchoServerApplicationUdpEchoServerApplication en encontrado en Contenedor de nodoque utilizamos para gestionar nuestros nodos, nodo con índice 1. Método Instalar devolverá un contenedor que contiene punteros a todas las aplicaciones (en este caso una, ya que pasamos un anónimo Contenedor de nodo, que contiene un nodo) creado por el asistente.

Las aplicaciones deben especificar cuándo comenzar a generar tráfico "comenzar" y es posible que deba especificar adicionalmente una hora en la que detenerlo "detener". Ofrecemos ambas opciones. Estos tiempos se establecen utilizando los métodos AplicaciónContenedor Inicio и Detener. Estos métodos aceptan parámetros de tipo Horario. En este caso utilizamos una secuencia explícita de conversiones de C++ para tomar C++. doble 1.0 y conviértalo en un objeto de tiempo tns-3 que usa el objeto Segundos para convertir a segundos. Recuerde 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 contar con que los parámetros se conviertan de la forma esperada. Dos lineas

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

hará que la aplicación del servidor de eco se inicie (se encienda automáticamente) un segundo después de que comience la simulación y se detenga (se apague) después de diez segundos de la simulación. Debido a que declaramos un evento de simulación (evento de detención de la aplicación), que se ejecutará en diez segundos, se simularán al menos diez segundos de operación de la red.

UdpEchoClientHelper

Solicitud de cliente echo configurado de una manera casi similar al servidor. Hay un objeto base UdpEchoClientApplicationUdpEchoClientApplicationcontener
UdpEchoClientHelper.

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

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

Sin embargo, para el cliente echo necesitamos configurar cinco atributos diferentes. Los dos primeros atributos se establecen en el momento de la creación. UdpEchoClientHelper. Pasamos parámetros que se utilizan (dentro del ayudante) para establecer los atributos. "Dirección remota" и "Puerto remoto" de acuerdo con nuestro acuerdo para pasar los parámetros necesarios al constructor auxiliar.

Recordemos que usamos Ipv4InterfazContenedor para rastrear las direcciones IP que tenemos asignadas a nuestros dispositivos. La interfaz nula en el contenedor de interfaces corresponderá a la dirección IP del nodo nulo en el contenedor de nodos. La primera interfaz en el contenedor de interfaces corresponde a la dirección IP del primer nodo en el contenedor de nodos. Entonces, en la primera línea de código (arriba), creamos un asistente y le decimos que la dirección remota del cliente será la dirección IP asignada al host donde se encuentra el servidor. También decimos que necesitamos organizar el envío de paquetes al puerto nueve.

El atributo "MaxPackets" le dice al cliente la cantidad máxima de paquetes que podemos enviar durante la simulación. El atributo "Intervalo" le dice al cliente cuánto tiempo esperar entre paquetes, y el atributo "PacketSize" le dice al cliente qué tan grande debe ser la carga útil del paquete. Con esta combinación de atributos le decimos al cliente que envíe un único paquete de 1024 bytes.

Al igual que con el servidor de eco, configuramos los atributos del cliente de eco Inicio и Detener, pero aquí iniciamos el cliente un segundo después de encender el servidor (dos segundos después del inicio de la simulación).

4.2.8 Simulador

En este punto necesitamos ejecutar la simulación. Esto se hace usando la función global. Simulador::Ejecutar.

Simulator::Run ();

Cuando llamamos a los métodos anteriormente,

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

De hecho, programamos eventos en el simulador a 1,0 segundos, 2,0 segundos y dos eventos a 10,0 segundos. despues de la llamada Simulador::Ejecutar, el sistema comenzará a ver la lista de eventos programados y ejecutarlos. Primero activará un evento después de 1,0 segundos, lo que activará la aplicación del servidor de eco (este evento, a su vez, puede programar muchos otros eventos). Luego activará un evento programado en t=2,0 segundos que iniciará la aplicación del cliente de eco. Nuevamente, este evento puede tener muchos más eventos planeados. La implementación del evento de inicio en el cliente de eco comenzará la fase de transferencia de datos de la simulación enviando un paquete al servidor.

El acto de enviar un paquete al servidor desencadenará una cadena de eventos que se programarán automáticamente entre bastidores y que implementarán la mecánica de enviar un paquete de eco de acuerdo con los parámetros de tiempo que hayamos establecido en el script.

Como resultado, dado que estamos enviando solo un paquete (recuerde, el atributo Paquetes máximos se configuró en uno), la cadena de eventos iniciada por este ping de cliente único finalizará y la simulación pasará al modo de espera. Una vez que esto suceda, los eventos restantes programados serán los eventos Detener para servidor y cliente. Cuando se ejecuten estos eventos, no quedarán eventos para su posterior procesamiento y Simulador::Ejecutar devolverá el control. La simulación está completa.

Todo lo que queda es limpiar lo que ensucia. Esto se hace llamando a la función global. Simulador::Destruir. Porque se llamaron las funciones auxiliares (o código ns-3 de bajo nivel), que están organizadas de manera que se insertaron ganchos en el simulador para destruir todos los objetos que se crearon. No necesitabas rastrear ninguno de estos objetos tú mismo; todo lo que tenías que hacer era llamar Simulador::Destruir y sal. El sistema ns-3 hará este arduo trabajo por usted. Las líneas restantes de nuestro primer script ns-3, first.cc, hacen precisamente eso:

Simulator::Destroy ();
return 0;
}

¿Cuándo se detendrá el simulador?

ns-3 es un simulador de eventos discretos (DE). En dicho simulador, cada evento está asociado con su tiempo de ejecución y la simulación continúa procesando los eventos en el orden en que ocurren a medida que avanza la simulación. Los eventos pueden hacer que se programen eventos futuros (por ejemplo, un temporizador puede reprogramarse para terminar de contar en el siguiente intervalo).

Los eventos iniciales generalmente los inicia la entidad; por ejemplo, IPv6 programará el descubrimiento de servicios en la red, solicitudes de vecinos, etc. La aplicación programa el primer evento de envío de paquetes, y así sucesivamente. Cuando se procesa un evento, puede generar cero, uno o más eventos. A medida que avanza la simulación, ocurren eventos, que terminan o crean otros nuevos. La simulación se detendrá automáticamente si la cola de eventos está vacía o se detecta un evento especial. Detener. Evento Detener generado por la función Simulador::Parar (para el tiempo).

Hay un caso típico en el que Simulator::Stop es absolutamente necesario para detener la simulación: cuando hay eventos autosostenibles. Los eventos autosostenibles (o repetitivos) son eventos que siempre se reprograman. Como consecuencia, siempre mantienen la cola de eventos no vacía. Existen muchos protocolos y módulos que contienen eventos repetidos, por ejemplo:

• FlowMonitor: comprobación periódica de paquetes perdidos;

• RIPng – difusión periódica de actualizaciones de la tabla de enrutamiento;

• etc.

En esos casos Simulador::Parar necesario para detener la simulación correctamente. Además, cuando ns-3 está en modo de emulación, RealtimeSimulator se utiliza para sincronizar el reloj de simulación con el reloj de la máquina, y Simulador::Parar necesario detener el proceso.

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

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

En realidad, lo anterior no cambiará el comportamiento de este programa, ya que esta simulación en particular finaliza naturalmente después de 10 segundos. Pero si cambiara el tiempo de parada en la declaración anterior de 11 segundos a 1 segundo, notaría que la simulación se detiene antes de que cualquier salida llegue a la pantalla (ya que la salida ocurre después de aproximadamente 2 segundos de tiempo de simulación).

Es importante llamar a Simulator::Stop antes de llamar a Simulator::Run; de lo contrario, es posible que Simulator::Run nunca devuelva el control al programa principal para ejecutar la parada.

4.2.9 Construyendo tu guión

Hemos hecho que la creación de scripts simples sea trivial. Todo lo que tienes que hacer es poner tu script en el directorio temporal y se compilará automáticamente si ejecutas Waf. Intentemos. Vuelva al directorio de nivel superior y copie ejemplos/tutorial/first.cc catalogar rayar

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

Ahora cree su primer script de muestra usando waf:

$ ./waf

Debería ver mensajes que indiquen que su primer ejemplo se creó correctamente.

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

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

$ ./waf --run scratch/myfirst

Deberías ver un resultado similar:

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

Aquí puede ver que el sistema de compilación verifica que el archivo se haya compilado y luego lo ejecuta. Verá que la entrada del componente en el cliente de eco indica que envió un único paquete de 1024 bytes al servidor de eco 10.1.1.2. Usted también ve el componente de registro en el servidor de eco para decir que recibió 1024 bytes de 10.1.1.1. El servidor de eco reproduce silenciosamente el paquete y puede ver en el registro del cliente de eco que recibió su paquete del servidor.

4.3 Código fuente ns-3

Ahora que ha utilizado algunos de los asistentes de ns-3, puede echar un vistazo al código fuente que implementa esta funcionalidad. El código más reciente se puede ver en nuestro servidor web en el siguiente enlace: https://gitlab.com/nsnam/ns-3-dev.git. Allí verá la página de resumen de Mercurial para nuestro árbol de desarrollo ns-3. En la parte superior de la página verá varios enlaces,

summary | shortlog | changelog | graph | tags | files

Continúe y seleccione el enlace de archivos. Así es como se verá el nivel superior de la mayoría de nuestros repositorios:

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

Nuestros scripts de ejemplo están en el directorio. ejemplos. Si hace clic en los ejemplos, verá una lista de subdirectorios. Uno de los archivos en el subdirectorio. tutorial - primero.cc. Si haces clic en primero.cc Verá el código que acaba de aprender.

El código fuente se encuentra principalmente en el directorio. src. Puede ver el código fuente haciendo clic en el nombre del directorio o haciendo clic en el enlace de archivos a la derecha del nombre del directorio. Si hace clic en el directorio src, obtendrá una lista de subdirectorios src. Si luego hace clic en el subdirectorio principal, encontrará una lista de archivos. El primer archivo que verá (al momento de escribir esta guía) es abortar.h. Si haces clic en el enlace abortar.h, se le enviará al archivo fuente para abortar.h, que contiene macros útiles para salir de scripts si se detectan condiciones anormales. El código fuente de los ayudantes que utilizamos en este capítulo se puede encontrar en el directorio src/Aplicaciones/ayudante. Siéntase libre de husmear en el árbol de directorios para descubrir dónde está y el estilo de los programas ns-3.

Fuente: habr.com

Añadir un comentario