版本 ns3.31
OS Ubuntu 18.04
ns-3是什么
是一个网络仿真工具,并不是ns-2的扩展而是一个全新的项目。
ns-3官方文档给出了详尽的下载、安装方案。完整的主目录如下:
- waf是基于Python开发的编译工具,从ns3.36开始替换为cmake
- scratch存放脚本文件(C++),也就是要运行的仿真过程。waf会自动到这里找脚本文件。
- build是编译ns-3完成后得到的目录,包含用到的共享库和头文件。
- src是模块源代码目录,每个模块占据一个目录,且都有如下结构:
- binding是模块用于绑定Python语言的;
- model是模块主代码;
- wscript是waf编译该模块的根据。
ns-3默认带有下面的模块:
core | ns-3的基本机制,所有的ns-3自带模块都依赖于此模块运行。 |
---|---|
network | 网络数据packet模块 |
Internet | 实现网络协议族 |
application | 几种常用的应用层协议 |
mobility | 移动设备仿真模型 |
topology-read | 读取制定轨迹文件数据,按照指定格式生成相应的网络拓扑 |
energy | 模仿移动设备的能量管理 |
status | 仿真数据收集、统计 |
tools | 统计工具 |
visualizer | 可视化界面工具PyViz |
netanim | 动画演示工具NetAnim |
propagation | 传播模型 |
flow-monitor | 流量监控模块 |
除此之外,还有一些经典的网络模型:
point-to-point | 点对点通信网络 |
---|---|
csma | IEEE 802.3以太网,包括MAC、物理层和媒体信道 |
mesh | IEEE802.11s的无线mesh网络 |
WI-FI | IEEE802.11a/b/g的无线网络,可以是由基础设施的也可以是ad hoc网络 |
wimax | IEEE802.16的无线城域网络 |
LTE | 3GPP主导的通用移动通信系统技术的长期演进 |
UAN | 水声通信网络,方针水下网络场景,实现了信道、物理层和MAC |
ns-3仿真脚本示例
通过下面这个示例,了解如何使用ns-3进行想要的仿真过程。
examples/tutorial/first.cc
//这些头文件就是引用 build/ns3/ 下的
#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"
// Default Network Topology
//
// 10.1.1.0
// n0 -------------- n1
// point-to-point
//
using namespace ns3;
// 用字符串定义日志组件(Component)
NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");
int
main (int argc, char *argv[])
{
CommandLine cmd (__FILE__);
cmd.Parse (argc, argv);
Time::SetResolution (Time::NS);
LogComponentEnable ("UdpEchoClientApplication", LOG_LEVEL_INFO);
LogComponentEnable ("UdpEchoServerApplication", LOG_LEVEL_INFO);
NodeContainer nodes;
// 创建2个节点,可以视为2台“计算机”在网络中代表的点
nodes.Create (2);
// Helper类的作用是:把模块常见的工作抽象出来方便使用
PointToPointHelper pointToPoint;
// 一次P2P网络连接实际上就是“设备-信道-设备”的模型,如下设置:
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
NetDeviceContainer devices;
// 按照上面的设置,配置设备和信道
devices = pointToPoint.Install (nodes);
// 主要配置的是IP层
InternetStackHelper stack;
stack.Install (nodes);
Ipv4AddressHelper address;
address.SetBase ("10.1.1.0", "255.255.255.0");
// 把选好的ip地址分配到设备
Ipv4InterfaceContainer interfaces = address.Assign (devices);
// 安装应用程序并设置端口号
UdpEchoServerHelper echoServer (9);
ApplicationContainer serverApps = echoServer.Install (nodes.Get (1));
// 使echo服务在1s开始并在10s时结束
serverApps.Start (Seconds (1.0));
serverApps.Stop (Seconds (10.0));
UdpEchoClientHelper echoClient (interfaces.GetAddress (1), 9);
// MaxPacket属性告诉客户端所允许模拟器件发送的最大数据packet个数
echoClient.SetAttribute ("MaxPackets", UintegerValue (1));
// Interval属性告诉客户端在2个packet之间的时间
echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.0)));
// PacketSize属性告诉客户端每个packet发送多少byte
echoClient.SetAttribute ("PacketSize", UintegerValue (1024));
ApplicationContainer clientApps = echoClient.Install (nodes.Get (0));
clientApps.Start (Seconds (2.0));
clientApps.Stop (Seconds (10.0));
// 实际上就是启动 serverApps和clientApps
Simulator::Run ();
Simulator::Destroy ();
return 0;
}
上面的示例代码可以分解为以下结构:
- 头文件、命名空间
- NS_LOG_COMPONENT_DEFINE("XXX"); 允许在该脚本中使用LOG系统中的宏定义
- main()开头的准备工作 命令行、时间、打印信息等等
- 创建网络拓扑 附录1
- 安装TCP/IP协议族 附录2
- 安装应用程序 附录3
- 数据生成 本示例中未涉及
- 启动与结束 Run()和Destory()
附录1
网络拓扑=节点+信道
Node=节点
Channel=物理层信道协议
NetDevice=链路层信道协议,且NetDevice安装在Node里。
- NetDevice和Channel基本上是一一对应的;
- Node和NetDevice是一对多的。
就代码来看,创建网络拓扑经历三个步骤:
- NodeContainer创建节点。
- PointToPointHelper配置信道属性。
- 创建信道连接节点。调用PointToPointHelper::Install()创建两个PPP-NetDevice和一个PPP-Channel。
需要指出,助手类PointToPointHelper实际上完成了很多操作,如
- node、channel、net_device之间关联关系的建立
- net_device分配MAC地址
- 为channel设置队列模型
- ……
附录2
ns-3中的TCP/IP协议族主要包括传输层的TCP/UDP、网络层IP、ICMP等。
安装协议栈的助手类是InternetStackHelper,在安装完协议栈后还需要为net_device分配IP地址。代码中可以看到,设置IP地址用的是Ipv4AddressHelper,而将IP分配到net_device得到Ipv4InterfaceContainer。
Ipv4Interface的作用如下图所示,简单地说就是暴露给NetDevice,帮它保存IP地址。
Ipv4是网络层的类,IpL4Protocol是传输层TCP/UDP的基类。至此,节点已经在物理层到传输层都准备好。
附录3
应用层对应的C++类是Application,不同的Application对应不同的分组收发行为。示例代码中使用的UdpEcho应用比较简单,代码也很直观。
可能的疑惑是,为什么UdpEcho建立UDP连接不需要调用Socket的相关接口?
答案是,这些调用被封装在2个助手类UdpEchoServerHelper(bind、connect)和UdpEchoClientHelper(bind、recvfrom、sendto)里。