ns-2与TCP拥塞模拟 之四 ns-2仿真脚本中的元素
一般的网络仿真脚本,需要有模拟器类(Simulator类)、事件、节点、链路、代理、应用等元素。
在ns-2中,每个仿真过程都需要一个类对整个过程进行控制和管理,这个类就是模拟器类(Simulator类)。整个模拟过程从创建一个模拟器类对象开始,通过调用这个对象的各种过程实现:创建节点、构建拓扑结构图、对模拟的各方面进行配置、定义事件、根据定义的事件模拟整个网络的运行等。
对应的脚本语句如下(通常都在脚本的开头部分):
set ns [new Simulator] ;#新建一个Simulator对象(如要使用这个ns对象,写作$ns)
模拟器类对象创建的同时,还会完成以下相关的初始化操作:
(1)初始化分组格式(调用create_packetformat);
(2)创建一个事件调度器(scheduler,默认为calendar scheduler);
(3)创建一个空代理(null agent)。
目前ns-2支持4种事件调度器:
(1)链表式(linked-list)调度器;
(2)堆式(heap)调度器,适用于大量事件的情况;
(3)时间队列式(calendar)调度器,这个是默认的事件调度器;
(4)实时(real-time)调度器。
常用的语句有如下4种:
$ns halt ;#停止或暂停调度器
$ns run ;#启动调度器
$ns at <time> <event> ;#在一个特定时间<time>调度一个事件<event>
$ns cancel <event> ;#取消<event>事件,将事件从准备好的调度器中删除
这样,就很容易理解示例1中“$ns at 5.0 "finish"”、“$ns run”这样的语句了。
根据网络节点之间通信方式的不同,分组的传输方式有两类:单播(unicast)和多播(multicast),在ns-2中对应单播节点和多播节点。以下仅介绍最相关的单播节点。
一个单播节点本质上是一个组合对象,主要包括两个Tcl对象:地址分类器(address classifier)和端口分类器(port classifier)。节点主要完成以下操作。
(1)每种不同的分类器分别查看报文的一个特殊部分,再依次转发报文;
(2)地址分类器的主要功能是用来判断报文的地址,转发报文到下一个接收器;
(3)端口分类器的主要功能是匹配报文的目的端口,将报文传递给相应的代理对象。
节点相关的命令比较多,下面只介绍脚本中最常用的几个:
set nodename [$ns node] ; #创建了一个单播节点nodename
$node attach <agent><optional:port_num> ;#将<agent>绑定到节点上
$node detach <agent> <null_agent> ;#从节点上撤除代理,然后在这个端口上绑定一个空代理
上述的attach绑定命令中,如果用户没有指定端口号<port_num>,节点将自动为代理分配一个端口号,并将该代理绑定到节点上。
ns-2的链路(link)同时实现了物理层、数据链路层及部分网络层的功能,按通信方式可以分为单工、半双工和全双工三种方式。
ns-2中有多种连接器,每种连接器执行不同的功能。一条链路是由一系列的连接器(connector)逐步构成的。组成链路的队列(Queues)、延迟链路对象(DelayLink)和TTL检查器对象(TTLChecker)都是连接器类(Connector类)的子类。以下简要说明之。
(1)队列对象(Queues):用来存放或丢弃分组的缓冲区。不同的队列类型拥有不同的队列管理及分组调度机制。目前ns-2支持的队列类型有以下4种:
①丢弃队尾(Drop-tail)的先进先出队列(最常见类型);
②RED缓冲区管理;
③CBQ(包括优先级和轮换调度);
④各种公平队列(FQ、SFQ、DRR)。
(2)延迟链路对象(DelayLink):主要用来模拟链路延迟和带宽特性的对象。
(3)TTL检查器对象(TTLChecker):代表了报文的生存期,是报文中的一个域。TTL通常表示报文在被丢弃前最多能经过的路由器个数。当记数到0时,路由器决定丢弃该报文,并发送一个ICMP报文给最初的发送者。
脚本通常使用双向链路,实际上一条双向链路由两条方向不同的单向链路构成。以下仅列举常用的两种命令(可以参考示例1中的语句)。
#创建一条node1到node2的双向链路,并且定义一些特性
$ns duplex-link <node1> <node2><bandwidth> <delay> <queue_type>
#设置链路的属性,主要包括方向、颜色等,用于Nam的动画显示
$ns duplex-link-op <node1> <node2><option> <args>
代理(Agent)用于构建和销毁网络层的分组报文,是网络层分组报文的起点和终点。同时,代理还可以实现各种不同层的网络协议。
典型的代理是ns-2中的Agent/TCP和Agent/UDP,分别实现了传输层的两个重要协议TCP和UDP。ns-2支持的各种协议代理都是Agent类的子类。字符“/”作为分隔符的类命名规则表示OTcl类中的继承关系。在ns-2中,所有的OTcl类都是从SplitObject类继承来的。
Agent类是由C++和OTcl共同实现的。对于代理的使用者来说,需要知道使用此特定代理的OTcl Agent中的内部变量。例如,OTcl中Agent/UDP类的内部变量packetSize_实际上是与C++中UDP Agent类中的size_属性绑定在一起的,这样只需创建一个Agent/UDP对象,并使用set命令设置packetSize_的值,模拟器就自动将相应的值赋给C++ Agent类中的size_属性。
(1)Agent/UDP。Agent/UDP类是Agent类的一个子类,模拟了UDP协议的主要功能。
ns-2创建和设置UDP代理可以分为以下4步:
①创建一个Agent/UDP对象,并绑定到相应的节点上作为报文分组的发送器;
②设置Agent/UDP的部分内部变量;
③创建一个Agent/Null对象,并绑定到相应的节点作为报文分组的接收器;
④在发送代理和接收代理之间创建连接(connect)。
具体的脚本代码可以参考以下的OTcl代码示例。
#创建UDP代理(假设节点n0和n1、模拟器对象ns已经建立)
set udp [new Agent/UDP] ;#创建一个UDP Agent
$ns attach-agent $n0 $udp ;#将UDP Agent绑定到节点n0上,作为报文的发送器
$udp set packetSize_ 536 ;#设置UDP数据分组大小为536B
set null [new Agent/Null] ;#创建一个空代理对象null,作为分组的接收器
$ns attach-agent $n1 $null ;#将null绑定到节点n1上
$ns connect $udp $null ;#在两个Agent之间建立连接
Agent/Null是空代理类,它通常和UDP代理配合使用,作为数据的接收器。空代理接收到报文分组后,直接丢弃,不做其他处理。这一点也符合UDP协议不要求接收端对报文分组做出任何响应的规范。
(2)Agent/TCP。ns-2中有两类TCP代理:单向代理(one-way agent)和双向代理(two-way agent)。单向代理包括一系列TCP发送器(实现了不同的拥塞算法或者差错控制算法)和接收器(TCPSink),双向代理本身既可以作为发送者也可以作为接收者。
ns-2创建和设置TCP代理可以分为以下4步:
①创建一个Agent/TCP对象,作为报文分组的发送器;
②设置Agent/TCP对象的部分内部变量;
③创建一个Agent/TCPSink对象,作为报文分组的接收器;
④在发送器和接收器之间创建连接(connect)。
具体代码以TCP的单向代理Agent/TCP(Tahoe算法)和Agent/TCPSink为例,OTcl代码如下。
#创建TCP代理(假设节点n0和n1,以及模拟器对象ns已经建立)
set tcp [new Agent/TCP] ;#创建一个TCP发送代理对象tcp
$ns attach-agent $n0 $tcp ;#把这个TCP发送代理绑定在节点n0上
$tcp set fid_ 1 ;#设置IP层数据流fid
$tcp set window_ 20 ;#设置TCP滑动窗口的大小为20
set sink [new Agent/TCPSink] ;#创建分组的接收代理对象
$ns attach-agent $n1 $sink ;#将接收器sink代理绑定到节点n1上
$ns connect $tcp $sink ;#在两个Agent之间建立连接
(3)其他协议Agent。ns-2中除了支持UDP、TCP协议外,还支持许多其他的协议,这些协议都是通过继承Agent来实现的,如ICMP(Internet Control Message Protocol)中的Agent/Ping等。
(4)相关的命令。在这里不再赘述已经举例的命令,仅简单举些例子。
$agent port ;#返回绑定的agent端口号
$agent dst-port ;#返回目标端口号
$agent attach-app <s_type> ;#在agent上绑定一个类型为<s_type>应用
$agent attach-trace <file> ;#将<file>绑定到agent上,允许Nam跟踪Agent的事件
在ns-2中,业务流是由应用层产生的。Application类是OTcl中应用层程序的基类,提供了应用层程序的一些行为的基本原型。应用层程序构建在传输层之上,通过在传输层Agent内部预定义一些成员函数来模拟socketAPI的功能。应用可以分为两大类:流量产生器(traffic generator)和应用模拟器(simulated application)。流量产生器一般构建在UDP代理之上,应用模拟器则建构在TCP代理之上。
(1)流量产生器。
网络中的业务流是随机产生的,为此,ns-2中创建了各种不同的概率模型来模拟实际网络中的业务流。在ns-2中,实现了4种流量产生器。
①指数分布流量产生器,在OTcl中对应的类名为Application/Traffic/Exponential。该流量产生器有一个“On/Off”开关。在“On”状态,流量产生器以固定的速率发送报文分组;在“Off”状态,停止发送报文分组;“On”和“Off”两种状态的时间长度符合指数分布。
②泊松分布流量产生器,在OTcl中对应的类名为Application/Traffic/Pareto。
③固定比特流量产生器,在OTcl中对应的类名为Application/Traffic/CBR。该流量产生器按照一个固定的速率产生业务流,分组的长度为一常数值。
④Trace文件流量产生器,在OTcl中对应的类名为Application/Traffic/Trace。
(2)应用模拟器。
①FTP应用模拟器,对应的OTcl类为Application/FTP,主要用来模拟大量数据的传送。
②Telnet应用模拟器,对应的OTcl类为Application/TELNET。
系列1的示例脚本中,使用CBR应用驱动了UDP数据传输,使用FTP驱动了TCP数据传输,因此相应的代码在此不再赘述。