NS2队列管理机制(转载)
原文地址:http://hi.baidu.com/jerry_916/blog/item/456bfbdc2aca47d48d1029be.html
两种传统的包的调度策略
在介绍Drop Tail之前,我们先介绍两种传统的包的调度策略-决定包的传送顺序。
(1)FIFO (First In First Out,先进先出)是一种经典的包调度策略,它的最大优点在于实施起来简单。FIFO又叫“先到先服务”(FCFS),即第一个到达路由器的数据包首先被传输。FIFO的问题在于在排队的时候没有考虑包的重要程度,对FIFO排队的一个简单改进是优先级排队。基本思想是给每个数据包分配一个优先级标志。这个优先级标志可以放在IP数据包内。路由器则执行多个FIFO排队。一个队列对应一个优先级。路由器在排队的时候总是给优先级高的队列先排队。在同一优先级队列中,数据包仍按FIFO排队。
(2)公平排队算法(Fair Queue,FQ)是FIFO的一种改进。FIFO排队的主要问题是无法区分不同的数据流。由于整个TCP的拥塞控制是在源端执行,而FIFO排队不提供约束所有数据源遵守拥塞控制的机制,这就有可能让行为不良的数据流强占大量带宽。在Internet环境中,某个应用不使用TCP协议是完全可能的。结果,它可以绕开端到端的拥塞控制机制,向路由器任意发送自己的数据包,从而引起其它应用的包被丢弃。FQ算法则解决了这个问题。在FQ算法中,路由器对每个输出线路有一个排队队列。路由器按“轮询”方式处理包。当一条线路闲时,路由器就来回扫描所有队列,依次将每队每一个包发出。当某个流的数据包到达过快时,其队列就会很快占满,属于这个流的新到的数据包就会被丢弃。采用这种方式,每个数据流就不可能牺牲其它数据流而多占资源。另外,FQ算法并没有告知源端路由器状态的机制,也就是说,FQ仍然要依赖于端到端的拥塞控制机制。它只是将数据流分隔,使不遵守拥塞控制机制的数据流不至于影响其它流。所以它在没有牺牲统计复用的情况下提供了公平性,与端到端的拥塞控制机制也可以较好地协同。
传统的队列长度管理机制是“去尾”( Drop Tail )。它有点类似于FIFO(先入先出)的存储方式。Drop Tail最大的优点是原理简单。当路由器队列长度达到最大值时,通过丢包来指示拥塞,先到达路由器的分组首先被传输。由于路由器缓存有限,如果包到达时缓存已满,那么路由器就丢弃该分组。一旦发生丢包,发送端立即被告知网络拥塞,从而调整发送速率。这种做法不考虑被丢弃包的重要程度。
Drop Tail仍是目前Internet使用最为广泛的分组排队、丢弃的方式。这种方式将拥塞控制的责任都推给网络边缘。所以TCP假定网络中的路由器对拥塞控制不起任何作用,而独自承担检测和响应拥塞的全部责任。
基于Drop Tail的一种改进算法是优先级排队。它的基本思路是将每个分组分配一个优先级标志。路由器则执行多个队列排队。一个队列对应一个优先级。路由器总是优先 传输非空的最高优先级队列。在同一优先级队列中,分组仍按Drop Tail方式管理。
优先级排队的主要问题是最高优先级队列能“抢占”其它所有的队列。只要高优先级队列非空,低优先级队列就得不到服务。所以,不能允许用户不受控地指定高优先级。同时,Drop Tail无法“识别”面向连接的TCP流,所以对它们的公平性较差,对上层TCP快速恢复的效率也很低。
除了这些,它在具体实施过程中也存在着很多其它的弊端。如;若缓冲器很长,则每个分组所经历的延迟就会增大:而若缓冲器很短的话,又不能够适应突发性数据 流;另外,全局同步的发生又将直接导致吞吐率的减小,等等。所有这些都可能引起网络崩溃。
常见的队列调度算法
另外,DropTail容易造成TCP全局同步(TCP Global Synchronization)问题,由于Internet上的数据流都具有突发本质(Burstiness),到达路由器的封包也往往是突发的。如果队列是满的或者几乎是满的,就会导致在短时间内连续大量的丢包。而TCP数据流具有自适应特性(Adaptive),来源端发现封包丢失就急剧地把传送速率降低,于是网络拥塞情况得以解除,但来源端在得知网络不再拥塞后又开始增加发送速度,最终又造成网络拥塞。这种现象常常会周而复始地进行下去,因此网络常处于链路利用率很低的状态,降低了整体吞吐量,这就是所谓的TCP全局同步现象。
(2)随机早期检测算法(Random Early Detection):RED配置在路由器监视网络流量以便避免拥塞,当即将拥塞发生时,它随机丢弃进来的分组,而不是等到队列缓冲区满时才开始丢弃所有进来的分组,这样可以最少化全局同步的发生。当拥塞发生时,RED丢弃每个连接分组的概率与该连接占用的带宽成比例,它监视每个输出队列的平均队列长度, 随机选择分组丢弃。虽然RED通过随机早期检测和丢包,从而有效地在TCP流之间分配带宽,但混合TCP和非TCP数据流时,RED不能有效地保护TCP 流,没有拥塞控制或采用比TCP更贪婪的非TCP流将比TCP流攫取更多的网络带宽,这种不公平性的主要原因是在拥塞发生时非TCP流不降低发送速率或降低的程度比TCP少,而RED对所有的流都采用同样的丢包比率。
NS2集成了多种网络协议(如TCP、UDP),业务类型(如FTP、Telnet、Web等),路由队列调度算法(如Drop Tail、RED、FQ等),路由算法(如Dijkstra等)。可参看DropTail、RED、SFQ(Stochastic Fair Queuing)和DRR四种队列调度算法。
(1)被动式队列管理机制——DropTail,Random Drop 和 Drop Front。Random Drop是指当队列满时,从队列中随机找一个包丢弃,让新来的包进入队列。Drop Front 是指当队列满时,从队列前端把封包丢弃,以便新包进入队列。由于这几种方法都是在队列满了时被迫丢包,因此称为被动式队列管理。
(2)主动式队列管理机制——RED。主动式队列管理机制会在队列满之前就开始把封包丢弃,这样可以对具有拥塞控制的传送端做流量速度管制,以避免满队列状态所带来的较长端到端时延或链路利用率很低的负面效应。
Analysis
#设置源节点和目的节点
set src($i) [$ns node] #s($i)
set dst($i) [$ns node] #d($i)
#仅用一句话便完成TCP联机的建立
for {set i 0} {$i<$par2} {incr i} {
set tcp($i) [$ns create-connection TCP/Reno $src($i) TCPSink $dst($i) 0]
$tcp($i) set fid_ $i
}
#在TCP联机之上建立FTP应用程序
for {set i 0} {$i<$par2} {incr i} {
set ftp($i) [$tcp($i) attach-app FTP]
$ns at $startT($i) "$ftp($i) start"
}
该实验的目的是将被动队列管理机制DropTail和主动队列管理机制RED在吞吐量、延时、队列长度方面做比较。实验中并没有直接采用 DropTail,而是将链路类型定义为myfifo,同时选择用如下代码将队列长度记录下来:
set q_ [[$ns link $r1 $r2] queue]
set queuechan [open q-$par1-$par2.tr w]
$q_ trace curq_
if {$par1=="RED"} {
$q_ set bytes_ false
$q_ set queue_in_bytes_ false
}
$q_ attach $queuechan
我在实验中尝试将链路参数直接设定为DropTail(而非myfifo),结果提示"$q_ attach $queuechan”处有错误,遂尝试其它链路类型,FQ等,均不对。查阅其它参考书,将这段代码替换为:
$ns monitor-queue $r1 $r2 [open q-$par1-$par2.tr w] 0.3
[$ns link $r1 $r2] queue-sample-timeout
至此,可以在运行时将参数给定为正常的链路类型,DropTail,FQ,RED,等,myfifo仍然可以使用。但后面用gnuplot画图 时,需要使用
plot "q-myfifo-10.tr" using 1:5 with linespoints 1, "q-RED-10.tr" using 1:5 with linespoints 2
而不是原来的
plot "q-myfifo-10.tr" using 2:3 with linespoints 1, "q-RED-10.tr" using 2:3 with linespoints 2
因为新的输出文件的第1列和第5列才是所需数据。(顺便强调一下,plot命令中,using 2:3的意思是用第2列数据作为横坐标,用第3列数据作为纵坐标。 )同时,原来产生的队列长度记录文件中有一些数据的第3列是相同的,但第2列不同,不明白是怎么回事,但在我改变后的新的输出文件中就没有这种现象。
Q 0.0342079 1
Q 0.118126 2
Q 0.206406 3
Q 0.314605 4
Q 0.354894 2
Q 0.354977 3
Q 0.372965 4
Q 0.440528 5
Q 0.440612 6
Q 0.481177 7
Q 0.486243 8
Q 0.486326 9
Q 0.514977 10
Q 0.565884 11
Q 0.663466 10
Q 0.663549 11
Q 0.728868 12
Q 0.817834 13
Q 0.849159 14
Q 0.886479 15
Q 0.966323 14
Q 0.966406 15
Q 0.9891 16
Q 0.989183 17
Q 1.20069 18
Q 1.21196 19
Q 1.21204 20
Q 1.34918 19
Q 1.34926 20
另外,书中的queue.tcl文件代码部分,在finish过程中计算吞吐量的循环中
for {set i 0} {$i<$par2} {incr i} {
set ackno_($i) [$tcp($i) set ack_]
set thgpt($i) [expr $ackno_($i)*1000.0*8.0/($time-$start($i))]
set sum_thgpt [expr $sum_thgpt+$thgpt($i)]
}
开始时间的数组start($i),参照先前的习惯,以及该文件后面对该数组的使用,应该是startT($i)。我没看CD中给出的代码,不 知道那里的原代码是不是正确。
PS: $tcp($i) set ack_表示接收端收到的最大确认号。
运行错误注解
(1)$ ns queue.tcl myfifo 10
invalid command name "Queue/myfifo"
while executing
"Queue/myfifo create _o476 "
invoked from within
"catch "$className create $o $args" msg"
invoked from within
"if [catch "$className create $o $args" msg] {
if [string match "__FAILED_SHADOW_OBJECT_" $msg] {
delete $o
return ""
}
global errorInfo
error "class $..."
(procedure "new" line 3)
invoked from within
"new Queue/$qtype"
("default" arm line 3)
invoked from within
"switch -exact $qtype {
ErrorModule {
if { [llength $args] > 0 } {
set q [eval new $qtype $args]
} else {
set q [new $qtype Fid]
}
}
intserv {
set qtyp..."
(procedure "_o3" line 14)
(Simulator simplex-link line 14)
invoked from within
"_o3 simplex-link _o70 _o73 56k 10ms myfifo"
("eval" body line 1)
invoked from within
"eval $self simplex-link $n1 $n2 $bw $delay $type $args"
(procedure "_o3" line 8)
(Simulator duplex-link line 8)
invoked from within
"$ns duplex-link $r1 $r2 56k 10ms $par1"
(file "queue.tcl" line 55)
按照上面的提示应该是队列名myfifo有问题,但是输入FIFO也不行。但是输入RED队列时
$ ns queue.tcl RED 10
average throughput: 4643.743454368604 (bps)
输出正常,不知道是什么原因?
解决办法:http://140.116.72.80/~smallko/ns2/module.htm
并将$q_ attach $queuechan改为:
$ns monitor-queue $r1 $r2 [open q-$par1-$par2.tr w] 0.3
[$ns link $r1 $r2] queue-sample-timeout
(2)SplitObject::trace called in the base class of _o476
解决办法:全是 因为 空格 的格式 出现的问题
所以 大家在要注意 这非常严谨的 语言
在這邊先做個小結,如何新增模組到ns2的核心步驟如下:
1.準備好模組檔(例如,a.cc 和 a.h)。
2.若有需要做初始設定的話,修改ns-default.tcl檔。
3.修改Makefile(把a.o加到OBJ_CC內)
4.重新編譯
5.測試模組