Pinvon's Blog

所见, 所闻, 所思, 所想

ns-3快速上手

需要的安装包

sudo apt install gcc g++ python 
sudo apt install gcc g++ python python-dev 
sudo apt install mercurial python-setuptools git
sudo apt install qt4-dev-tools libqt4-dev
sudo apt install cmake libc6-dev libc6-dev-i386 g++-multilib
sudo apt install gdb valgrind
sudo apt install gsl-bin libgsl2 libgsl-dev
sudo apt install flex bison libfl-dev
sudo apt install tcpdump
sudo apt install sqlite sqlite3 libsqlite3-dev
sudo apt install libxml2 libxml2-dev
sudo apt install libgtk2.0-0 libgtk2.0-dev
sudo apt install vtun lxc
sudo apt install uncrustify
sudo apt install doxygen graphviz imagemagick
sudo apt install texlive texlive-extra-utils texlive-latex-extra texlive-font-utils texlive-lang-portuguese dvipng
sudo apt install python-sphinx dia
sudo apt install python-pygraphviz python-kiwi python-pygoocanvas libgoocanvas-dev ipython
sudo apt install libboost-signals-dev libboost-filesystem-dev
sudo apt install openmpi-bin openmpi-common openmpi-doc libopenmpi-dev

其中, gcc和g++可以不是指定的3.4版本, 但要比这个版本更新. 另外, 由于系统的版本不同, libgsl0ldbl和python-pygoocanvas和libgoo-canvas-dev三个装不上, 其中, 在Ubuntu 16.04LTS之后, 使用libgsl0-dev即可替代libgsl0ldbl, 而另外两个则在需要的时候再查看资料安装.

下载ns-3

使用mercurial

mercurial是一种轻量级分布式版本控制系统, 采用Python语言实现, 易于学习和使用, 扩展性强. 此处不使用mercurial来下载ns-3.

直接下载tar压缩包

wget http://www.nsnam.org/release/ns-allinone-3.24.tar.bz2

下载完后解压即可.

tar jxvf ns-allinone-3.24.tar.bz2

编译安装

使用allinone环境的build.py脚本进行编译. 找到类似ns-allinone-3.24的目录, 输入 ./build.py.

使用waf进行配置

使用waf进行配置和编译ns-3工程, 因为工程一旦已经编译过, 就不能再使用build.py脚本 了, 这时如果读者想改变原有ns-3的配置, 就需要使用交互式的waf命令, 进行重新配置和编译. 如果使用make来编译ns-3这样的庞大工程是一件痛苦的事, waf是一个基于Python语言的开源编译系统, 使用它将会轻松不少.

进入ns-3.24目录, 在该目录下可看到waf可执行文件. 使用waf重新配置和编译ns-3. 首先清除先前配置编译:

./waf clean

重新配置ns-3, 优化编译包括例子和测试(因为默认情况下例子和测试是不编译的), 然后系统会重新配置.

./waf -d optimized --enable-examples --enable-tests configure

如果此时说 pyviz visualizer not enable, 则把配置命令改成:

python ./waf -d debug --enable-examples --enable-tests configure --with-pybindgen=../pybindgen-0.17.0.post41+ngd10fa60/

编译ns-3:

./waf

测试

测试ns-3发行版是否编译正确:

./test.y -c core

验证ns-3是否正常安装:

# 重新配置, 使得可显示日志
./waf -d debug --enable-examples --enable-tests configure
./waf
sudo ./waf --run scratch-simulator

目录结构

waf是基于Python开发的编译工具, ns-3系统本身和将要写的仿真代码都由waf负责编译运行.

scratch目录一般存放用户脚本文件, 也可以把要运行的例子拷贝到此目录下, 该目录是ns-3默认的脚本存放目录, 使用waf编译运行脚本文件时, 可以不加目录scratch, 如果脚本文件在其他目录下需要在文件名前加入目录.

examples是ns-3提供的关于如何使用ns-3的例子, 包含许多模块的使用, 如能量, 路由, 无线网络等, 对初学者有很大的帮助, 其中, tutorial目录下的例子适合入门者学习.

doc是帮助文档.

build目录是ns-3编译目录.

src是ns-3源代码目录, 里面的文件基本和ns-3模块相对应. 打开其中一个模块目录, 包含几个子文件. 其中, wscript文件结构是固定的, 用来注册模块中包含的源代码和使用其他模块情况; 模块代码的.cc和.h文件包含在model目录下; helper目录存放的模块对应helper类代码的源文件; test目录包含的是模块设计者编写的模块测试代码; examples目录存放的则是应用该模块的示例代码; doc是帮助文档; bindings目录是模块用来绑定Python语言的.

ns-3模块

core: ns-3的内核模块, 实现了ns-3的基本机制, 如智能指针, 属性, 回调, 随机变量, 日志, 追踪, 事件调度等内容.

