Loading...

# 4. 仿真流程

在本节中,将介绍 ns3 中仿真的流程,

# 基本流程

使用 ns3 仿真时,一般经过以下 4 个步骤。

# 1. 选择或开发相应的模块

根据实际仿真对象和仿真场景选择相应的仿真模块:如有线网或还是无线网 ( Wi-Fi ),节点移动性 mobility ,能量 energy , 路由协议,应用程序 application 等,若是没有相应模块,那就需要自己编写 (在后续章节中讲述)。

# 2. 编写网络仿真脚本

若是有了相应的模块,那么我们就可以搭建网络仿真环境,ns-3 仿真脚本支持 2 种语言:C 和 Python,两种语言接口的 API 接口是一样的,但是部分 API 可能没有 Python 的接口。所以,仿真主要还是采用 C 进行编写。

编写 ns-3 仿真脚本的大体过程如下【具体的例子查看 examples/tutorial/ 下面 的示例,后面也会分析一些】:

  • 生成节点:ns-3 中节点相当于一个空的计算机外壳,我们需要根据需求给这个计算机安装网络所需要的软硬件,如网卡、应用程序、协议栈等。

  • 安装网卡设备:不同的网络类型有不同的网络设备,从而提供不同的通信、物理层和 MAC 层,如 CSMA WI-FI WIMAXpoint-to-point 等。

  • 安装协议栈ns-3 网络中一般是 TCP/IP 协议栈,依据网络选择具体协议,如是 UDP 还是 TCP ,选择何种不同的路由协议( OLSR AODVGlobal 等)并为其配置相应的 IP 地址, ns3 既支持 IPv4 也支持 IPv6

  • 安装应用层协议:依据选择的传输层协议选择相应的应用层协议,但是有时需要自己编写应用层产生数据流量的代码。

  • 其他配置:如节点是否移动,是否需要能量管理等

  • 启动仿真:整个网络场景配置完毕,启动仿真

# 3. 仿真结果分析

仿真结果一般有两种:一种是网络场景,二是网络数据。网络场景如节点拓扑结构、移动模型等,一般通过可视化界面( PyViz 或者 NetAnim )可直接观测到。网络数据可以在可视化界面进行简单统计,此外还可以通过专门的统计框架 status 或者自行通过 ns3 提供的追踪框架收集、统计和分析相应的网络数据,如数据分组的延迟、网络流量、分组丢失和节点消息缓存队列的等, 但是上述统计结果对于一些新的开源模块可能不一定有用,所以更推荐的是采用 track 自行分析。

# 4. 依据仿真结果调整网络配置参数或者修改源代码。

# 例子

为了更好的展示上述流程,样例代码是 aodv 的实例代码,位于 ns-3.xx/src/aodv/examples

完整代码如下所示:

#include <iostream>
#include <cmath>
#include "ns3/aodv-module.h"
#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/internet-module.h"
#include "ns3/mobility-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/v4ping-helper.h"
#include "ns3/yans-wifi-helper.h"
using namespace ns3;
/**
 * \ingroup aodv-examples
 * \ingroup examples
 * \brief Test script.
 * 
 * This script creates 1-dimensional grid topology and then ping last node from the first one:
 * 
 * [10.0.0.1] <-- step --> [10.0.0.2] <-- step --> [10.0.0.3] <-- step --> [10.0.0.4]
 * 
 * ping 10.0.0.4
 *
 * When 1/3 of simulation time has elapsed, one of the nodes is moved out of
 * range, thereby breaking the topology.  By default, this will result in
 * only 34 of 100 pings being received.  If the step size is reduced
 * to cover the gap, then all pings can be received.
 */
