资源描述
网络仿真和模拟课程设计实验报告
学院: 计算机学院
专业: 网络工程
组员(学号):
指导老师:
完成时间 2016年6月30日
2
目录
网络仿真和模拟课程设计实验报告 1
目录 2
一、NS2模拟环境搭建 1
1.1安装cygwin 1
1.2安装NS2 6
二、不同版本的TCP协议仿真模拟 9
2.1实验目的 9
2.1实验步骤 9
2.2实验过程及结果比较 9
三、添加Ping协议 16
3.1实验目的 16
3.2 实验步骤 16
四、添加Application和Agent协议 21
4.1实验目的 21
4.2实验步骤 21
附录A 27
附录B 30
附录C 34
附录D 44
附录E 45
附录F 48
网络仿真和模拟课程设计手册
一、NS2模拟环境搭建
在Windows操作系统下安装比较繁琐,需要根据NS不同版本,下载相关补丁进行修正。
下面介绍在Windows下安装NS-allinone过程。
1.1安装cygwin
1) 点击安装setup.exe文件,如图1所示:
图1 执行setup.exe文件
2) 请点击“下一步”按钮,如图2所示:
图2 安装步骤2
3) 选择“Install from Internet”单选按钮,如图3所示:
图3 安装步骤3
4) 点击“下一步”按钮,如图4所示:
图4 安装步骤4
5) 点击“下一步”按钮,如图5所示:
图5 安装步骤5
6) 点击“下一步”按钮,如图6所示:
图6 安装步骤6
7) 点击“下一步”按钮,如图7所示:
图7 安装步骤7
8) 点击“下一步”按钮,如图8所示:
图8 安装步骤8
9) 选择“Curr”,点击“View”按钮,使右方出现“full”,然后把最下角的隐藏过期包组件那个勾去掉,如图9所示:
图9 安装步骤9
10) 由于是初次接触该软件,在不清楚各个包作用的情况下将所有的包都安装,然后点击“下一步”按钮,如图10所示:
图10 安装步骤10
11) 安装结束后,点击“完成”按钮,如图11所示:
图11 安装步骤11
1.2安装NS2
1) 解压缩并改变路径到ns-allinone-2.35,如图12所示:
图12 切换到NS目录
2) 修改ls.h错误代码行(进入C:cygwinhome/Administartor/ns-allinone -2.35/ns-2.35/linkstate/ls.h 第137行):
3) 安装指令,进行编译安装,如图13所示:
图13 进行编译安装
4) 重新编译完后,如图14所示:
图14 编译结果
5) 设置环境变量:
6) 测试NS2是否安装成功,如图15所示:
图15 进入图形化接口窗口
7) 在跳出的对话框中,输入nam,系统跳出一个图形界面,如图16所示:
图16 Nam界面
8) 在窗口中输入gnuplot,结果如图17所示,则NS2安装成功:
图17 gnuplot界面
二、不同版本的TCP协议仿真模拟
2.1实验目的
通过本实验了解如何利用OTcl脚本编写NS仿真案例。
2.1实验步骤
l NS2下不同版本的TCP协议的OTcl脚本编写。
l 在winx-server模式下键入命令:ns <文件名.tcl>运行ns文件。
l 对实验结果进行分析比较。
2.2实验过程及结果比较
n Tahoe执行方法,如下所示:
1. ns lab11.tcl Tahoe (lab11.tcl文件代码参考附录A ,TCPV1)
2. gnuplot 进入gnuplot>提示符
会在目录下生成gif 图片,见下面图片比较。
n Reno执行方法,如下所示:
n NewReno执行方法,如下所示:(lab12.tcl)
n SACK执行方法,如下所示:
n Vegas执行方法,如下所示:(lab13_1.tcl)
gnuplot> set title “Vegas”
gnuplot> set xlabel “time”
gnuplot> set ylabel “cwnd”
gnuplot> set terminal gif
gnuplot> set output “cwnd-Vegas”
gnuplot>plot “cwnd0.tr” with linespoints lt 1, “cwnd1.tr” with linespoints lt 2
n Vegas和 Re执行方法,如下所示:(lab13_2.tcl)
1 . ns lab13_2.tcl
2.
gnuplot> set title “Vegas vs Reno”
gnuplot> set xlabel “time”
gnuplot> set ylabel “cwnd”
gnuplot> set terminal gif
gnuplot> set output “cwnd-Vegas-Reno”
gnuplot>plot “cwnd-vegas.tr” with linespoints lt 1, “cwnd-reno.tr” with linespoints lt
n 结果比较
图16 Tahoe的cwnd变化图
图17 Reno的cwnd变化图
图18 TCP NewReno
图19 SACK
图20 Vegas图形
图21 Vegas与Reno的cwnd变化图
n 结果分析
从Tahoe的cwnd变化图(图16)中我们可以看出,TCP的Congestion Window值会呈现周期性的重复变化。开始时,先由Slow-start开始,cwnd超过Ssthresh时进入Congestion Avoidance阶段。由于传送到网络上的封包不断地增加,当超出允许能传送到网络上的个数时,路由器开始使用Drop-tail将封包丢掉。当有封包遗失时,Tahoe这个TCP版本会将ssthresh设为发现到封包遗失时的Window值的1/2,接着将Window的值设为1。在Tahoe这个例子中,由于只要有封包遗失,Cwnd的值就会被重置为1(小于Ssthresh),因此每次封包遗失,Tahoe都重新由slow-start开始。
从Reno的cwnd变化图(图17)中看到,当检测到封包遗失时,ssthresh和cwnd的值会被设为先前cwnd值的1/2。因此在重送遗失的封包后,TCP Reno会由Congestion Avoidance开始。由于结束Fast recovery后,Reno的cwnd由先前cwnd值的1/2开始增加,所以得到的平均吞吐量较Tahoe为佳。从该图中我们还可以看到,当TCP的传送端观察到端点到端点的路径并没有拥塞的情况时(没有检测到封包遗失),会持续地以累加的方式增加传送速率。但是当检测到路径拥塞的情况时,则以倍数的方式减少传送速率。基于上述原因,TCP的拥塞控制算法又常被称为累加递增-倍数递减的算法。
从TCP NewReno的cwnd变化图(图18)中我们可以看到,NewReno在收到Partial ACK时,并不会立刻结束Fast-recovery,相反,NewReno的传送端会持续地重送Partial ACK之后的封包,直到将所有遗失的封包重送后才会结束Fast-recovery,这使得NewReno的传送端在网络有大量封包遗失时不需等待Timeout就能更正此错误,减少大量封包遗失对传输效果所造成的影响。NewReno大约每一个RTT时间可重送一个遗失的封包,在Fast-recovery阶段,若允许的话,传送端可以继续送出新的封包,以增加Link的使用率。
从TCP SACK的cwnd变化图(图19)中我们可以看到,在这个版本中,加入了一个SACK选项,允许接收端在返回Duplicate ACK时,将已接收到的数据区段(连续收到的数据范围)返回给传送端,数据区段与数据区段之间的间隔就是接收端没有收到的数据。通过这些信息,传送端就知道哪些是已经收到的,哪些是该重送的,因此SACK的传送端可以在一个RTT时间之内重送一个以上的封包。
从Vegas的图形(图20)中可以看到,第一条Vegas从0s开始执行,10s时结束。第二条Vegas在5s时才开始执行,10s时结束。从图中我们还可以看到,在Slow-start阶段,cwnd的值大约两个RTT才会增加1倍。与Reno不同的是,当Diff的值介于α与β之间时,Vegas的cwnd会持续维持在一个稳定的状态,这是因为,基本上Vegas的拥塞控制算法是一种“拥塞避免”的方法。
从Vegas与Reno的cwnd的变化图(图21)中可以看到,Reno的Window总是在较高的地方振荡,而Vegas的Window总是在较低的位置。虽然根据研究显示,当网络的通信都使用TCP Vegas时,整体的执行效果会优于TCP Reno,这是因为TCP Vegas采取较为保守的作法避免封包遗失,并以此提高网络的执行效果。但当TCP Vegas和Reno共存时,TCP Vegas并没有办法与TCP Reno公平地竞争频宽。造成这个问题的主要原因是,Reno使用了较具侵略性的拥塞控制方法,TCP Reno的传送端会持续地将封包送到网络上直到发生拥塞。比较之下,Vegas的传送端在网络开始拥塞时就将传送端的传送速度降慢,以避免拥塞的情形发生。因此,当TCP Vegas与TCP Reno共存Vegas在效果上的表现总是会比较差。
三、添加Ping协议
3.1实验目的
本实验通过实现一个Ping协议来说明如何在NS2中添加新协议
3.2 实验步骤
一、
在ns-2.35目录下新建一个MyPing目录,将老师给的文件MyPing.h和MyPing.cc放到这个目录里下。
这两个文件见 附录D和E。(红色字体为修订处)
文件说明:
MyPing.h中 :
定义了包头结构:
struct hdr_ping {
char ret;
double send_time;
};
定义PingAgent类
class PingAgent : public Agent {
public:
PingAgent();
int command(int argc, const char*const* argv);
void recv(Packet*, Handler*);
protected:
int off_ping_;
};
MyPing.cc中:
定义PingHeaderClass类
static class PingHeaderClass : public PacketHeaderClass {
public:
PingHeaderClass() : PacketHeaderClass("PacketHeader/Ping",
sizeof(hdr_ping)) {}
} class_pinghdr;
定义PingClass类
static class PingClass : public TclClass {
public:
PingClass() : TclClass("Agent/Ping") {}
TclObject* create(int, const char*const*) {
return (new PingAgent());
}
} class_ping;
定义PingAgent的实现
PingAgent::PingAgent() : Agent(PT_PING){
bind("packetSize_", &size_);
bind("off_ping_", &off_ping_);
}
int PingAgent::command(int argc, const char*const* argv){
if (argc == 2) {
if (strcmp(argv[1], "send") == 0) {
…
}
}
return (Agent::command(argc, argv));
}
void PingAgent::recv(Packet* pkt, Handler*){
…
}
二、
修改ns-2.35/common/packet.h文件
如图找到相应的地方添加修改:(代码前面的 + 表示添加,-表示删除,下同)
三、
编辑ns-2.35/tcl/lib/ns-default.tcl
增加一行 Agent/MyPing set packetSize_ 64
四、
编辑ns-2.35/Makefile文件
如图在 OBJ_CC 下添加一行
五、
Makefile目录下编译文件
make clean
make depend
make
六、
编写测试的TCL代码
#Create a simulator object
set ns [new Simulator]
#Open a trace file
set nf [open out.nam w]
$ns namtrace-all $nf
#Define a 'finish' procedure
proc finish {} {
global ns nf
$ns flush-trace
close $nf
exec nam out.nam &
exit 0
}
#Create three nodes
set n0 [$ns node]
set n1 [$ns node]
set n2 [$ns node]
#Connect the nodes with two links
$ns duplex-link $n0 $n1 1Mb 10ms DropTail
$ns duplex-link $n1 $n2 1Mb 10ms DropTail
#Define a 'recv' function for the class 'Agent/MyPing'
Agent/MyPing instproc recv {from rtt} {
$self instvar node_
puts "node [$node_ id] received ping answer from \
$from with round-trip-time $rtt ms."
#}
#Create two ping agents and attach them to the nodes n0 and n2
set p0 [new Agent/MyPing]
$ns attach-agent $n0 $p0
set p1 [new Agent/MyPing]
$ns attach-agent $n2 $p1
#Connect the two agents
$ns connect $p0 $p1
#Schedule events
$ns at 0.2 "$p0 send"
$ns at 0.4 "$p1 send"
$ns at 0.6 "$p0 send"
$ns at 0.6 "$p1 send"
$ns at 1.0 "finish"
#Run the simulation
$ns run
七、运行代码
四、添加Application和Agent协议
4.1实验目的
本部分通过编写一个UDP上的multimedia Application来说明如何添加Application和Agent
4.2实验步骤
一、
在ns-2.35下新建目录Multimedia,将udp-mm.cc,udp-mm.h,mm-app.cc,mm-app.h 四个文件放到该目录下,这四个文件详细见 附录F。
文件说明:
其中定义包头结构
编写MmApp Sender
编写MmApp Receiver
具体见附录。
编写UdpMmAgent
UdpMmAgent继承了UdpAgent,添加了部分功能。具体见附录。
二、
修改ns-2.35/packet.h
在如图两处,各添加一行,并做相应修改。
三、
修改ns-2.35/tcl/lib/ns-packet.tcl
在protolist里添加
四、
修改ns-2.35/common/agent.h
五、
修改 ns-2.35/apps/app.h:
六、
在ns-2.35/tcl/lib/ns-default.tcl 中设置新参数的默认值
七、
编辑ns-2.35/Makefile :
八、
在Makeflie目录下编译:
make clean
make depend
make
九、运行
编写测试的TCL代码 。 见附录F :ex-mm-app.tcl
十、
运行程序
ns ex-mm-app.tcl
附录A
TCPV1代码
if {$argc !=1} {
puts "Usage: ns lab11.tcl TCPversion "
puts "Example:ns lab11.tcl Tahoe or ns lab11.tcl Reno"
exit
}
set par1 [lindex $argv 0]
# 产生一个仿真的对象
set ns [new Simulator]
$ns color 1 Blue
#开启一个trace file,用来记录封包传送的过程
set nd [open out-$par1.tr w]
$ns trace-all $nd
set nf [open out-$par1.nam w]
$ns namtrace-all $nf
#开启一个档案用来记录cwnd变化情况
set f0 [open cwnd-$par1.tr w]
#定义一个结束的程序
proc finish {} {
global ns nd nf f0 tcp par1
#显示最后的平均吞吐量
puts [format "average throughput:%.1f Kbps" \
[expr [$tcp set ack_]*([$tcp set packetSize_])*8/1000.0/10]]
$ns flush-trace
#关闭档案
close $nd
close $nf
close $f0
exec nam out-$par1.nam &
exit 0
}
#定义一个记录的程序
#每格0.01秒就去记录当时的cwnd
proc record {} {
global ns tcp f0
set now [$ns now]
puts $f0 "$now [$tcp set cwnd_]"
$ns at [expr $now+0.01] "record"
}
#产生传送节点,路由器r1,r2和接收节点
set n0 [$ns node]
set r0 [$ns node]
set r1 [$ns node]
set n1 [$ns node]
#建立链路
$ns duplex-link $n0 $r0 10Mb 1ms DropTail
$ns duplex-link $r0 $r1 1Mb 4ms DropTail
$ns duplex-link $r1 $n1 10Mb 1ms DropTail
$ns duplex-link-op $n0 $r0 orient right
$ns duplex-link-op $r0 $r1 orient right
$ns duplex-link-op $r1 $n1 orient right
$ns duplex-link-op $r0 $r1 queuePos 0.5
#设定队列长度为18个封包大小
set queue 18
$ns queue-limit $r0 $r1 $queue
#根据使用者的设定,指定TCP版本
if {$par1=="Tahoe"} {
set tcp [new Agent/TCP]
} else {
set tcp [new Agent/TCP/Reno]
}
$ns attach-agent $n0 $tcp
set tcpsink [new Agent/TCPSink]
$ns attach-agent $n1 $tcpsink
$ns connect $tcp $tcpsink
$tcp set fid_ 1
#建立FTP应用程序
set ftp [new Application/FTP]
$ftp attach-agent $tcp
#在0.0秒时,开始传送
$ns at 0.0 "$ftp start"
#在10.0秒时,结束传送
$ns at 10.0 "$ftp stop"
#在0.0秒时去呼叫record来记录TCP的cwnd变化情况
$ns at 0.0 "record"
#在第10.0秒时去呼叫finish来结束模拟
$ns at 10.0 "finish"
#执行模拟
$ns run
附录B
TCPV2代码
if {$argc !=1} {
puts "Usage: ns lab12.tcl TCPversion "
puts "Example:ns lab12.tcl Reno or ns lab12.tcl Newreno or ns lab12.tcl Sack"
exit
}
set par1 [lindex $argv 0]
# 产生一个仿真的对象
set ns [new Simulator]
#开启一个trace file,用来记录封包传送的过程
set nd [open out-$par1.tr w]
$ns trace-all $nd
#开启一个档案用来记录cwnd变化情况
set f0 [open cwnd-$par1.tr w]
#定义一个结束的程序
proc finish {} {
global ns nd f0 tcp par1
#显示最后的平均吞吐量
puts [format "average throughput: %.1f Kbps" \
[expr [$tcp set ack_]*([$tcp set packetSize_])*8/1000.0/10]]
$ns flush-trace
#关闭档案
close $nd
close $f0
#使用awk分析记录文件以观察队列的变化
exec awk {
BEGIN {
highest_packet_id = -1;
packet_count = 0;
q_eln = 0;
}
{
action = $1;
time = $2;
src_node = $3;
dst_node = $4;
type = $5;
flow_id = $8;
seq_no = $11;
packet_id = $12;
if (src_node == "0" && dst_node == "1") {
if (packet_id > highest_packet_id) {
highest_packet_id = packet_id;
}
if (action == "+") {
q_len++;
print time, q_len;
}
if (action == "-" || action == "d") {
q_eln = q_len--;
print time, q_len;
}
}
}
} out-$par1.tr > queue_length-$par1.tr
exit 0
}
#定义一个记录的程序
#每格0.01秒就去记录当时的cwnd
proc record {} {
global ns tcp f0
set now [$ns now]
puts $f0 "$now [$tcp set cwnd_]"
$ns at [expr $now+0.01] "record"
}
#产生传送节点,路由器r1,r2和接收节点
set r0 [$ns node]
set r1 [$ns node]
set n0 [$ns node]
set n1 [$ns node]
#建立链路
$ns duplex-link $n0 $r0 10Mb 1ms DropTail
$ns duplex-link $r0 $r1 1Mb 4ms DropTail
$ns duplex-link $r1 $n1 10Mb 1ms DropTail
#设定队列长度为15个封包大小
set buffer_size 15
$ns queue-limit $r0 $r1 $buffer_size
#根据使用者的设定,指定TCP版本
if {$par1=="Reno"} {
set tcp [new Agent/TCP/Reno]
set tcpsink [new Agent/TCPSink]
$tcp set debug_ 0
} elseif {$par1=="Newreno"} {
set tcp [new Agent/TCP/Newreno]
set tcpsink [new Agent/TCPSink]
$tcp set debug_ 0
} else {
set tcp [new Agent/TCP/Sack1]
set tcpsink [new Agent/TCPSink/Sack1]
$tcp set debug_ 1
}
$ns attach-agent $n0 $tcp
#将awnd的值设为24,这是advertised window的上限
# advertised window是接收端的缓冲区可以容纳的封包个数,
#因此当congestion window的值超过advertised window时,
#TCP的传送端会执行流量控制以避免送的太快而导致接收端的缓冲区溢满。
$tcp set window_ 24
$ns attach-agent $n1 $tcpsink
$ns connect $tcp $tcpsink
#建立FTP应用程序
set ftp [new Application/FTP]
$ftp attach-agent $tcp
#在0.0秒时,开始传送
$ns at 0.0 "$ftp start"
#在10.0秒时,结束传送
$ns at 10.0 "$ftp stop"
#在0.0秒时去呼叫record来记录TCP的cwnd变化情况
$ns at 0.0 "record"
#在第10.0秒时去呼叫finish来结束模拟
$ns at 10.0 "finish"
#计算在传输路径上大约可以容纳多少的封包
#计算方式:在bottleneck link上每秒可以传送的封包数*RTT+队列缓冲区大小
puts [format "on path: %.2f packets" \
[expr (1000000/(8*([$tcp set packetSize_]+40)) * ((1+4+1) * 2 * 0.001)) + $buffer_size]]
#执行模拟
$ns run
附录C
TCPv3代码
# 产生一个仿真的对象
set ns [new Simulator]
#开启一个trace file,用来记录封包传送的过程
set nd [open out13_1.tr w]
$ns trace-all $nd
#开启两个档案用来记录cwnd变化情况
set f0 [open cwnd0.tr w]
set f1 [open cwnd1.tr w]
#定义一个结束的程序
proc finish {} {
global ns nd f0 tcp0 f1 tcp1
#puts "ACK number: [$tcp0 set ack_]"
puts [format "average throughput: %.1f Kbps" \
[expr [$tcp1 set ack_]*([$tcp1 set packetSize_])*8/1000.0/10]]
puts [format "average throughput: %.1f Kbps" \
[expr [$tcp0 set ack_]*([$tcp0 set packetSize_])*8/1000.0/10]]
$ns flush-trace
#关闭档案
close $nd
close $f0
close $f1
#使用awk分析记录文件以观察队列的变化
exec awk {
BEGIN {
highest_packet_id = -1;
packet_count = 0;
q_eln = 0;
}
{
action = $1;
time = $2;
src_node = $3;
dst_node = $4;
type = $5;
flow_id = $8;
seq_no = $11;
packet_id = $12;
if (src_node == "0" && dst_node == "1") {
if (packet_id > highest_packet_id) {
highest_packet_id = packet_id;
}
if (action == "+") {
q_len++;
print time, q_len;
}
if (action == "-" || action == "d") {
q_eln = q_len--;
print time, q_len;
}
}
}
} out13_1.tr > queue_length-13_1.tr
exit 0
}
#定义一个记录的程序
#每格0.01秒就去记录当时的cwnd
proc record {} {
global ns tcp0 f0 tcp1 f1
set now [$ns now]
puts $f0 "$now [$tcp0 set cwnd_]"
puts $f1 "$now [$tcp1 set cwnd_]"
$ns at [expr $now+0.01] "record"
}
#建立节点
set r0 [$ns node]
set r1 [$ns node]
set n0 [$ns node]
set n1 [$ns node]
set n2 [$ns node]
set n3 [$ns node]
#建立链路
$ns duplex-link $n0 $r0 10Mb 1ms DropTail
$ns duplex-link $n2 $r0 10Mb 1ms DropTail
$ns duplex-link $r0 $r1 1Mb 20ms DropTail
$ns duplex-link $r1 $n1 10Mb 1ms DropTail
$ns duplex-link $r1 $n3 10Mb 1ms DropTail
set buffer_size 15
$ns queue-limit $r0 $r1 $buffer_size
#建立TCP Vegas的FTP联机
set tcp0 [new Agent/TCP/Vegas]
$tcp0 set v_alpha_ 1
$tcp0 set v_beta_ 3
$tcp0 set window_ 24
$ns attach-agent $n0 $tcp0
set tcp0sink [new Agent/TCPSink]
$ns attach-agent $n1 $tcp0sink
$ns connect $tcp0 $tcp0sink
set ftp0 [new Application/FTP]
$ftp0 attach-agent $tcp0
#建立另一条TCP Vegas的FTP联机
set tcp1 [new Agent/TCP/Vegas]
$tcp1 set v_alpha_ 1
$tcp1 set v_beta_
展开阅读全文