网络仿真器NS2的配置与应用
这个实验环境配置很麻烦,但是实验内容很简单......
配置环境一上午,实验只要十分钟......
1. 实验要求
安装并运行网络仿真器NS2,了解其功能模块及配套工具的使用,掌握利用NS2进行网络仿真的方法,为进一步的网络系统性能分析设计创造良好的条件。
2. 实验条件
硬件:一台计算机
软件:Ubuntu操作系统、NS2工具包
3. 实验指导
1) NS2仿真流程
采用NS2进行仿真实验之前,必须先掌握本书7.2.1节中的相关内容。一般来说,采用NS2进行仿真大致可分为3个步骤:
●建立Networkmodel:描述整个网络的拓扑、带宽等信息。
●建立traffic model:描述所有的网络流量或错误情况的时间、类型、或呈何种数学分布。
●追踪分析结果:仿真完成后,可调用nam观察整个仿真流程,或是将namfile中的信息抽取出来加以分析。
下面是一些具体的实现语句,其中#后的说明为该语句的相关注释。(根据本人测试运行,最好文件中不要加注释,否则会报错)
a) 建立Networkmodel
●建立ns对象
set ns[new Simulator]
●建立节点
set n0[$ns node]
●建立连接
$ns duplex-link $n0 $n1 <bandwidth><delay><queue_type>
队列(queue)是保持(held)或丢弃(drop)数据包的地方,目前NS2所支持的队列缓冲管理机制有drop-tail(FIFO)队列、RED缓冲管理、公平队列(Fair Queueing,FQ)、随机公平队列(StochasticFair Queueing,SFQ)、DRR(Deficit Round-Robin)和基于类的队列(class-based queuein,CBQ)。
●建立局域网
$ns make-lan <node_list><bandwidth><delay>LLQueue/DropTail MAC/802.3 Channel
若只想建立点对点的网络,则无需建立局域网这个步骤。
b) 建立Trafficmodel
建立连接
根据不同的流量类型,可分为
TCP连接
set tcp[new Agent/TCP] #建立TCP代理,用以产生流量
set tcpslink[new Agent/TCPSink] #建立TCPSink代理,用以接收流量
$ns attach-agent $n0 $tcp #将所建立的tcp配置给节点n0
$ns attach-agent $n1 $tcpsink #将所建立的tcpsink配置给节点n1
$ns connect $tcp $tcpsink #连接
UDP连接
set udp[new Agent/UDP] #建立UDP代理,用以产生流量
set null[new Agent/NULL] #建立NULL代理,用以接收流量
$ns attach-agent $n0 $udp #将所建立的udp配置给节点n0
$ns attach-agent $n1 $null #将所建立的null配置给节点n1
$ns connect $udp $null #连接
●产生流量
对应TCP连接,产生FTP(or Telnet)流量:
set ftp[new Application/FTP]
$ftp attach-agent $udp
●建立排程
$ns at<time><event> #<event>为任何合法的ns/tcl命令
$ns run
c) 追踪分析结果
$ns namtrace-all[open test.nam w]
其中test.nam为记录仿真过程的输出文件,内容包含网络的拓扑(node、link、queues、…),以及所有数据包的信息。用户可以使用该文件中的有关数据包的信息来作一些追踪分析。
2) NS2仿真示例—nam方式
下面给出一个具体的NS2仿真示例,一遍可以更快更清楚地了解网络仿真的实际操作流程。例如,在文本编辑器中写入OTcl脚本。
脚本内容如下:
set ns [new Simulator] #建立一个ns对象
#设定第一条数据流在nam中用蓝色表示,第二条数据流用红色表示,主要是为了便于观察被传送和丢弃的数据包是属于哪个数据流,其中参数1、2为数据流所对应的flowid(流量标识符)
$ns color 1 Blue
$ns color 2 Red
set nf [open out.nam w] #打开跟踪文件out.nam,其中nf为文件句柄
$ns namtrace-all $nf
proc finish {} { #定义结束过程
global ns nf
$ns flush-trace
close $nf #关闭跟踪文件
exec nam out.nam & #调用nam
exit 0
}
set ns0 [$ns node] #建立四个节点:n0、n1、n2、n3
set ns1 [$ns node]
set ns2 [$ns node]
set ns3 [$ns node]
#建立节点间的链路Link、设置带宽1Mbit/s,时延10ms,队列DropTail,即先进先出(FIFO)
$ns duplex-link $ns0 $ns2 1Mb 10ms DropTail
$ns duplex-link $ns1 $ns2 1Mb 10ms DropTail
$ns duplex-link $ns3 $ns2 1Mb 10ms DropTail
#设定节点在拓扑图中的位置,使得整个图看起来布局更为合理
$ns duplex-link-op $ns0 $ns2 orient right-down
$ns duplex-link-op $ns1 $ns2 orient right-up
$ns duplex-link-op $ns2 $ns3 orient right
#设定nam中queue的位置,便于检测节点n2和n3之间链路的队列
$ns duplex-link-op $ns2 $ns3 queuePos 0.5
#为节点n0建立一个UDP代理udp0,用于产生流量,并设定flowid(流量标识符)为1
set udp0 [new Agent/UDP]
$udp0 set class_ 1
$ns attach-agent $ns0 $udp0
#设置udp0产生CBR流量,每隔0.005s发送大小为500B的数据包
set cbr0 [new Application/Traffic/CBR]
$cbr0 set packetSize_ 500
$cbr0 set interval_ 0.005
$cbr0 attach-agent $udp0
#为节点n1建立一个UDP代理udp1,用于产生流量,并设定flowid(流量标识符)为2
set udp1 [new Agent/UDP]
$udp1 set class_ 2
$ns attach-agent $ns1 $udp1
#设置udp1产生CBR(Constant BitRate,固定比特率)流量,每隔0.005s发送大小为500B的数据包
set cbr1 [new Application/Traffic/CBR]
$cbr1 set packetSize_ 500
$cbr1 set interval_ 0.005
$cbr1 attach-agent $udp1
#为节点n3建立一个Null代理null0,用以接收流量
set null0 [new Agent/Null]
$ns attach-agent $ns3 $null0
#分别连接流量产生代理udp0、udp1和流量接收代理null0
$ns connect $udp0 $null0
$ns connect $udp1 $null0
#排程,设置cbr0在仿真0.5s后开始传输数据,4.5s后停止传输数据;设置cbr1在仿真1.0s后开始传送数据,4.0s后停止传送数据
$ns at 0.5 "$cbr0 start"
$ns at 1.0 "$cbr1 start"
$ns at 4.0 "$cbr1 stop"
$ns at 4.5 "$cbr0 stop"
#仿真5.0s后,调用结束过程
$ns at 5.0 "finish"
#执行仿真
$ns run
保存脚本文件为example1.tcl,运行命令:ns example1.tcl
运行结果如下图所示:
点击窗口上的“PLAY”按钮,将动态显示仿真过程:
仿真0.5s后,结点n0开始向结点n2传送数据包,该数据流以蓝色动态显示,此时可以拖动窗口右上方的“Step”滑尺以减缓nam的速度:
仿真1.0s后,节点n1开始向节点n2传送数据包,以红色动态显示:
经过一段时间后,可观察到链路队列上的数据包如何被丢弃,因为脚本采用的是FIFO队列机制,所以两种颜色的数据包并没有被“公平”地丢弃,所丢弃的都是蓝色的数据包,这可以通过修改链路配置的队列机制来提高公平性。
3) NS2仿真示例—Xgraph方式
由上面的仿真示例可以看出,采用nam方式显示的是整个仿真的动态过程,如数据包的传输、链路的断开、丢包等;若想显示仿真过程中的内部状态,如传输速率、各种峰值等,可采用NS2提供的另外一种方式—Xgraph方式。
下面给出另一个采用Xgraph显示方式的NS2仿真示例。其网络拓扑结构如下图所示,链路Link都是带宽1Mbit/s、时延100ms、采用FIFO队列,udp连接从节点n0、n1、n2到节点n4,对应的OTcl脚本如后面所示。
在文本编辑器中写入OTcl脚本,脚本内容如下:
#建立一个ns对象
set ns [new Simulator]
#打开输出文件
set f0 [open out0.tr w]
set f1 [open out1.tr w]
set f2 [open out2.tr w]
#for循环,建立n0~n4共5个节点
for { set i 0 } { $i<5 } {incr i}{
setn$i [$ns node]
}
#建立链路Link
$ns duplex-link $n0 $n3 1Mb 100msDropTail
$ns duplex-link $n1 $n3 1Mb 100msDropTail
$ns duplex-link $n2 $n3 1Mb 100msDropTail
$ns duplex-link $n3 $n4 1Mb 100msDropTail
#定义结束过程
proc finish {} {
globalf0 f1 f2
close$f0
close$f1
close$f2
#调用Xgraph显示仿真结果
execxgraph out0.tr out1.tr out2.tr -geometry 800x400 &
exit0
}
#定义过程,为节点node和流量接收代理sink建立UDP连接,产生Expoo流量,并设置流量的size(packetSize,数据包大小)、burst(burst_time,突发事件)、idle(idle_time,空闲时间)和rate(burst peakrate,峰率)等
proc attach-expoo-traffic { node sinksize burst idle rate } {
set ns [Simulator instance]
#为节点node建立一个UDP代理source,用于产生流量
set source [new Agent/UDP]
$ns attach-agent $node $source
#产生Expoo流量
set traffic [newApplication/Traffic/Exponential]
#设置Expoo流量的packetSize(数据包大小)、burst_time(突发时间)、idle_time(空闲时间)和rate(burst peakrate,峰率)等
$traffic set packetSize_ $size
$traffic set burst_time_ $burst
$traffic set idle_time_ $idle
$traffic set rate_ $rate
$traffic attach-agent $source
#连接流量产生代理source和流量接收代理sink
$ns connect $source $sink
return $traffic
}
#定义记录过程,周期性地记录3个流量接收代理sink0、sink1、sink2所接受到的数据流带宽,并分别写入3个文件f0、f1、f2中
proc record {} {
globalsink0 sink1 sink2 f0 f1 f2
setns [Simulator instance]
#定义过程再次被调用的时间,即调用周期
settime 0.5
#获取代理已接收的字节数,即变量bytes的值
setbw0 [$sink0 set bytes_]
setbw1 [$sink1 set bytes_]
setbw2 [$sink2 set bytes_]
#获取当前时间
setnow [$ns now]
#计算带宽(单位:Mbit/s),将结果写入文件
puts$f0 "$now [expr $bw0/$time*8/1000000]"
puts$f1 "$now [expr $bw1/$time*8/1000000]"
puts$f2 "$now [expr $bw2/$time*8/1000000]"
#重置接收代理中的变量bytes的值
$sink0set bytes_ 0
$sink1set bytes_ 0
$sink2set bytes_ 0
#重新排程
$nsat [expr $now+$time] "record"
}
#为节点n4建立3个流量接收代理sink0、sink1、sink2
set sink0 [new Agent/LossMonitor]
set sink1 [new Agent/LossMonitor]
set sink2 [new Agent/LossMonitor]
$ns attach-agent $n4 $sink0
$ns attach-agent $n4 $sink1
$ns attach-agent $n4 $sink2
#调用attach-expoo-traffic过程,分别建立节点n0、n1、n2与流量接收代理sink0、sink1、sink2的UDP连接,产生并设置Expoo流量
set source0 [attach-expoo-traffic $n0$sink0 200 2s 1s 100k]
set source1 [attach-expoo-traffic $n1$sink1 200 2s 1s 200k]
set source2 [attach-expoo-traffic $n2$sink2 200 2s 1s 300k]
#排程
$ns at 0.0 "record"
$ns at 10.0 "$source0 start"
$ns at 10.0 "$source1 start"
$ns at 10.0 "$source2 start"
$ns at 50.0 "$source0 stop"
$ns at 50.0 "$source1 stop"
$ns at 50.0 "$source2 stop"
$ns at 60.0 "finish"
#执行仿真
$ns run
保存文件为example2.tcl,运行命令:nsexample2.tcl
运行结果如下所示:
Xgraph显示仿真过程中的内部状态,从图中可以看出,三条数据流的峰值依次为0.1Mbit/s、0.2Mbit/s和0.3Mbit/s
4. 实验总结
在nam辅助分析工具中发现ftp1在零秒开始启动,ftp2在第三秒时刻开始启动,都在第十秒停止,这符合设计目标。在发送端收到新一轮的确认包时发送包的数量也加一,传输的过程中队列的长度超过一定值时开始丢包。这由设定的队列最小的门限值和队列最大门限值决定。当队列长度小于最小门限值时一定不会丢包,只有超过最小门限值时才会发生丢包,且超过的越多丢弃的概率越大。当队列长度超过最大门限值时队列一定丢包。丢包后的确认包不再让发送窗口增大,反而从零开始增加。传送过程中,丢包不再决定于队列的长度了,而是根据平均队列长度随机丢弃,因为采用的是RED丢包机制。