network: 网络数据分组(packet)的模块, 一般仿真都会使用.

Internet: 实现了关于TCP/IPv4和IPv6的相关协议簇.

...

ns-3模块基本流程

  1. 选择或开发相应模块
  2. 编写网络仿真脚本(C++或Python): 生成节点, 安装网络设备, 安装协议栈, 安装应用层协议, 其他配置, 启动仿真.
  3. 仿真结果分析
  4. 依据仿真结果调整网络配置参数或修改源代码

代码简单介绍

头文件

为了帮助高层的用户脚本处理大量系统中的include文件, 会把所有的文件根据模块功能进行大致的分类, 提供了按大致功能分类的一组include文件, 在使用时只需选择包含几个头文件即可. 如:

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

在编译过程中, 每一个ns-3的include文件被放在build目录下一个叫做ns3的目录中, 这样做可以避免include文件名的冲突.

命名空间

using namespace ns3;

C++用using来把ns-3命名空间引入到当前(全局的)声明域中, 使用这个声明, 可以在用ns-3的代码时不必打上ns3::作用域操作符. 这把所有与ns-3相关的声明, 集中在一个与全局命名空间相区别的命名空间中, 但是如果使用标准C++的内容就需要加上std::前缀了.

日志

日志要定义之后才能使用, 日志定义很简单:

NS_LOG_COMPONENT_DEFINE("unique_string");

在自己写的代码中, 使用上面定义的日志名字来启动日志:

LogComponentEnable("unique_string", LOG_LEVEL_INFO);

main()

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

这两行代码将"UdpEcho"应用程序的客户端和服务端的日志级别设为"INFO", 当仿真产生数据分组发送和接收时, 对应的应用就会输出相应的日志消息到相关的日志模块.

生成网络节点

NodeContainer nodes;
nodes.Create(2);

物理连接计算机

现实中连接两台计算机需要使用网卡和网线, ns-3中将对应的物理实体抽象为网络设备和信道2个概念, 使用下面的语句实现网络节点物理连接:

PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
NetDeviceContainer devices;
devices = pointToPoint.Install (nodes);

几乎所有的模块都有相应的一个或若干个Helper类, 负责把网络设备连接到节点、信道, 配置IP地址等普遍的任务, ns-3把这些工作抽象出来, 便于程序开发者使用.

PointToPointHelper类负责设置网络设备和信道属性, 并通过Install方法把设备安装到节点中. 信道和网络设备是对应的, 比如以太网设备和无线信道就不能一起使用.

第一行初始化了一个PointToPointHelper的对象pointToPoint, 然后设置数据速率和传输延迟值. 然后完成设备和信道的配置, 首先声明一个设备容器, 再使用Install()完成主要工作.

对于在NodeContainer对象中的每一个节点(对于一个点到点链路必须明确有2个节点), 1个PointToPointNetDevice被创建和保存在设备容器内, 1个PointToPointChannel对象被创建, 2个PointToPointNetDevices与之连接.

调用Install(nodes)后, 会有2个节点, 每一个节点安装了点到点网络设备, 在它们之间是一个点到点信道. 2个设备会被配置在一个有2ms传输延迟的信道上以5Mbit/s的速率传输数据.

为计算机安装协议栈

InternetStackHelper stack;
stack.Install (nodes);
Ipv4AddressHelper address;
address.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer interfaces = address.Assign (devices);

InternetStackHelper会为每一个节点容器中的节点安装一个网络协议栈, 主要是IP层.

地址从10.1.1.0开始, 以子网掩码为255.255.255.0分配地址.

Ipv4Interface对象将一个IP地址同一个设备关联起来.

现在有一个安装了协议栈, 配置了IP地址类的点到点的网络.

安装应用层

UdpEchoServerHelper echoServer (9);
ApplicationContainer serverApps = echoServer.Install (nodes.Get (1));

首先声明一个UdpEchoServerHelper对象, 该对象用来创建真正的应用, 端口号为9. echoServer.Install()方法初始化回显服务器应用, 在索引号为1的节点上安装一个UdpEchoServerApplication.

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

使echoServer应用在1s时开始产生数据通信, 在10s时停止.

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));

echo客户端需要多设置几个属性. UdpEchoClientHelper的构造函数有两个参数, 分别是RemoteAddress和RemotePort, 在这边, RemoteAddress即为服务器的地址, 服务器是索引为1的节点, RemotePort为9.

MaxPackets: 模拟期间能发送的最大数据包个数.

Interval: 两个数据包的相隔时间.

PacketSize: 数据包大小.

本例中, 让客户端发送一个1024byte的数据包.

启动模拟器

Simulator::Run ();
Simulator::Destroy ();

运行

first.cc 放到 scratch 目录, 执行命令 ./waf --run scratch/first.

0.png

Figure 1: first.cc运行结果

Comments

使用 Disqus 评论
comments powered by Disqus