class AodvExample 
{
public:
  AodvExample ();
  /**
   * \brief Configure script parameters
   * \param argc is the command line argument count
   * \param argv is the command line arguments
   * \return true on successful configuration
  */
  bool Configure (int argc, char **argv);
  /// Run simulation
  void Run ();
  /**
   * Report results
   * \param os the output stream
   */
  void Report (std::ostream & os);
private:
  // parameters
  /// Number of nodes
  uint32_t size;
  /// Distance between nodes, meters
  double step;
  /// Simulation time, seconds
  double totalTime;
  /// Write per-device PCAP traces if true
  bool pcap;
  /// Print routes if true
  bool printRoutes;
  // network
  /// nodes used in the example
  NodeContainer nodes;
  /// devices used in the example
  NetDeviceContainer devices;
  /// interfaces used in the example
  Ipv4InterfaceContainer interfaces;
private:
  /// Create the nodes
  void CreateNodes ();
  /// Create the devices
  void CreateDevices ();
  /// Create the network
  void InstallInternetStack ();
  /// Create the simulation applications
  void InstallApplications ();
};
int main (int argc, char **argv)
{
  AodvExample test;
  if (!test.Configure (argc, argv))
    NS_FATAL_ERROR ("Configuration failed. Aborted.");
  test.Run ();
  test.Report (std::cout);
  return 0;
}
//-----------------------------------------------------------------------------
AodvExample::AodvExample () :
  size (10),
  step (50),
  totalTime (100),
  pcap (true),
  printRoutes (true)
{
}
bool
AodvExample::Configure (int argc, char **argv)
{
  // Enable AODV logs by default. Comment this if too noisy
  // LogComponentEnable("AodvRoutingProtocol", LOG_LEVEL_ALL);
  SeedManager::SetSeed (12345);
  CommandLine cmd (__FILE__);
  cmd.AddValue ("pcap", "Write PCAP traces.", pcap);
  cmd.AddValue ("printRoutes", "Print routing table dumps.", printRoutes);
  cmd.AddValue ("size", "Number of nodes.", size);
  cmd.AddValue ("time", "Simulation time, s.", totalTime);
  cmd.AddValue ("step", "Grid step, m", step);
  cmd.Parse (argc, argv);
  return true;
}
void
AodvExample::Run ()
{
//  Config::SetDefault ("ns3::WifiRemoteStationManager::RtsCtsThreshold", UintegerValue (1)); // enable rts cts all the time.
  CreateNodes ();
  CreateDevices ();
  InstallInternetStack ();
  InstallApplications ();
  std::cout << "Starting simulation for " << totalTime << " s ...\n";
  Simulator::Stop (Seconds (totalTime));
  Simulator::Run ();
  Simulator::Destroy ();
}
void
AodvExample::Report (std::ostream &)
{ 
}
void
AodvExample::CreateNodes ()
{
  std::cout << "Creating " << (unsigned)size << " nodes " << step << " m apart.\n";
  nodes.Create (size);
  // Name nodes
  for (uint32_t i = 0; i < size; ++i)
    {
      std::ostringstream os;
      os << "node-" << i;
      Names::Add (os.str (), nodes.Get (i));
    }
  // Create static grid
  MobilityHelper mobility;
  mobility.SetPositionAllocator ("ns3::GridPositionAllocator",
                                 "MinX", DoubleValue (0.0),
                                 "MinY", DoubleValue (0.0),
                                 "DeltaX", DoubleValue (step),
                                 "DeltaY", DoubleValue (0),
                                 "GridWidth", UintegerValue (size),
                                 "LayoutType", StringValue ("RowFirst"));
  mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
  mobility.Install (nodes);
}
void
AodvExample::CreateDevices ()
{
  WifiMacHelper wifiMac;
  wifiMac.SetType ("ns3::AdhocWifiMac");
  YansWifiPhyHelper wifiPhy = YansWifiPhyHelper::Default ();
  YansWifiChannelHelper wifiChannel = YansWifiChannelHelper::Default ();
  wifiPhy.SetChannel (wifiChannel.Create ());
  WifiHelper wifi;
  wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager", "DataMode", StringValue ("OfdmRate6Mbps"), "RtsCtsThreshold", UintegerValue (0));
  devices = wifi.Install (wifiPhy, wifiMac, nodes); 
  if (pcap)
    {
      wifiPhy.EnablePcapAll (std::string ("aodv"));
    }
}
void
AodvExample::InstallInternetStack ()
{
  AodvHelper aodv;
  // you can configure AODV attributes here using aodv.Set(name, value)
  InternetStackHelper stack;
  stack.SetRoutingHelper (aodv); // has effect on the next Install ()
  stack.Install (nodes);
  Ipv4AddressHelper address;
  address.SetBase ("10.0.0.0", "255.0.0.0");
  interfaces = address.Assign (devices);
  if (printRoutes)
    {
      Ptr<OutputStreamWrapper> routingStream = Create<OutputStreamWrapper> ("aodv.routes", std::ios::out);
      aodv.PrintRoutingTableAllAt (Seconds (8), routingStream);
    }
}
void
AodvExample::InstallApplications ()
{
  V4PingHelper ping (interfaces.GetAddress (size - 1));
  ping.SetAttribute ("Verbose", BooleanValue (true));
  ApplicationContainer p = ping.Install (nodes.Get (0));
  p.Start (Seconds (0));
  p.Stop (Seconds (totalTime) - Seconds (0.001));
  // move node away
  Ptr<Node> node = nodes.Get (size/2);
  Ptr<MobilityModel> mob = node->GetObject<MobilityModel> ();
  Simulator::Schedule (Seconds (totalTime/3), &MobilityModel::SetPosition, mob, Vector (1e5, 1e5, 1e5));
}

