NS2 如何监控队列长度 建议方法2
方法1: 只对RED有效
set q_n1_n2 [[$ns link $n1 $n2] queue]
set q_ $q_n1_n2
set queuefd [open q-Red_Queue.tr w]
$q_ trace curq_ ;#current queue
$q_ trace ave_ ;#average queue
$q_ attach $queuefd
方法2:monitor-queue 对所有队列有效,只记录结果,,
注意queue_limit*meanpktsizes 才是统计结果
利用“monitor-queue”可以监视指定链路的队列的实时变化情况,用法如下:
set qm [$ns monitor-queue $s0 $r0 [open qm.out w] 0.01]
$qm set size_
解释:
1.$ns monitor-queue $n0 $n1 [open qm.out w] 0.01
依次的含义:“$ns”表示ns对象,“monitor-queue”是ns对象的方法(也可以认为是固定的命令)用来创建队列监视的对象,“$n0”和"n1"表示链路的两个网络节点, "[open qm.out w]“表示打开文件,"0.01"表示监视队列的时间间隔。
2.注意上面的命令返回的是一个对象,所以使用set将其赋值给了变量qm,利用此变量进行后续操作。
3.$qm set size_ 返回当前的队列大小。
4.上面的还不能满足需求,需要将其放到一个函数中,下面的是一个较完整的例子:
........省略代码
set qf [open myfile.txt w]
proc record {} {
#声明全局变量,qf为记录队列大小随时间变化的文本文件
global qm ns qf
set now [$ns now]
puts $qf "$now [$qm set size_]"
$ns at [expr $now + 0.01] "record"
}
set qm [$ns monitor-queue $n0 $n1 [open qm.out w] 0.01]
.......省略代码
$ns at 0.0 "record"
.......
$ns run
方法3:对所有队列有效,记录整个队列情况
queue_limit设置为10 这里刚好到n-1 也就是9
绘制曲线的时候使用gnuplot设置绘制数据的列就可以了,,
gnuplot> plot "qm.out" using 1:5
gnuplot> plot "qm.out" using 1:5 with lines
gnuplot>
其中qm.out结果格式可能比较复杂,需要自己分析
qm.out格式,,,
http://www.mathcs.emory.edu/~cheung/Courses/558-old/Syllabus/90-NS/trace.html
set file1 [open qm.out w]
set qmon [$ns monitor-queue $n2 $n3 $file1 0.1]
[$ns link $n2 $n3] queue-sample-timeout
方法4:修改源代码实现,,较复杂,通用
队列的输出
实现队列输出的思路:首先编写运行一个tcl脚本,读取脚本生成原的trace文件(out_rc_3.tr),在该trace文件中计算获取相应节点和队列长度(调用一些.h文件实现),然后将这些内容在生成一个trace文件(qlen.tr),为了阅读的方便在由gnuplot读取qlen.tr生成gnuplot图。
首先对NS2进行编译,查看是否有错:打开NS2,进入到相关路径,在该路径下分别输入“make clean”,“make depend”,“make”命令符。
编译结束。没有出错在进行程序源代码的修改(红色为添加部分)。修改的步骤如下所示:
1.修改queue/priqueue.h文件
#include "trace.h"
class PriQueue : public DropTail {
public:
PriQueue();
int command(int argc, const char*const* argv);
void recv(Packet *p, Handler *h);
void recvHighPriority(Packet *, Handler *);
// insert packet at front of queue
void filter(PacketFilter filter, void * da
// apply filter to each packet in queue,
// - if filter returns 0 leave packet in queue
// - if filter returns 1 remove packet from queue
Packet* filter(nsaddr_t id);
void Terminate(void);
Tcl_Channel tchan_; /* place to write trace records */tchan_指向存放trace文件内容的地方
TracedInt curq_; /* current qlen seen by arrivals */当前的队列长度
void trace(TracedVar*); /* routine to write trace records */实现写下trace记录的程序
private:
int Prefer_Routing_Protocols;
/*
* A global list of Interface Queues. I use this list to iterate
* over all of the queues at the end of the simulation and flush
* their contents. - josh
*/
public:
LIST_ENTRY(PriQueue) link;
static struct PriQueue_List prhead;
};
#endif /* !_priqueue_h */
2.修改queue/ priqueue.cc
PriQueue::PriQueue() : DropTail()
{
bind("curq_",&curq_);
tchan_=0;
bind("Prefer_Routing_Protocols", &Prefer_Routing_Protocols);
LIST_INSERT_HEAD(&prhead, this, link);
}
int PriQueue::command(int argc, const char*const* argv)
{
if (argc == 2 && strcasecmp(argv[1], "reset") == 0) {
Terminate();
//FALL-THROUGH to give parents a chance to reset
}
else if(argc == 3 &&strcmp(argv[1], "attach") == 0) {
int mode;
const char* id = argv[2];
Tcl& tcl = Tcl::instance();
tchan_ = Tcl_GetChannel(tcl.interp(), (char*)id, &mode);
if (tchan_ == 0) {
tcl.resultf("trace: can't attach %s for writing", id);
return (TCL_ERROR);
}
return (TCL_OK);
}
return DropTail::command(argc, argv);
}
void PriQueue::recv(Packet *p, Handler *h)
{
struct hdr_cmn *ch = HDR_CMN(p);
curq_ = q_->length();
if(Prefer_Routing_Protocols) {
……………………………
}
}
void PriQueue::trace(TracedVar* v)
{
char wrk[500], *p;
if (((p = strstr(v->name(), "curq")) == NULL) ) {
fprintf(stderr, "PriQueue:unknown trace var %s\n", v->name());
return;
}
strstr的功能返回curq在v->name()中第一次出现的位置,如果没有返回NULL,fprintf(文件指针,格式字符串,输出表列);将按格式要求处理后的数据写入文件
if (tchan_) {实现从trace文件中数据读取
int n;
double t = Scheduler::instance().clock();将仿真时间赋给t
if (strstr(v->name(), "curq") != NULL) {
sprintf(wrk, "Q %g %d", t, int(*((TracedInt*) v)));
}
/*sprintf将t和int(*((TracedInt*) v))按照 %g %d保存到wrk数组中,在此处实现新qlen.tr文件的输出格式,如第四步下图所示。t为当前仿真时刻,由于t的指数大于-4故按照%f格式输出。int(*((TracedInt*) v))为当前时刻的队列大小*/%g是一种输出格式,指数小于-4按%e输出,否则安装%f输出;当大于精度时按%e输出,否则安装%f输出。%min.max g其中min和max指定了输出数据的精度——最小和最大有效数据字符个数。如%6g和%.7g最小为6个有效字符个数,最大为7个有效字符个数。
n = strlen(wrk);计算wrk中有效长度
wrk[n] = '\n';
wrk[n+1] = 0;
(void)Tcl_Write(tchan_, wrk, n+1);
}
return;
}
3.修改tcl/lib/ns-default.tcl
加入 Queue/DropTail/PriQueue set curq_ 0。然后重新编译。
4. 运行测试脚本
运行脚本后生成该脚本的trace文件,模拟时间为5秒。
为了方便查看,启动NS2中的gnuplot画图工具作图,具体步骤如下图所示:
运行tcl脚本和调用gnuplot
调用gnuplot,并设置相关参数,用set设置坐标时要区分大小写!set xlabel与set Xlabel
不同!
生成图像
该tcl脚本程序如下:
set opt(chan) Channel/WirelessChannel ;# channel type
set opt(prop) Propagation/TwoRayGround ;# radio-propagation model
set opt(netif) Phy/WirelessPhy ;# network interface type
set opt(mac) Mac/802_11 ;# MAC type
set opt(ifq) Queue/DropTail/PriQueue ;# interface queue type
set opt(ll) LL ;# link layer type
set opt(ant) Antenna/OmniAntenna ;# antenna model
set opt(ifqlen) 50 ;# max packet in ifq
set opt(adhocRouting) DumbAgent ;# routing protocol
set opt(x) 670 ;# X dimension of the topography
set opt(y) 670 ;# Y dimension of the topography
set ns [new Simulator]
#number of nodes
set num_mobile_nodes 3
设置数据流速率
Mac/802_11 set dataRate_ 1Mb
Mac/802_11 set basicRate_ 1Mb
建立trace文件——用于数据的记录
set ntr [open out_rc_3.tr w]
$ns trace-all $ntr
set chan [new $opt(chan)] 信道的声明
建立拓扑结构
set topo [new Topography]
$topo load_flatgrid $opt(x) $opt(y)
# Create God动态保存个移动节点之间的连接关系
create-god $num_mobile_nodes
# config node 节点信息的配置
$ns node-config -adhocRouting $opt(adhocRouting) \
-llType $opt(ll) \
-macType $opt(mac) \
-ifqType $opt(ifq) \
-ifqLen $opt(ifqlen) \
-antType $opt(ant) \
-propType $opt(prop) \
-phyType $opt(netif) \
-channel $chan\
-topoInstance $topo \
-wiredRouting ON \
-agentTrace ON \
-routerTrace ON \
-macTrace ON \
-movementTrace ON
是否启用RTS/CTS协议使用时默认为0否则为3000(MAC层固定的)
Mac/802_11 set RTSThreshold_ 3000
创建节点,物理范围
for {set i 0} {$i < $num_mobile_nodes} {incr i} {
set wl_node_($i) [$ns node]
$wl_node_($i) random-motion 0 ;# disable random motion
puts "wireless node $i created ..."
$wl_node_($i) set X_ [expr $i * 10.0]
$wl_node_($i) set Y_ [expr $i * 10.0]
$wl_node_($i) set Z_ 0.0
}
以下内容是关键部分,用于实现从trace文件中读取某个节点的队列长度
设置目标节点的接口队列——确定要查看哪个节点的队列长度
set wl_ifq [$wl_node_(0) set ifq_(0)]
将trace文件的内容放到queuechan中
set queuechan [open qlen.tr w]
实现wl_ifq和queuechan的相结合——在trace文件中获取相应节点的实时队列长度
$wl_ifq attach $queuechan
设置要观察的变量为当前队列长度curq_
$wl_ifq trace curq_
该程序段实现对各节点的代理和应用的定义,得到一个环形的数据流模式!
for {set i 0} {$i < $num_mobile_nodes} {incr i} {
set src_udp_($i) [new Agent/UDP]
$src_udp_($i) set class_ $i
set dst_udp_($i) [new Agent/Null]
$ns attach-agent $wl_node_($i) $src_udp_($i)
$ns attach-agent $wl_node_([expr ($i+1)%($num_mobile_nodes)]) $dst_udp_($i)
set app_($i) [new Application/Traffic/CBR]
$app_($i) set packetSize_ 1025
$app_($i) set interval_ 0.005
$app_($i) attach-agent $src_udp_($i)
$ns connect $src_udp_($i) $dst_udp_($i)
$ns set fid_ $i
$ns at $i "$app_($i) start"
}
# Define node initial position in nam
for {set i 0} {$i < $num_mobile_nodes} {incr i}
{
$ns initial_node_pos $wl_node_($i) 20
}
# Tell nodes when the simulation ends
for {set i 0} {$i < $num_mobile_nodes } {incr i} {
$ns at 10.0 "$wl_node_($i) reset";
}
for {set i 0} {$i < $num_mobile_nodes} {incr i} {
$ns at 5.0 "$app_($i) stop"
}
$ns at 11.0 "puts \"NS EXITING...\" ; $ns halt"
proc stop {} {
global ns ntr queuechan
close $ntr
close $queuechan
}
$ns run