
4 Visão geral do conceito
4.1 Principais abstrações
4.1.1 Nó
4.1.2 Aplicação
4.1.3 Canal
4.1.4 Dispositivo de Rede
4.1.5 Assistentes topológicos
4.2 Primeiro script ns-3
4.2.1 Código padrão
4.2.2 Plug-ins
4.2.3 Namespace ns3
4.2.4 Registro
4.2.5 Função principal
4.2.6 Usando assistentes de topologia
4.2.7 Usando Aplicativo
4.2.8 Simulador
4.2.9 Construindo seu roteiro
4.3 Código-fonte do ns-3
Capítulo 4
Visão geral do conceito
A primeira coisa que precisamos fazer antes de começarmos a aprender ou escrever código ns-3 é explicar alguns conceitos básicos e abstrações do sistema. Muito disso pode parecer óbvio para alguns, mas recomendamos reservar um tempo para ler esta seção para garantir que você esteja começando com uma base sólida.
4.1 Principais abstrações
Nesta seção, veremos alguns termos que são comumente usados na web, mas que possuem um significado específico no ns-3.
4.1.1 Nó
No jargão da Internet, um dispositivo de computador que se conecta a uma rede é chamado de host ou, às vezes, de sistema final. Como o ns-3 é um simulador de rede e não um simulador de Internet, deliberadamente não utilizamos o termo host, pois está intimamente relacionado à Internet e seus protocolos. Em vez disso, usamos um termo mais geral, também usado por outros simuladores, que tem origem na teoria dos grafos: nó (nó).
No ns-3, a abstração subjacente de um dispositivo de computação é chamada de nó. Esta abstração é representada em C++ pela classe Node. Aula NóNode (nó) fornece métodos para manipular representações de dispositivos de computação em simulações.
Você deve entender Node como um computador ao qual você adiciona funcionalidade. Você adicionará itens como aplicativos, pilhas de protocolos e placas periféricas com drivers que permitem ao computador realizar trabalhos úteis. Usamos o mesmo modelo básico no ns-3.
4.1.2 Aplicação
Geralmente, o software de computador é dividido em duas grandes classes. O software do sistema organiza vários recursos do computador, como memória, ciclos de processador, disco, rede, etc., de acordo com algum modelo de computação. O software do sistema normalmente não utiliza esses recursos para executar tarefas que beneficiem diretamente o usuário. Um usuário normalmente executa um aplicativo para atingir um objetivo específico, que obtém e utiliza recursos controlados pelo software do sistema.
Freqüentemente, a linha de separação entre o sistema e o software aplicativo é traçada nas alterações de nível de privilégio que ocorrem nas armadilhas do sistema operacional. O ns-3 não tem nenhum conceito real de sistema operacional e, portanto, nenhum conceito de níveis de privilégio ou chamadas de sistema. No entanto, temos uma ideia para um aplicativo. Assim como no “mundo real” os aplicativos de software são executados em computadores para realizar tarefas, os aplicativos ns-3 são executados em nós ns-3 para controlar simulações no mundo simulado.
No ns-3, a abstração básica para um programa de usuário que gera alguma atividade para modelagem é uma aplicação. Essa abstração é representada em C++ pela classe Application. A classe Application fornece métodos para manipular visualizações de nossa versão de aplicativos em nível de usuário em simulações. Espera-se que os desenvolvedores especializem a classe Application no sentido de programação orientada a objetos para criar novos aplicativos. Neste tutorial, usaremos especializações da classe Application chamada Aplicativo UdpEchoClient и Aplicativo UdpEchoServer. Como seria de esperar, esses aplicativos constituem um conjunto de aplicativos cliente/servidor usados para gerar e ecoar pacotes de rede.
4.1.3 Canal
No mundo real, você pode conectar um computador a uma rede. Freqüentemente, os meios pelos quais os dados são transmitidos nessas redes são chamados de canais. Ao conectar um cabo Ethernet a uma tomada de parede, você conecta seu computador a um link Ethernet. No mundo simulado do ns-3, um nó está conectado a um objeto que representa um canal de comunicação. Aqui, a abstração básica da sub-rede de comunicação é chamada de canal e é representada em C++ pela classe Channel.
Classe CanalCanal fornece métodos para gerenciar a interação de objetos de sub-rede e conectar nós a eles. Os canais também podem ser especializados pelos desenvolvedores no sentido de programação orientada a objetos. A especialização de canal pode modelar algo tão simples quanto um fio. Um canal dedicado também pode modelar coisas complexas como um grande switch Ethernet ou um espaço tridimensional cheio de obstáculos no caso de redes sem fio.
Usaremos versões especializadas do canal neste tutorial chamado CsmaChannelCsmaChannel, PointToPointChannelPointToPointChannel и WifiCanalWifiCanal. Canal Csma, por exemplo, modela uma versão de uma sub-rede de comunicações que implementa um ambiente de comunicações de acesso múltiplo com detecção de portadora. Isso nos dá uma funcionalidade semelhante à Ethernet.
4.1.4 Dispositivo de Rede
Antigamente, se você quisesse conectar um computador a uma rede, era necessário comprar um cabo de rede específico e um dispositivo de hardware chamado (na terminologia do PC) uma placa periférica que precisava ser instalada no computador. Se uma placa periférica implementasse algumas funções de rede, elas eram chamadas de placas de interface de rede ou placas de rede. Hoje, a maioria dos computadores vem com hardware de interface de rede integrado e não são vistos pelos usuários como dispositivos separados.
Uma placa de rede não funciona sem um driver de software que controle seu hardware. No Unix (ou Linux), um equipamento periférico é classificado como um dispositivo. Os dispositivos são controlados por meio de drivers de dispositivo, e os dispositivos de rede (NICs) são controlados por meio de drivers de dispositivo de rede (drivers de dispositivos de rede) e são chamados coletivamente de dispositivos de rede (dispositivos de rede). Em Unix e Linux Você acessa dispositivos de rede por nomes como eth0.
No ns-3, a abstração do dispositivo de rede abrange tanto o driver de software quanto o hardware que está sendo modelado. Na simulação, um dispositivo de rede é “instalado” em um nó para permitir que ele se comunique com outros nós através de canais. Assim como um computador real, um nó pode ser conectado a vários canais através de vários dispositivos Dispositivos Net.
A abstração de rede de um dispositivo é representada em C++ pela classe Dispositivo Net... Aula Dispositivo Net fornece métodos para gerenciar conexões com objetos Node e Channel; e pode ser especializado por desenvolvedores no sentido de programação orientada a objetos. Neste tutorial usaremos diversas versões especializadas do NetDevice chamadas Dispositivo CsmaNet, Dispositivo ponto a ponto Net и Dispositivo WifiNet. Assim como um adaptador de rede Ethernet foi projetado para funcionar com uma rede Ethernet, Dispositivo CsmaNet projetado para trabalhar com Canal Csma, Dispositivo ponto a ponto Net projetado para trabalhar com Canal ponto a pontoE Dispositivo WifiNet - projetado para trabalhar com Canal Wi-Fi.
4.1.5 Assistentes topológicos
Em uma rede real, você encontrará computadores host com placas de rede adicionadas (ou integradas). No ns-3 diríamos que você verá nós com NetDevices conectados. Em uma grande rede simulada, você precisará organizar conexões entre muitos objetos Node , Dispositivo Net и Canal.
Desde conectar NetDevices a nós, NetDevices a links, atribuir endereços IP, etc. no ns-3 são uma tarefa comum, para tornar isso o mais fácil possível, fornecemos os chamados auxiliares de topologia. Por exemplo, para criar um NetDevice, você precisa realizar muitas operações do kernel ns-3, adicionar um endereço MAC, instalar o dispositivo de rede no Node, configurar a pilha de protocolos do nó e, em seguida, conectar o NetDevice ao Canal. Será necessário ainda mais trabalho para conectar vários dispositivos a links multiponto e depois conectar as redes individuais em uma rede Internetworks. Fornecemos objetos auxiliares de topologia que combinam essas diversas operações em um modelo fácil de usar para sua conveniência.
4.2 Primeiro script ns-3
Se você instalou o sistema conforme sugerido acima, você terá a versão do ns-3 em um diretório chamado repos em seu diretório home. Ir para o diretório liberar
Se você não possui esse diretório, significa que você não especificou o diretório de saída ao construir a versão de lançamento do ns-3, construa assim:
$ ./waf configure —build-profile=release —out=build/release,
$ ./waf compilação
lá você deverá ver uma estrutura de diretórios semelhante à seguinte:
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.pycIr para o diretório exemplos / tutorial. Você deverá ver um arquivo localizado lá chamado primeiro.cc. Este é um script que criará uma conexão ponto a ponto simples entre dois nós e transmitirá um pacote entre os nós. Vejamos este script linha por linha; para fazer isso, abra first.cc em seu editor favorito.
4.2.1 Código padrão
A primeira linha do arquivo é a linha do modo editor emacs. Ele informa ao emacs sobre as convenções de formatação (estilo de codificação) que usamos em nosso código-fonte.
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */Esta é sempre uma questão bastante controversa, por isso precisamos esclarecer as coisas para tirá-la do caminho imediatamente. O projeto ns-3, como a maioria dos grandes projetos, adotou um estilo de codificação ao qual todo código contribuído deve obedecer. Se você quiser contribuir com seu código para o projeto, eventualmente terá que estar em conformidade com o padrão de codificação ns-3, conforme descrito no arquivo doc / codingstd.txt ou mostrado na página web do projeto: .
Recomendamos que você se acostume com a aparência do código ns-3 e aplique esse padrão sempre que trabalhar com nosso código. Toda a equipe de desenvolvimento e colaboradores concordaram com isso depois de algumas reclamações. A linha do modo emacs acima facilita a formatação correta se você estiver usando o editor emacs.
O simulador ns-3 é licenciado usando GNU General Public License. Você verá o cabeçalho legal GNU apropriado em cada arquivo de distribuição do ns-3. Muitas vezes você verá um aviso de copyright de uma das instituições participantes do projeto ns-3 acima do texto e autor da GPL, mostrado abaixo.
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/4.2.2 Plug-ins
O próprio código começa com uma série de instruções de inclusão (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 ajudar nossos usuários de scripts de alto nível a lidar com o grande número de arquivos de cabeçalho presentes no sistema, nós os agrupamos de acordo com seu uso em grandes módulos. Fornecemos um único arquivo de cabeçalho que carregará recursivamente todos os arquivos de cabeçalho usados em um determinado módulo. Em vez de ter que procurar exatamente qual cabeçalho você precisa e possivelmente obter a lista correta de dependências, oferecemos a capacidade de baixar um grupo de arquivos com grande granularidade. Não é a abordagem mais eficiente, mas certamente facilita muito a escrita de scripts.
Cada um dos arquivos de inclusão do ns-3 é colocado em um diretório chamado ns3 (subdiretório de construção) para evitar conflitos de nome de arquivo durante o processo de construção. Arquivo ns3 / core-module.h corresponde ao módulo ns-3, que você encontrará no diretório src / core na versão que você instalou. Na listagem deste diretório você encontrará um grande número de arquivos de cabeçalho. Quando você faz a montagem, Waf coloca arquivos de cabeçalho público no diretório ns3 em um subdiretório construir / depurar
Se você não possui esse diretório, significa que você não especificou o diretório de saída ao construir a versão de lançamento do ns-3, construa assim:
$ ./waf configure --build-profile=debug --out=build/debug
$ ./waf compilação
ou
$ ./waf configure --build-profile=optimizado --out=build/otimizado
$ ./waf compilação
ou construir / otimizado, dependendo da sua configuração. Waf também gerará automaticamente um arquivo de inclusão de módulo para carregar todos os arquivos de cabeçalho público. Como é claro que você está seguindo este guia religiosamente, você já fez
$ ./waf -d debug --enable-examples --enable-tests configurepara configurar o projeto para executar compilações de depuração que incluem exemplos e testes. Você também fez
$ ./wafpara montar o projeto. Então agora, quando você olha no diretório ../../build/debug/ns3, aí você encontrará, entre outros, os arquivos de cabeçalho dos quatro módulos mostrados acima. Você pode observar o conteúdo desses arquivos e descobrir que eles incluem todos os arquivos públicos usados pelos módulos correspondentes.
4.2.3 Namespace ns3
Próxima linha no script primeiro.cc é uma declaração de namespace.
using namespace ns3;O projeto ns-3 é implementado em um namespace C++ chamado ns3. Isso agrupa todas as declarações relacionadas ao ns-3 em um escopo fora do namespace global, o que esperançosamente ajudará na integração com outros códigos. O uso do operador C++ introduz o namespace ns-3 na região declarativa atual (global). Esta é uma maneira elegante de dizer que após esta declaração, você não precisará digitar o operador de permissão ns3::scope antes de todo o seu código ns-3 para usá-lo. Se você não estiver familiarizado com namespaces, consulte quase qualquer tutorial C++ e compare o namespace ns3 usando o namespace e a declaração std using namespace std; em exemplos de trabalho com o operador de saída cout e fluxos.
4.2.4 Registro
A próxima linha do script é,
NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");Usaremos esta declaração como um local conveniente para discutir nosso sistema de documentação Doxygen. Se você consultar o site do projeto ns-3, encontrará um link de documentação na barra de navegação. Se você clicar neste link, você será direcionado para nossa página de documentação. Existe um link "Latest Release" que o levará à documentação da última versão estável do ns-3. Se você selecionar o link "API Documentation", você será direcionado para a página de documentação da API ns-3.
No lado esquerdo da página você encontrará uma representação gráfica da estrutura da documentação. Um bom lugar para começar é o "livro" Módulos ns-3 na árvore de navegação do ns-3. Se você revelar Módulos, você verá uma lista de documentação dos módulos do ns-3. Conforme discutido acima, o conceito de módulo aqui está diretamente relacionado aos arquivos incluídos no módulo acima. O subsistema de registro do ns-3 é discutido na seção Usando o Módulo de Log, então voltaremos a isso mais tarde neste tutorial, mas você pode aprender sobre a afirmação acima olhando o módulo Setores dee então abrindo o livro Ferramentas de depuraçãoe selecionando a página Logging. Clique em Logging.
Agora você deve revisar a documentação Doxygen para módulo Logging. Na lista de macros no topo da página você verá uma entrada para NS_LOG_COMPONENT_DEFINE. Antes de clicar no link, não deixe de conferir a “Descrição detalhada” do módulo de cadastro para entender como ele funciona em geral. Para fazer isso, você pode rolar para baixo ou selecionar "Mais..." abaixo do gráfico.
Depois de ter uma ideia geral do que está acontecendo, vá em frente e consulte a documentação do NS_LOG_COMPONENT_DEFINE específico. Não vou duplicar a documentação aqui, mas para resumir, esta linha declara um componente de registro chamado Exemplo de FirstScript, que permite ativar ou desativar o log de mensagens do console por referência a um nome.
4.2.5 Função principal
Nas linhas a seguir do script você verá,
int
main (int argc, char *argv[])
{ Esta é simplesmente uma declaração da função principal do seu programa (script). Como acontece com qualquer programa C++, você precisa definir uma função principal, que é executada primeiro. Não há nada de especial aqui. Seu script ns-3 é apenas um programa C++. A linha a seguir define a resolução de tempo para 1 nanossegundo, que é o padrão:
Time::SetResolution (Time::NS);A resolução de tempo, ou simplesmente resolução, é o menor valor de tempo que pode ser usado (a menor diferença representável entre dois tempos). Você pode alterar a resolução exatamente uma vez. O mecanismo que proporciona essa flexibilidade consome memória, portanto, uma vez definida explicitamente a resolução, liberamos memória, evitando futuras atualizações. (Se você não definir a resolução explicitamente, o padrão será um nanossegundo e a memória será liberada quando a simulação começar.)
As duas linhas de script a seguir são usadas para ativar dois componentes de registro integrados em aplicativos EcoCliente и Servidor Eco:
LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO); LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO);Se você ler a documentação do componente Logging, verá que existem vários níveis de registro/granularidade que podem ser ativados em cada componente. Essas duas linhas de código permitem o log de depuração no nível INFO para clientes e servidores de eco. Neste nível, a aplicação imprimirá mensagens à medida que envia e recebe pacotes durante a simulação.
Agora vamos começar a criar a topologia e executar a simulação. Usamos objetos auxiliares de topologia para tornar esse trabalho o mais fácil possível.
4.2.6 Usando assistentes de topologia
As próximas duas linhas de código em nosso script criarão os objetos Node ns-3 que representarão os computadores na simulação.
NodeContainer nodes;
nodes.Create (2);Antes de continuarmos, vamos encontrar a documentação da classe NodeContainer. Outra forma de acessar a documentação de uma determinada classe é através da aba Classes nas páginas Doxygen. Se você já tem o Doxygen aberto, basta rolar até o topo da página e selecionar a guia Classes. Você deverá ver um novo conjunto de guias, uma das quais é uma lista de classes. Nesta aba você verá uma lista de todas as classes do ns-3. Role para baixo até ns3::NodeContainer. Ao encontrar uma turma, selecione-a para acessar a documentação da turma.
Como lembramos, uma de nossas principais abstrações é o nó. Representa o computador ao qual adicionaremos itens como pilhas de protocolos, aplicativos e placas periféricas. Assistente de topologia NodeContainer fornece uma maneira conveniente de criar, gerenciar e acessar quaisquer objetos Node , que criamos para executar a simulação. A primeira linha acima simplesmente declara NodeContainer, que chamamos de nós. A segunda linha chama o método Create no objeto de nós e solicita ao contêiner que crie dois nós. Conforme descrito em Doxygen, o contêiner solicita ao sistema ns-3 que crie dois objetos Node e armazena ponteiros para esses objetos internamente.
Os nós criados no script ainda não fazem nada. A próxima etapa na construção da topologia é conectar nossos nós à rede. A forma mais simples de rede que oferecemos suporte é uma conexão ponto a ponto entre dois nós. Agora criaremos essa conexão.
PointToPoint Helper
Criamos uma conexão ponto a ponto usando um padrão familiar, usando um objeto auxiliar de topologia para realizar o trabalho de baixo nível necessário para a conexão. Lembre-se de que nossas duas abstrações principais Dispositivo Net и Canal. No mundo real, estes termos correspondem aproximadamente a placas periféricas e cabos de rede. Normalmente, essas duas coisas estão intimamente relacionadas e ninguém pode contar com o compartilhamento, por exemplo, de dispositivos Ethernet através de um canal sem fio. Nossos ajudantes de topologia seguem esse relacionamento próximo e, portanto, você usará um único objeto neste cenário PointToPoint Helper para configurar e conectar objetos ns-3 Dispositivo ponto a ponto Net и Canal ponto a ponto. As próximas três linhas do script:
PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));Primeira linha,
PointToPointHelper pointToPoint;cria uma instância de um objeto na pilha PointToPoint Helper. Do ponto de vista de nível superior, a seguinte linha,
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));diz ao objeto PointToPoint Helper use o valor "5 Mbit/s" (cinco megabits por segundo) como "Taxa de dados".
De um ponto de vista mais específico, a string “DataRate” corresponde ao que chamamos de atributo Dispositivo ponto a ponto Net. Se você olhar Doxygen para classe ns3 :: PointToPointNetDevice e na documentação do método ObterTypeId você encontrará uma lista de atributos definidos para o dispositivo. Entre eles estará o atributo “Taxa de dados" A maioria dos objetos ns-3 visíveis ao usuário possui listas de atributos semelhantes. Usamos esse mecanismo para configurar facilmente a simulação sem recompilação, como você verá na próxima seção.
Igual a "Taxa de dados" em PointToPointNetDevice, você encontrará o atributo "Delay" associado ao PointToPointChannel. A linha final
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));fala PointToPoint Helper use o valor "2 ms" (dois milissegundos) como o valor do atraso de propagação para o link ponto a ponto que ele cria posteriormente.
NetDevice Container
No momento temos no roteiro NodeContainer, que contém dois nós. Nós temos PointToPoint Helper, que está preparado para criar objetos Dispositivos PointToPointNet e conectá-los usando um objeto PointToPointChannel. Assim como usamos o objeto auxiliar de topologia NodeContainer para criar nós, perguntaremos PointToPoint Helper realizar trabalhos para nós relacionados à criação, configuração e instalação de nossos dispositivos. Precisamos de uma lista de todos os objetos criados Dispositivo Net, então usamos NetDevice Container para armazená-los da mesma maneira que usamos NodeContainer para armazenar os nós que criamos. As próximas duas linhas de código,
NetDeviceContainer devices;
devices = pointToPoint.Install (nodes);configuração completa do dispositivo e canal. A primeira linha declara o contêiner do dispositivo mencionado acima e a segunda faz o trabalho principal. Método Instale um objeto PointToPoint Helper toma NodeContainer como parâmetro. Dentro NetDevice Container para cada nó localizado em NodeContainer é criado (para comunicação ponto a ponto deve haver exatamente dois deles) Dispositivo ponto a ponto Net é criado e salvo no contêiner do dispositivo. Canal ponto a ponto é criado e dois são anexados a ele Dispositivos PointToPointNet. Depois de criar objetos, os atributos armazenados em PointToPoint Helper, são usados para inicializar os atributos correspondentes nos objetos criados.
Depois de fazer uma ligação pointToPoint.Install (nós) teremos dois nós, cada um com um dispositivo de rede ponto a ponto instalado e um link ponto a ponto entre eles. Ambos os dispositivos serão configurados para transmitir dados a uma velocidade de cinco megabits por segundo com atraso de transmissão de dois milissegundos pelo canal.
InternetStackHelper
Agora temos nós e dispositivos configurados, mas nossos nós não possuem pilhas de protocolos instaladas. As próximas duas linhas de código cuidarão disso.
InternetStackHelper stack;
stack.Install (nodes);InternetStackHelper - é um auxiliar de topologia para pilhas de Internet, semelhante ao PointToPointHelper para dispositivos de rede ponto a ponto. Método Instale usa NodeContainer como parâmetro. Quando executado, instalará a pilha da Internet (TCP, UDP, IP, etc.) em cada nó do contêiner.
Ajudante de Endereço Ipv4
Então precisamos associar nossos dispositivos a endereços IP. Fornecemos um assistente de topologia para gerenciar a alocação de endereços IP. A única API visível para o usuário é definir o endereço IP base e a máscara de rede a serem usados ao fazer a distribuição real do endereço (isso é feito em um nível inferior dentro do auxiliar). As próximas duas linhas de código em nosso script de exemplo primeiro.cc,
Ipv4AddressHelper address;
address.SetBase ("10.1.1.0", "255.255.255.0");declare o objeto auxiliar de endereço e diga a ele que ele deve começar a alocar endereços IP da rede 10.1.1.0, usando a máscara de bits 255.255.255.0 para determinar. Por padrão, os endereços alocados começarão em um e aumentarão monotonicamente, então o primeiro endereço alocado nesta base será 10.1.1.1, depois 10.1.1.2, etc. Na realidade, em um nível baixo, o sistema ns-3 lembra todos os endereços IP alocados e gera um erro fatal se você acidentalmente criar uma situação em que o mesmo endereço seja gerado duas vezes (aliás, esse erro é difícil de depurar).
A seguinte linha de código,
Ipv4InterfaceContainer interfaces = address.Assign (devices);executa a atribuição de endereço real. No ns-3 estabelecemos uma associação entre um endereço IP e um dispositivo usando o objeto Interface IPv4. Assim como às vezes precisamos de uma lista de dispositivos de rede criada pelo assistente para uso posterior, às vezes precisamos de uma lista de objetos Interface IPv4. Ipv4InterfaceContainer fornece essa funcionalidade.
Construímos uma rede ponto a ponto, com pilhas instaladas e endereços IP atribuídos. Agora precisamos de aplicativos em cada nó para gerar tráfego.
4.2.7 Usando Aplicativo
Outra das principais abstrações do sistema ns-3 é Aplicação (aplicativo). Neste cenário, estamos usando duas especializações de classe base Aplicação ns-3 chamado Aplicativo UdpEchoServer и Aplicativo UdpEchoClient. Como nos casos anteriores, utilizamos objetos auxiliares para configurar e gerenciar os objetos base. Aqui usamos UdpEchoServerHelperName и UdpEchoClientAjudar objetos para facilitar nossas vidas.
UdpEchoServerHelperName
As linhas de código a seguir em nosso script de exemplo first.cc são usadas para configurar um aplicativo de servidor de eco UDP em um dos nós que criamos anteriormente.
UdpEchoServerHelper echoServer (9);
ApplicationContainer serverApps = echoServer.Install (nodes.Get (1));
serverApps.Start (Seconds (1.0));
serverApps.Stop (Seconds (10.0));A primeira linha de código no trecho acima cria UdpEchoServerHelperName. Como sempre, este não é um aplicativo em si, é um objeto que nos ajuda a criar aplicativos reais. Uma de nossas convenções é passar os atributos necessários para o construtor do objeto auxiliar. Neste caso, o auxiliar não pode fazer nada de útil a menos que lhe seja fornecido o número da porta na qual o servidor irá escutar os pacotes; este número também deve ser conhecido pelo cliente. Neste caso, passamos o número da porta para o construtor auxiliar. O construtor, por sua vez, simplesmente faz Definir atributo com o valor passado. Posteriormente, se desejar, você poderá usar SetAttribute para definir um valor diferente para o atributo Port.
Como muitos outros objetos auxiliares, o objeto UdpEchoServerHelperName tem um método Instale. A execução desse método cria efetivamente um aplicativo básico de servidor de eco e o vincula ao host. Curiosamente, o método Instale toma NodeContainer como parâmetro assim como os outros Instale métodos que vimos.
A conversão implícita C++ que funciona aqui leva o resultado do método nó.Get(1) (que retorna um ponteiro inteligente para o objeto do nó - Ptr ) e usa-o no construtor do objeto anônimo NodeContainerque é então passado para o método Instale. Se você não conseguir determinar no código C++ qual assinatura de método é compilada e executada, procure entre as conversões implícitas.
Agora vemos isso echoServer.Instalar prestes a instalar o aplicativo Aplicativo UdpEchoServer em encontrado em NodeContainerque usamos para gerenciar nossos nós, nó com índice 1. Método Instale retornará um contêiner que contém ponteiros para todos os aplicativos (neste caso, já que passamos um anônimo NodeContainer, contendo um nó) criado pelo auxiliar.
Os aplicativos precisam especificar quando começar a gerar tráfego "começar" e pode ser necessário especificar adicionalmente um momento para interrompê-lo "parar". Oferecemos ambas as opções. Esses tempos são definidos usando os métodos ApplicationContainer Começar и Dê um basta. Esses métodos aceitam parâmetros do tipo Tempo. Neste caso, usamos uma sequência explícita de conversões C++ para obter C++ duplo 1.0 e converta-o em um objeto Time tns-3 que usa o objeto Seconds para converter em segundos. Lembre-se de que as regras de conversão podem ser controladas pelo autor do modelo e o C++ possui regras próprias, portanto nem sempre você pode contar com a conversão dos parâmetros da maneira esperada. Duas linhas
serverApps.Start (Seconds (1.0));
serverApps.Stop (Seconds (10.0));fará com que o aplicativo do servidor de eco seja iniciado (ligado automaticamente) um segundo após o início da simulação e pare (desligado) após dez segundos da simulação. Devido ao fato de termos declarado um evento de simulação (evento de parada de aplicação), que será executado em dez segundos, serão simulados pelo menos dez segundos de operação da rede.
UdpEchoClientHelper
Aplicativo cliente eco configurado de maneira quase semelhante ao servidor. Existe um objeto base Aplicativo UdpEchoClient, que é administrado
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));;Entretanto, para o cliente echo precisamos definir cinco atributos diferentes. Os dois primeiros atributos são definidos no momento da criação UdpEchoClientHelper. Passamos parâmetros que são usados (dentro do helper) para definir os atributos "Endereço Remoto" и "Porta Remota" de acordo com nosso acordo para passar os parâmetros necessários ao construtor auxiliar.
Vamos lembrar que usamos Ipv4InterfaceContainer para rastrear os endereços IP que atribuímos aos nossos dispositivos. A interface nula no contêiner de interfaces corresponderá ao endereço IP do nó nulo no contêiner de nós. A primeira interface no contêiner de interfaces corresponde ao endereço IP do primeiro nó no contêiner de nós. Assim, na primeira linha do código (acima), criamos um helper e informamos que o endereço remoto do cliente será o endereço IP atribuído ao nó onde o servidor está localizado. Também dizemos que precisamos providenciar o envio dos pacotes para a porta nove.
O atributo “MaxPackets” informa ao cliente o número máximo de pacotes que podemos enviar durante a simulação. O atributo “Interval” informa ao cliente quanto tempo esperar entre os pacotes, e o atributo “PacketSize” informa ao cliente qual deve ser o tamanho da carga útil do pacote. Com esta combinação de atributos dizemos ao cliente para enviar um único pacote de 1024 bytes.
Tal como acontece com o servidor de eco, definimos os atributos do cliente de eco Começar и Dê um basta, mas aqui iniciamos o cliente um segundo após o servidor ser ligado (dois segundos após o início da simulação).
4.2.8 Simulador
Neste ponto precisamos executar a simulação. Isso é feito usando a função global Simulador :: Executar.
Simulator::Run ();Quando chamamos métodos anteriormente,
serverApps.Start (Seconds (1.0));
serverApps.Stop (Seconds (10.0));
...
clientApps.Start (Seconds (2.0));
clientApps.Stop (Seconds (10.0));na verdade, agendamos eventos no simulador para 1,0 segundos, 2,0 segundos e dois eventos para 10,0 segundos. Depois da ligação Simulador :: Executar, o sistema começará a visualizar a lista de eventos agendados e a executá-los. Ele primeiro disparará um evento após 1,0 segundo, o que acionará o aplicativo do servidor de eco (esse evento pode, por sua vez, agendar muitos outros eventos). Em seguida, ele disparará um evento agendado para t=2,0 segundos que iniciará o aplicativo cliente de eco. Novamente, este evento pode ter muitos outros eventos planejados. A implementação do evento start no cliente echo iniciará a fase de transferência de dados da simulação enviando um pacote ao servidor.
O ato de enviar um pacote ao servidor irá desencadear uma cadeia de eventos que serão automaticamente agendados nos bastidores e que implementarão a mecânica de envio de um pacote de eco de acordo com os parâmetros de tempo que definimos no script.
Como resultado, como estamos enviando apenas um pacote (lembre-se, o atributo MaxPackets foi definido como um), a cadeia de eventos iniciada por este ping de cliente único terminará e a simulação entrará em modo de espera. Quando isso acontecer, os eventos agendados restantes serão os eventos Dê um basta para servidor e cliente. Quando esses eventos forem executados, não haverá mais eventos para processamento adicional e Simulador :: Executar retornará o controle. A simulação está completa.
Tudo o que resta é limpar você mesmo. Isso é feito chamando a função global Simulador :: Destruir. Porque foram chamadas as funções auxiliares (ou código ns-3 de baixo nível), que são organizadas de forma que ganchos foram inseridos no simulador para destruir todos os objetos que foram criados. Você não precisava rastrear nenhum desses objetos sozinho - tudo que você precisava fazer era ligar Simulador :: Destruir e sair. O sistema ns-3 fará esse trabalho duro para você. As linhas restantes do nosso primeiro script ns-3, first.cc, fazem exatamente isso:
Simulator::Destroy ();
return 0;
}Quando o simulador irá parar?
ns-3 é um simulador de eventos discretos (DE). Nesse simulador, cada evento está associado ao seu tempo de execução, e a simulação continua processando os eventos na ordem em que ocorrem à medida que a simulação avança. Os eventos podem fazer com que eventos futuros sejam agendados (por exemplo, um cronômetro pode se reprogramar para terminar a contagem no próximo intervalo).
Os eventos iniciais geralmente são iniciados pela entidade, por exemplo o IPv6 irá agendar a descoberta de serviços na rede, solicitações de vizinhos, etc. A aplicação agenda o primeiro evento de envio de pacotes e assim por diante. Quando um evento é processado, ele pode gerar zero, um ou mais eventos. À medida que a simulação avança, eventos ocorrem, encerrando ou criando novos. A simulação irá parar automaticamente se a fila de eventos estiver vazia ou um evento especial for detectado Dê um basta. Evento Dê um basta gerado pela função Simulador :: Pare (pare o tempo).
Há um caso típico onde Simulator::Stop é absolutamente necessário para parar a simulação: quando há eventos autossustentáveis. Eventos autossustentáveis (ou repetidos) são eventos que são sempre reprogramados. Como consequência, eles sempre mantêm a fila de eventos não vazia. Existem muitos protocolos e módulos contendo eventos repetidos, por exemplo:
• FlowMonitor – verificação periódica de pacotes perdidos;
• RIPng – transmissão periódica de atualizações da tabela de roteamento;
• etc.
Em tais casos Simulador :: Pare necessário para parar a simulação corretamente. Além disso, quando o ns-3 está em modo de emulação, o RealtimeSimulator é usado para sincronizar o relógio da simulação com o relógio da máquina, e Simulador :: Pare necessário para interromper o processo.
Muitos dos programas de simulação no livro didático não chamam Simulador :: Pare explicitamente, uma vez que terminam automaticamente quando os eventos enfileirados se esgotam. No entanto, esses programas também aceitarão a chamada Simulator::Stop. Por exemplo, a seguinte instrução adicional no primeiro programa de exemplo agendará uma parada explícita em 11 segundos:
+ Simulator::Stop (Seconds (11.0));
Simulator::Run ();
Simulator::Destroy ();
return 0;
}O que foi dito acima não irá realmente alterar o comportamento deste programa, uma vez que esta simulação em particular termina naturalmente após 10 segundos. Mas se você alterasse o tempo de parada na instrução acima de 11 segundos para 1 segundo, notaria que a simulação para antes que qualquer saída chegue à tela (já que a saída ocorre após cerca de 2 segundos do tempo de simulação).
É importante chamar Simulator::Stop antes de chamar Simulator::Run; caso contrário, Simulator::Run poderá nunca retornar o controle ao programa principal para executar a parada!
4.2.9 Construindo seu roteiro
Tornamos a criação de seus scripts simples algo trivial. Tudo que você precisa fazer é colocar seu script no diretório scratch e ele será compilado automaticamente se você executar Waf. Vamos tentar. Volte para o diretório de nível superior e copie exemplos / tutorial / first.cc catalogar arranhar
$ cd ../..
$ cp examples/tutorial/first.cc scratch/myfirst.ccAgora crie seu primeiro script de amostra usando WAF:
$ ./wafVocê deverá ver mensagens indicando que seu primeiro exemplo foi criado com sucesso.
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)Agora você pode executar o exemplo (observe que se você compilar seu programa no diretório scratch, deverá executá-lo a partir de arranhar):
$ ./waf --run scratch/myfirstVocê deverá ver uma saída semelhante:
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.2Aqui você pode ver que o sistema de compilação verifica se o arquivo foi compilado e então o executa. Você vê a entrada do componente no cliente de eco indicando que ele enviou um único pacote de 1024 bytes para o servidor de eco 10.1.1.2. Você também vê o componente de log no servidor echo para dizer que recebeu 1024 bytes de 10.1.1.1. O servidor de eco reproduz silenciosamente o pacote e você pode ver no log do cliente de eco que ele recebeu o pacote de volta do servidor.
4.3 Código-fonte do ns-3
Agora que você usou alguns dos auxiliares do ns-3, você pode dar uma olhada em alguns códigos-fonte que implementam essa funcionalidade. O código mais recente pode ser visualizado em nosso servidor web no seguinte link: . Lá você verá a página de resumo do Mercurial para nossa árvore de desenvolvimento do ns-3. No topo da página você verá vários links,
summary | shortlog | changelog | graph | tags | filesVá em frente e selecione o link dos arquivos. Esta é a aparência do nível superior da maioria dos nossos repositórios:
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 | annotateNossos scripts de exemplo estão no diretório exemplos. Se você clicar nos exemplos, verá uma lista de subdiretórios. Um dos arquivos do subdiretório tutorial - primeiro.cc. Se você clicar em primeiro.cc você verá o código que acabou de aprender.
O código fonte está localizado principalmente no diretório src. Você pode visualizar o código-fonte clicando no nome do diretório ou clicando no link dos arquivos à direita do nome do diretório. Se você clicar no diretório src, obterá uma lista de subdiretórios src. Se você clicar no subdiretório principal, encontrará uma lista de arquivos. O primeiro arquivo que você verá (no momento em que este guia foi escrito) é abortar.h. Se você clicar no link abortar.h, você será enviado para o arquivo de origem para abortar.h, que contém macros úteis para sair de scripts se condições anormais forem detectadas. O código fonte dos helpers que usamos neste capítulo pode ser encontrado no diretório src/Aplicativos/helper. Sinta-se à vontade para vasculhar a árvore de diretórios para descobrir onde está e entender o estilo dos programas ns-3.
Fonte: habr.com