从上述代码 run 函数中也可以很清晰的看出,实际上总共就分为几个步骤.

void AodvExample::Run ()
{
  CreateNodes (); // 创建节点
  CreateDevices ();// 创建设备
  InstallInternetStack ();// 安装协议栈
  InstallApplications ();// 设置应用
  std::cout << "Starting simulation for " << totalTime << " s ...\n";
  Simulator::Stop (Seconds (totalTime));
  Simulator::Run ();
  Simulator::Destroy ();
}

# 1. 创建节点过程

创建了 size 个节点,并编号命名,

然后节点采用了 Grid 布局,(0,0) 点开始,

然后设置节点静止不动。

void AodvExample::CreateNodes ()
{
  std::cout << "Creating " << (unsigned)size << " nodes " << step << " m apart.\n";
  nodes.Create (size);
  // Name nodes
  for (uint32_t i = 0; i < size; ++i)
    {
      std::ostringstream os;
      os << "node-" << i;
      Names::Add (os.str (), nodes.Get (i));
    }
  // Create static grid
  MobilityHelper mobility;
  mobility.SetPositionAllocator ("ns3::GridPositionAllocator",
                                 "MinX", DoubleValue (0.0),
                                 "MinY", DoubleValue (0.0),
                                 "DeltaX", DoubleValue (step),
                                 "DeltaY", DoubleValue (0),
                                 "GridWidth", UintegerValue (size),
                                 "LayoutType", StringValue ("RowFirst"));
  mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
  mobility.Install (nodes);
}

# 2. 创建设备

设置了 wifi 信道,wifi 的速率,pcap 设置一般没什么用,需要第三方软件分析可以采用。

void AodvExample::CreateDevices ()
{
  WifiMacHelper wifiMac;
  wifiMac.SetType ("ns3::AdhocWifiMac");
  YansWifiPhyHelper wifiPhy = YansWifiPhyHelper::Default ();
  YansWifiChannelHelper wifiChannel = YansWifiChannelHelper::Default ();
  wifiPhy.SetChannel (wifiChannel.Create ());
  WifiHelper wifi;
  wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager", "DataMode", StringValue ("OfdmRate6Mbps"), "RtsCtsThreshold", UintegerValue (0));
  devices = wifi.Install (wifiPhy, wifiMac, nodes); 
  if (pcap)
    {
      wifiPhy.EnablePcapAll (std::string ("aodv"));
    }
}

# 3. 安装协议栈

路由选择了 aodv 路由协议,设置了节点的 Ipv4 地址,设置是否需要打印路由表。

void AodvExample::InstallInternetStack ()
{
  AodvHelper aodv;
  // you can configure AODV attributes here using aodv.Set(name, value)
  InternetStackHelper stack;
  stack.SetRoutingHelper (aodv); // has effect on the next Install ()
  stack.Install (nodes);
  Ipv4AddressHelper address;
  address.SetBase ("10.0.0.0", "255.0.0.0");
  interfaces = address.Assign (devices);
  if (printRoutes)
    {
      Ptr<OutputStreamWrapper> routingStream = Create<OutputStreamWrapper> ("aodv.routes", std::ios::out);
      aodv.PrintRoutingTableAllAt (Seconds (8), routingStream);
    }
}

# 4. 设置应用

设置了 ping 的应用程序,正常测网络性能,用的是 OnOffHelper 或者直接 socket 测试。

void AodvExample::InstallApplications ()
{
  V4PingHelper ping (interfaces.GetAddress (size - 1));
  ping.SetAttribute ("Verbose", BooleanValue (true));
  ApplicationContainer p = ping.Install (nodes.Get (0));
  p.Start (Seconds (0));
  p.Stop (Seconds (totalTime) - Seconds (0.001));
  // move node away
  Ptr<Node> node = nodes.Get (size/2);
  Ptr<MobilityModel> mob = node->GetObject<MobilityModel> ();
  Simulator::Schedule (Seconds (totalTime/3), &MobilityModel::SetPosition, mob, Vector (1e5, 1e5, 1e5));
}
更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

jluyeyu 微信支付

微信支付

jluyeyu 支付宝

支付宝