NS2 整理 总结
1, 模拟器全部都是在Tcl的Simulator类中定义的,它提供了一套用做模拟配置和选择用于驱动模拟的事件调度器的接口。该类涉及到Simulator.cc/h以及ns-lib.tcl都有定义。
2, 不知道在Otcl中是否存在这种父类调用子类定义的函数。对于脚本中存在的如下情况有两种解释
//这里在MobileNode里面定义了两个函数实体。
Node/MobileNode instproc getIfq { param0} {
$self instvar ifq_
return $ifq_($param0)
}
Node/MobileNode instproc getPhy { param0} {
$self instvar netif_
return $netif_($param0)
}
set n($i) [$ns node]
set mac($i) [$n($i) getMac 0]
set ifq($i) [$n($i) getIfq 0]
set phy($i) [$n($i) getPhy 0]
在上面的代码中,Node/MobileNode中定义的函数,在node类型的实体进行调用。
问题解决:
父类不可以调用子类中定义的函数。
在Ns-lib.tcl中寻找代码的调用路径,可以发现最终会调用到创建移动节点的语句。
Simulator instproc create-node-instance args {
$self instvar routingAgent_
# DSR is a special case
if {$routingAgent_ == "DSR"} {
set nodeclass [$self set-dsr-nodetype]
} else {
set nodeclass Node/MobileNode
}
return [ev
}
上面的过程是依据simulator类型实体中的参数类型来最终选择了创建移动类型节点。
3 ev
4 定义数组的话。
示例:
$self instvar $ary
Ev
5 在ns中一个成员函数中定义了一个类的成员变量,在其他成员函数中要想使用,还需要重新申明一下这个成员变量,申明的方式与定义的方式相似。都是使用 $self instvar vname
另外,要想在成员函数中使用局部变量,则直接使用 set vname 就可以了。(p38)
这也是在移动节点里面好多地方出现的我疑惑的地方。
Node/MobileNode instproc getIfq { param0} {
$self instvar ifq_
return $ifq_($param0)
}
Node/MobileNode instproc getPhy { param0} {
$self instvar netif_
return $netif_($param0)
}
上面的ifq_,以及netif_就是在其他成员函数中已经定义了的成员变量,在这个成员函数中要使用,仍然需要重新声明一下。
Otcl中成员变量并不是预先定义才在成员函数中使用,而是在成员函数中定义。
6,TCL中,局部变量与全局变量可以同名,两者的作用域的交集为空;局部变量的作用域是它所在的过程的内部,全局变量的作用域则不包括所有过程的内部。这一点和C语言有很大的不同。如果我们想在过程内部引用一个全局变量的值,可以使用global命令。
7,事件调度机制
1, NS是一个事件(event)驱动的模拟器,里面有多种对事件进行模拟调度的调度器(scheduler)。一个调度器的执行过程是这样的:从所有事件中选择发生时刻最早的事件,调用它的Handler函数,把该事件执行完毕,然后从剩余的事件中选择发生时刻最早的事件,调用它的Handler函数执行,如此反复执行。
2, 一个事件(event)是由触发时间(firing time)和Handler函数组成。
3, 定时器,各种定时器都是基于TimerHandler的,它们经常用于agent对象中,但也可以被其他对象使用。里面涉及到定时器长度设置,定时器超时后的执行的事件的指针。(5.4节)定时器有没有被激活,挂起,执行三种状态。
8 Infrastructure多速率机制
多速率的调用流程如下:从左到右为调用过程。
Decr/Incr/RTSFail àARF:CounterEvent(id) à Mac80211EventHandler::CounterHandle(id)
->Mac80211mr中多处以不同的id来调用不同的函数。
9 在infrastructure里面的流程如下:
分成了一个基站,多个接入点,然后在一个接入点之中引入了速率自适应机制来统计其吞吐量,统计的内容包括mac层的各种情况,单对节点的传输情况统计,(目前单对节点的传输情况统计是没有开启)
10 ns里面随机种子流的处理
在ns里面,随机种子产生类为RNG。要想每次产生不同的随机流,需要设置不同的随机种子数。在脚本中也有体现。可以以命令的方式输入。
11 GDB调试
找到了一个GDB调试的技术文档,里面讲述了如何实现设置cc文档中的(要想在tcl文件中使用断点需要安装tcldebug)断点,单步调试,进入调试的方式。设置调试文档的路径。如果不在当前路径下,要设置绝对路径。
12 分组头管理
在NS书籍中5.5节讲述的就是当想在帧中添加一个新的协议时,如果需要添加一个新的帧头的时候该如何操作。
13 deimr里面的定时器处理
继承自handle的各种操作的类。里面可以设置定时开始时间,以及执行时间,然后定时时间超时后执行handle里面的各种函数,里面的各种函数又对应着一些处理定时器操作。
14 节点的配置,在$ns node(set ns [new simulator])前要先用node-config配置节点的一些参数,包括多种层次的性质。后面在ns node的时候就会依照前面的参数来进行节点的创建。
15 好多的TclObject的创建是要基于已创建的模拟对象(Simulator类)。如果直接创建,会出现断错误。
16 tcl中的new 和delete都是tcl脚本语言所写的两个过程。
17 在Otcl对象中,创建了一个SplitObject(所有编译类的基类),会调用其构造函数(init)生成对应的TclObject.在删除该对象时,也同样会调用析构函数来进行删除。(P46)当用户直接在C++中创建一个编译的TclObject,Otcl中的影像对象是不会被创建的。因此,在NS中禁止程序员直接使用C++的new操作来创建编译对象。
18 每个解释类都会通过基于TclClass继承出来的子类进行绑定,而其中的create函数就是由解释类的初始函数(init)中的create-shadow函数来调用进行生成对应的编译类。Lookup查找的参数为变量名。$varname
19 要想在c++脚本中将执行的Otcl命令返回给解释器,可以采用以下方式:
Set str [$objetc command] //command里面会有tcl.ev
20 事件(Event)是由触发时间(firing time)和Handler函数组成。Handler是当事件准备好的激发句柄。
21 Scheduler(调试)这个类中(cc,h)中提供的主要以及常用方法包括:事件链表(Event list)以及对应的一些相应操作(增删改查询),系统时钟获取(clock)。从这个类中会派生出书本上所提的链表类,堆类,日历类。
22 EOT:End of tx
pktRx_:已经接收到的包,在使用捕获模型的时候,如果前一个包还没有接收完,也就是现在不是处于MAC_IDLE(只有处理MAC_IDLE才表明节点现在即不处于接收也不处于发送状态),此时在pktRx_里面保存的就是正在接收的帧。
23 接收函数处理
当接收函数(recv_timer)结束的时候,就会清除在pktRx_里面的内容。如果是数据帧的话,用uptarget_->recv(p,(Handler*) 0)将数据帧上传,其他帧则进行相应的处理。然后状态进入MAC_IDLE.
24 trace中开启了哪层的跟踪就记录哪层的帧接收与发送过程,如果这个帧的接收只到一层就截止了,就只记录这一层的处理,最多到AGT层。
25 在node节点的配置过程中,需要用参数格式为node-config命令这种配置方法来进行配置。在node-config函数中,使用init-vars来对选项与配对参数进行函数调用,然后来实现多种参数的设置。在ns-moblienode.tcl里面有对移动节点配置的具体实现过程。经过配置参数后,生成的节点类型都是一致的。到下次配置前,都是生成同样类型的节点。
26 使用定时器的时候,要注意在start里面的时间,决定了这个定时器所对应的功能是在什么时刻实现,这个是按照标准来进行实现的。
27 Packet类的函数里面的一些方法简介:alloc()方法通常是创建新的分组作为一个辅助函数(support function)。它试图在使用C++的new操作分配失败时在空闲链表中定位一个旧的分组。Free()方法通过将一个分组返回到空表中来释放这个分组,分组决不会返回给系统的内存分配器中,取而代之的是,在packet::free()被调用的时候,它们存储在一个空表中。成员copy()创建一个分组的新的,同样的拷贝,除了一个唯一的uid_域不同。
28 Cmutrace中所有的ACK.RTS,CTS帧的ch->uid()都是设置为0.而其他上层业务(比如说cbr),则是帧的uid会依次增加。