计算机网络原理 实验2 《NS3 路由模拟实验》
一、实验目的
1、了解NS3网络模拟器的基本操作; 2、学习采用距离矢量算法(Distance Vector Algorithm)的动态路由。
二、实验内容
本实验的主要实验过程分别是:搭建NS3平台的坏境和学习采用距离矢量算法(Distance Vector Algorithm)的动态路由。此外,在实验过程中需要自学linux操作系统的安装和使用(可在虚拟机中安装linux,本实验指导书使用的VMware虚拟机中的ubuntu操作系统),熟悉linux下的软件开发过程(如vi编辑器,gcc编译器),熟悉C++、Python编程语言。
三、实验方法
1.利用提供的ns3安装包在Linux虚拟机(Ubuntu 18.04)安装ns3的运行环境,并安装相关依赖的环境如gcc编译器、python解释器环境等。 2、利用ns3模拟路由,写好距离矢量算法模拟程序并将其编译、形成ns3需要的xml文件,在ns3的图形化界面做好设定,使用该xml文件进行模拟并保存实验结果。
四、实验步骤
1、NS3环境的安装
安装环境:VMWare WorkStation Pro 16,Linux发行版(Ubuntu 18.04)
(1) 检查源,最好更换为国内镜像源如阿里源、华为源等,这里因为之前下载软件的时候换过源,因此无需换源。
(2) 安装依赖库,包括gcc编译器、python 3解释器环境及其相应的依赖库等。通过依次执行如下命令安装。
sudo apt-get install gcc g++ python python3
sudo apt-get install gcc g++ python python3 python3-dev
sudo apt-get install python3-setuptools git mercurial
sudo apt-get install qt5-default mercurial
sudo apt-get install gir1.2-goocanvas-2.0 python-gi python-gi-cairo python-pygraphviz python3-gi python3-gi-cairo python3-pygraphviz gir1.2-gtk-3.0 ipython ipython3
sudo apt-get install openmpi-bin openmpi-common openmpi-doc libopenmpi-dev
sudo apt-get install autoconf cvs bzr unrar
sudo apt-get install gdb valgrind
sudo apt-get install uncrustify
sudo apt-get install doxygen graphviz imagemagick
sudo apt-get install texlive texlive-extra-utils texlive-latex-extra texlive-font-utils dvipng latexmk
sudo apt-get install python3-sphinx dia
sudo apt-get install gsl-bin libgsl-dev libgsl23 libgslcblas0
sudo apt-get install tcpdump
sudo apt-get install sqlite sqlite3 libsqlite3-dev
sudo apt-get install libxml2 libxml2-dev
sudo apt-get install cmake libc6-dev libc6-dev-i386 libclang-6.0-dev llvm-6.0-dev automake
sudo apt-get install libgtk2.0-0 libgtk2.0-dev
sudo apt-get install vtun lxc uml-utilities
sudo apt-get install libboost-signals-dev libboost-filesystem-dev
(3) 安装NS3基础模块。使用命令tar -xjvf ns-allinone-3.27.tar.bz2 解压还原ns-allinone-3.27.tar.bz2文件。可以看到解压完毕后目录内容如下。
解压后通过终端进入ns-allinone-3.27目录使用sudo ./build.py 命令执行编译。 这里编译失败,一堆红字。执行以下命令解决问题:
cd ns-3.27
sudo ./waf clean
sudo ./waf -d debug --enable-example --enable-tests configure
sudo ./waf
之后问题得到解决,如下。
(3) 编译NetAnim可视化部分。返回目录ns-allinone-3.27,进入目录netanim-3.108,执行下列命令进行编译:
sudo make clean
sudo qmake NetAnim.pro
sudo make
编译结束后如果目录netanim-3.108下有NetAnim的话,执行sudo ./NetAnim 可以打开如下仿真界面,则安装全部完成。
2、编程实现模拟
本次实验主要是观察链路状态发生变化时,使用动态路由算法进行实系统调整的效果。实验的结构如图1所示,结构包含csma/cd和点对点的传输方式。节点n1会使用udp将数据传送到n6,在时间为1s时, n1到n6之间最近的传输方式是n1-n6通过点对点方式传播。在时间2s时n1-n6之间发生问题,所以数据无法从n1到n4之间的链路传送,数据传输路径转换为n1-n2-n5-n6。在4s时,重新使n1-n6连接有效。6s时n6-n1发生问题,但是在n1的视角,还不知道链路发生问题,数据传输将切换成路径n1-n2-n5-n6。8s时n1-n6恢复。10s时,停止数据流的发送。11s时重新开始数据的发送,继续重复数次使得n1-n6链路失效、有效操作,直到16s时,模拟停止。
使用GVim编辑器编写模拟程序的C++代码。
编写完毕后执行编译并运行。
sudo ./waf
sudo ./waf --run scratch/ns3routing
执行完毕结果如下。
最后使用netanim程序运行生成的ns3routing.xml文件,观察结果。
五、实验结果
(1) 初始打开ns3routing.xml文件,调整节点显示的大小。
(2) 初始时候,数据通过n1-n6路径传输,如下图。
(3) 在2.0s时,n1到n6链路发生问题,通过动态路由算法,数据将通过n1-n2-n5-n6路径传输,如下图。
(4) 在3.0s时,n1到n6链路的问题得到解决,所以4.0s时数据的传输路径从n1-n2-n5-n6转换为n1-n6. 如下图。
(5) 之后,随着链路状态的变化,数据传播路径也会根据路由算法做出相应调整。
六、实验结论
使用距离矢量路由算法时,每个路由器维护一个距离矢量(通常是以延时是作变量的)表,然后通过相邻路由器之间的距离矢量通告进行距离矢量表的更新。每个距离矢量表项包括两部分:到达目的结点的最佳输出线路和到达目的结点所需时间或距离,通信子网中的其它每个路由器在表中占据一个表项,并作为该表项的索引。每隔一段时间,路由器会向所有邻居结点发送它到每个目的结点的距离表,同时它也接收每个邻居结点发来的距离表。这样以此类推,经过一段时间后便可将网络中各路由器所获得的距离矢量信息在各路由器上统一起来,这样各路由器只需要查看这个距离矢量表就可以为不同来源分组找到一条最佳的路由。
七、实验小结
本次实验主要是体验了动态路由算法中的距离矢量算法的模拟运用,通过ns3的仿真模拟手段模拟出动态路由算法在遇到链路状态改变时会做出的一些动作如改变路由路径等等,使得自己进一步熟悉了动态路由的特点,同时也进一步熟悉了动态路由算法相比静态路由算法的优势,熟悉了Linux发行版Ubuntu的使用。
路由的模式主要分为「静态路由」和「动态路由」。静态路由协议是由网络管理员手动输入配置的,适用于小型的不太复杂的网络环境中,或者有特定需求的网络场景中。而动态路由协议是现代计算机网络中最为常用的一种方式。动态路由算法能够根据网络拓扑结构去适应流量的变化,其中最流行的两种动态路由算法是距离矢量路由算法和链路状态路由算法。
距离矢量路由算法(Distance Vector Routing),它是网络上最早使用的动态路由算法,也称为Bellman-Ford或者Ford-Fulkerson算法。基于这类算法实现的协议有:RIP、BGP等。距离矢量路由算法的优点很明显:非常简单清晰,且任何加入到网络中的新节点都能很快的与其它节点建立起联系获得补充信息。缺点是需要较大存储、CPU、网络开销,对资源的要求会越来越高;并且收敛时间长,即无穷收敛问题,进而造成路由环路问题。
链路状态路由算法(Link State Routing ),基于Dijkstra算法,它是以图论作为理论基础,用图来表示网络拓扑结构,用图论中的最短路径算法来计算网络间的最佳路由。基于这类算法实现的协议有:OSPF 等。链路状态路由算法 不会像距离矢量路由算法那样发送整个路由表,链路状态路由协议只会广播更新的或者改变了的网络拓扑,这样传播的信息量会少很多,同时对带宽和CPU资源也是一种节省;并且它具有很好的扩展能力,也具有更快的收敛速度,能够快速的适应网络变化,且由于一个路由器的链路状态只涉及与其相邻的路由器的联通状态,因而与整个互联网的规模并无直接关系,因此链路状态路由算法可以用于大型的或者路由信息变化剧烈的互联网环境。
八、附录
ns3routing仿真的C++代码:
#include <iostream>
#include <fstream>
#include <string>
#include <cassert>
#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/csma-module.h"
#include "ns3/internet-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/applications-module.h"
#include "ns3/ipv4-global-routing-helper.h"
#include "ns3/netanim-module.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE ("DynamicGlobalRoutingExample");
int main (int argc, char *argv[] ) {
Config::SetDefault ("ns3::Ipv4GlobalRouting::RespondToInterfaceEvents",
BooleanValue (true));
CommandLine cmd;
cmd.Parse (argc, argv);
NS_LOG_INFO ("Create nodes.");
NodeContainer c;
c.Create (7);
NodeContainer n0n2 = NodeContainer (c.Get (0), c.Get (2));
NodeContainer n1n2 = NodeContainer (c.Get (1), c.Get (2));
NodeContainer n5n6 = NodeContainer (c.Get (5), c.Get (6));
NodeContainer n1n6 = NodeContainer (c.Get (1), c.Get (6));
NodeContainer n2345 = NodeContainer (c.Get (2), c.Get (3), c.Get (4), c.Get (5));
InternetStackHelper internet;
internet.Install (c);
NS_LOG_INFO ("Create channels.");
PointToPointHelper p2p;
p2p.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
p2p.SetChannelAttribute ("Delay", StringValue ("2ms"));
NetDeviceContainer d0d2 = p2p.Install (n0n2);
NetDeviceContainer d1d6 = p2p.Install (n1n6);
NetDeviceContainer d1d2 = p2p.Install (n1n2);
p2p.SetDeviceAttribute ("DataRate", StringValue ("1500kbps"));
p2p.SetChannelAttribute ("Delay", StringValue ("10ms"));
NetDeviceContainer d5d6 = p2p.Install (n5n6);
CsmaHelper csma;
csma.SetChannelAttribute ("DataRate", StringValue ("5Mbps"));
csma.SetChannelAttribute ("Delay", StringValue ("2ms"));
NetDeviceContainer d2345 = csma.Install (n2345);
NS_LOG_INFO ("Assign IP Addresses.");
Ipv4AddressHelper ipv4;
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
ipv4.Assign (d0d2);
ipv4.SetBase ("10.1.2.0", "255.255.255.0");
ipv4.Assign (d1d2);
ipv4.SetBase ("10.1.3.0", "255.255.255.0");
Ipv4InterfaceContainer i5i6 = ipv4.Assign (d5d6);
ipv4.SetBase ("10.250.1.0", "255.255.255.0");
ipv4.Assign (d2345);
ipv4.SetBase ("172.16.1.0", "255.255.255.0");
Ipv4InterfaceContainer i1i6 = ipv4.Assign (d1d6);
Ipv4GlobalRoutingHelper::PopulateRoutingTables ();
NS_LOG_INFO ("Create Applications.");
uint16_t port = 9;
OnOffHelper onoff ("ns3::UdpSocketFactory",
InetSocketAddress (i5i6.GetAddress (1), port));
onoff.SetConstantRate (DataRate ("2kbps"));
onoff.SetAttribute ("PacketSize", UintegerValue (50));
ApplicationContainer apps = onoff.Install (c.Get (1));
apps.Start (Seconds (1.0));
apps.Stop (Seconds (10.0));
OnOffHelper onoff2 ("ns3::UdpSocketFactory",
InetSocketAddress (i1i6.GetAddress (1), port));
onoff2.SetAttribute ("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]"));
onoff2.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0]"));
onoff2.SetAttribute ("DataRate", StringValue ("2kbps"));
onoff2.SetAttribute ("PacketSize", UintegerValue (50));
ApplicationContainer apps2 = onoff2.Install (c.Get (1));
apps2.Start (Seconds (11.0));
apps2.Stop (Seconds (16.0));
PacketSinkHelper sink ("ns3::UdpSocketFactory",
Address (InetSocketAddress (Ipv4Address::GetAny (), port)));
apps = sink.Install (c.Get (6));
apps.Start (Seconds (1.0));
apps.Stop (Seconds (10.0));
PacketSinkHelper sink2 ("ns3::UdpSocketFactory",
Address (InetSocketAddress (Ipv4Address::GetAny (), port)));
apps2 = sink2.Install (c.Get (6));
apps2.Start (Seconds (11.0));
apps2.Stop (Seconds (16.0));
AsciiTraceHelper ascii;
Ptr<OutputStreamWrapper> stream = ascii.CreateFileStream ("dynamic-global-routing.tr");
p2p.EnableAsciiAll (stream);
csma.EnableAsciiAll (stream);
internet.EnableAsciiIpv4All (stream);
p2p.EnablePcapAll ("dynamic-global-routing");
csma.EnablePcapAll ("dynamic-global-routing", false);
Ptr<Node> n1 = c.Get (1);
Ptr<Ipv4> ipv41 = n1->GetObject<Ipv4> ();
uint32_t ipv4ifIndex1 = 2;
Simulator::Schedule (Seconds (2),&Ipv4::SetDown,ipv41, ipv4ifIndex1);
Simulator::Schedule (Seconds (4),&Ipv4::SetUp,ipv41, ipv4ifIndex1);
Ptr<Node> n6 = c.Get (6);
Ptr<Ipv4> ipv46 = n6->GetObject<Ipv4> ();
uint32_t ipv4ifIndex6 = 2;
Simulator::Schedule (Seconds (6),&Ipv4::SetDown,ipv46, ipv4ifIndex6);
Simulator::Schedule (Seconds (8),&Ipv4::SetUp,ipv46, ipv4ifIndex6);
Simulator::Schedule (Seconds (12),&Ipv4::SetDown,ipv41, ipv4ifIndex1);
Simulator::Schedule (Seconds (14),&Ipv4::SetUp,ipv41, ipv4ifIndex1);
Ipv4GlobalRoutingHelper g;
Ptr<OutputStreamWrapper> routingStream = Create<OutputStreamWrapper> ("dynamic-global-routing.routes", std::ios::out);
g.PrintRoutingTableAllAt (Seconds (12), routingStream);
AnimationInterface animsd("ns3routing.xml");
animsd.SetConstantPosition(c.Get(0),0,0);
animsd.SetConstantPosition(c.Get(1),0,40);
animsd.SetConstantPosition(c.Get(2),20,20);
animsd.SetConstantPosition(c.Get(3),80,20);
animsd.SetConstantPosition(c.Get(4),40,20);
animsd.SetConstantPosition(c.Get(5),60,20);
animsd.SetConstantPosition(c.Get(6),60,40);
NS_LOG_INFO ("Run Simulation.");
Simulator::Run ();
Simulator::Destroy ();
NS_LOG_INFO ("Done.");
}
|