NED语言.docx
《NED语言.docx》由会员分享,可在线阅读,更多相关《NED语言.docx(30页珍藏版)》请在冰豆网上搜索。
NED语言
第三章NED语言
3.1NED概述
模型的拓扑结构可以使用NED语言详细描述.NED语言方便了一个网络的模块描述.这意味着一个网络描述包括许多组件描述(通道,简单/复合模块类型).网络描述的通道,简单模块和复合模块可以在另一个网络描述中重复使用.
包含网络拓扑模型描述的文件通常以.ned为后缀名,它可以动态地载入仿真程序或由NED编译器翻译为C++代码,并链接到可执行文件中.
EBNF语言描述见附录[14].
3.1.1一个NED描述组件
一个NED描述包括以下组件,以任意数据或顺序:
导入命令
定义信道
简单和复合模块定义
网络定义
3.1.2保留字
网络描述必须注意不能使用保留字命名.NED语言的保留字有:
Import,channel,endchannel,simple,endsimple,module,endmodule,error,delay,datarate,const,parameters,gates,submodules,connections,gatesizes,if,for,do,endfor,network,endnetwork,nocheck,ref,ancestor,true,false,like,input,numeric,string,bool,char,xml,xmldoc.
3.1.3标识符
标识符是模块名,信道,网络,子模块,参数,网关,信道属性和函数.
标识符必须由英文字母表(a-z,A-Z),数字(0-9)和下划线”_”.可以由字母或下划线开始.如果你想以数据开头的话,在前面加个下划线,例如_3Com.
如果标识符由几个单词组成时,按惯例大写每个单词的首字母,建议大写模块,信道,网络等标识符的首字母,小写参数,门,子模块等标识符的首字母.下划线很少使用.
3.1.4大小写敏感
网络描述和所有的标识符是大小写敏感的.例如,TCP和Tcp是两个不同的命名.
3.1.5注释
注释可以放在NED文件的任何地方,跟C++语法类似:
由双斜线开始”//”,一直延续到这行的结尾,注释被NED编译器忽略.
NED注释可以用于产生文档,像JavaDoc和Doxygen.此特性在第[11]章描述.
3.2导入命令
导入命令是用于从其他网络描述文件中导入描述.在导入一个网络描述后,可以使用组件(信道,简单/复合模块类型定义.
一个文件被导入,仅仅是其声明被使用,当父文件被编译时,被导入的文件并不会被编译,即必须编译和链接每个网络描述文件,而不仅仅是最上一层的文件.
可以指定有无.ned扩展名的文件名.也能在文件中中包括路程,或使用NED编译器的命令行选项-I指定被导入的文件.
例如:
import"ethernet";//importsethernet.ned
3.3信道定义
信道定义是详细说明链接类型的特征(属性).信道名可用于后面的NED描述来创建这些参数的连接.语法:
channelChannelName
//...
endchannel
在信道描述中,三个可选属性可以被赋值:
延迟,比特错误率,和数据速率.延迟是传播延迟,以仿真秒为单位.比特错误率是比特数据传输时发生错误的概率;数据速率是指信息的带宽(比特/秒),用于计算数据包的传输时间,三个属性可以以任何顺序出现,所赋值应为常数.
例如:
channelLeasedLine
delay0.0018//sec
error1e-8
datarate128000//bit/sec
endchannel
3.4简单模块定义
简单模块是其他(复合)模块的基本构建块.简单模块类型由名称标识.惯例是,模块名以大定字母开头.
简单模块通过声明参数和门来定义.简单模块由发下语法来声明:
simpleSimpleModuleName
parameters:
//...
gates:
//...
endsimple
3.4.1简单模块参数
参数是属于模块的变量.简单模块参数可以被简单模块算法使用.例如,TrafficGen模块可能有参数numOfMessages,该参数决定多少消息将被产生.
参数由名称标识.按惯例,参数名以小写字母开头.
Parameters域列出其名字即可声明参数.参数类型可以被指定为:
numeric,numericconst(或simplyconst),bool,string,或xml,numeric为缺省类型.
例如:
simpleTrafficGen
parameters:
interarrivalTime,
numOfMessages:
const,
address:
string;
gates:
//...
endsimple
参数可以由NED指定(当模块用于大的复合模块的构建块时)或从配置文件omnetpp.ini,配置文件在第[8]章详细描述.
随机参数和常数truncnormal(2,0.8),当每次从简单模块(C++代码)读参数时,剪切2.0正态分布和标准差为0.8,返回一个新随机数.例如,这用于指定产生包或作业的间隔时间.
Numeric参数可以被设置从统一的分布或各种不同的分布返回随机数.例如,设置一个参数为
如果想初始化参数值来被随机选择,但在后面并不改变.可以通过声明其为常量.常量参数仅在仿真开始时计算,然后设置为一个常数值.
推荐标记每一个参数为常量,除非想要使用随机数的特性.
XML参数
许多模块需要描述比简单模块参数更复杂的输入.然后输入这些参数至一个外部配置文件,然后让模块读文件,处理文件.在一串参数中通过文件到达模块.
最近XML越来越成为一种配置文件的标准格式,可以在XML中描述配置.从3.0版的OMNet++就包含了支持XML配置文件.
OMNet++包括了XML解释器(LibXML,Expat,等),读取和验证文件类型定义的文件(如果XML文档包括一个DOCTYPE),缓存文件(如果多个模块引用,只加载一次),通过一个XPath子集符号来选择文档的一部分,在类DOM的对象树中显示内容.
这种机制可以通过NED参数类型xml和xmldoc()操作访问.可以通过xmldoc()操作指定xml类型模块参数至一个具体的XML文件(或XML内的一个元素).可以从NED和omnetpp.ini指定xml参数.
3.4.2简单模块门
门是模块的链接点.模块间起点和终点就是门.OMNet++支持单向链接,因此有输入和输出门.消息通过输出门发送,输入门接收.
门由名称标识,按惯例,门名以小写字母开头.
支持门向量:
一个门向量包含多个单一门.
模块描述的gates域:
列出其名字即可声明门.空的方括号对[]表示门向量.向量的元素从0开始编号.
例:
simpleNetworkInterface
parameters:
//...
gates:
in:
fromPort,fromHigherLayer;
out:
toPort,toHigherLayer;
endsimple
simpleRoutingUnit
parameters:
//...
gates:
in:
output[];
out:
input[];
endsimple
门向量的大小在被用作复合模块的部件时给定.因此,每个模块实例的门向量大小不同.
3.5复合模块定义
复合模块由一个或多个子模块组成.任何模块类型(简单或复合模块)都可被用作子模块.复合模块的定义类似简单模块,也有gates和parameters域,可用于任何使用简单模块的地方.
可以把复合模块看成是”纸板盒”,帮助你组织仿真模型,产生结构.没有活动行为与复合模块相联—他们简单地组合模块成更大的部件,可用于作为一个模型或其他复合模块的部件.
按惯例,模块类型名(也包括复合模块类型名)以大写字母开头.
子模块可以使用复合模块的参数.他们彼此相连或与复合模块本身相联.
复合模块的定义类似于简单模块的定义:
有gates域和parameters域,它还有两附加的域submodules和connections.
复合模块的语法如下:
moduleCompoundModule
parameters:
//...
gates:
//...
submodules:
//...
connections:
//...
endmodule
所有的域(parameters,gates,submodules,connections)都是可选的.
3.5.1复合模块和门
复合模块的参数和门与3.4.1与3.4.2中所描述的简单模块的参数和门一样定义使用.
通常复合模块参数是用于传递给子模块,对子模块的参数初始化的.
参数也可以用于描述复合模块的内部结构,子模块的数目,门向量的林小可借助于复合模块的参数来指定,参数也用于定义复合模块的内部连接.例如,Router复合模块有若干端口,端口数由参数numOfPorts指定.
影响复合模块内部结构的参数必须声明为const,保证每次访问该参数都返回相同值.否则,如果参数分配随机值,在构建复合模块的内部时每次访问参数都是不同的值,这绝对不是所表达的意思.
例:
moduleRouter
parameters:
packetsPerSecond:
numeric,
bufferSize:
numeric,
numOfPorts:
const;
gates:
in:
inputPort[];
out:
outputPort[];
submodules:
//...
connections:
//...
endmodule
3.5.2子模块
在复合模块声明的submodules:
域定义子模块.标识子模块的名称通常以小写字母开头.
子模块是模块类型(简单/复合,之间没有区别)的实体.子模块类型对NED编译器必须是可知的,即模块类型必须在该NED文件中定义过或者从其他文件中导入.
可以定义子模块向量,其大小可由某个参数值决定.
当定义子模块时,可以为其参数赋值,如果相应的模块类型有门向量,则必须指定其大小.
例:
moduleCompoundModule
//...
submodules:
submodule1:
ModuleType1
parameters:
//...
gatesizes:
//...
submodule2:
ModuleType2
parameters:
//...
gatesizes:
//...
endmodule
模块向量
可以创建一个子模块(一个模块向量)数组.这是通过模块类型名后面的中括号这间的表达式完成的.这个表达式可以引用模块参数.允许模块数为0.
例
moduleCompoundModule
parameters:
size:
const;
submodules:
submod1:
Node[3]
//...
submod2:
Node[size]
//...
submod3:
Node[2*size+1]
//...
endmodule
3.5.3作为参数的子模块类型
有时将子模块类型作为参数非常方便,因此可以很方便地插入任何模块.
例如,假定仿真学习的目的是比较不同的路由算法,将参与比较的路由算法设计为简单模块:
DistVecRoutingNode,AntNetRouting1Node,AntNetRouting2Node等,同时还创建了为复合模块的网络拓扑RoutingTestNetwork,这些将用来测试路由算法.目前RoutingTestNetwork使用DistVecRoutingNode进行的硬编码(所有的子模块都是这类型),但是如果切换到其他路由算法则比较麻烦.
NED可以添加一个字符串参数,比如routingNodeType到复合模块RoutingTestNetwork,子模块不再是某个固定的类型,其类型包含在routingNodeType参数中.现在用户可以自由地从字符串常量"DistVecRoutingNode","AntNetRouting1Node"或"AntNetRouting2Node"中选择,网络将使用选择的路由算法.
如果指定一个错误的值,比如"FooBarRoutingNode",但用户没有实现"FooBarRoutingNode"模块,那么仿真开始时得到一个运行时间错误:
moduletypedefinitionnotfound.
在RoutingTestNetwork模块内部指定参数值和连接路由模块的门.为了提供一些类型安全等级NED要保证没有拼错的参数或门名称,并正确地使用.为了完成这些检验,NED需要一些帮助:
必须命名一个现存的模块类型(比如RoutingNode),并保证运行的所有模块中指定的routingNodeTyp参数至少与RoutingNode模块的参数和门是相同的.
[以上的方法,与面向对象语言中的多态性类似—RoutingNode类似于基类,DistVecRoutingNode和AntNetRouting1Node类似于派生类,routingNodeType参数类似指向基类的指针,可以向下指定类型.]
以上的都通过like关键字完成.语法如下:
moduleRoutingTestNetwork
parameters:
routingNodeType:
string;//shouldholdthenameofanexistingmoduletype
gates:
//...
submodules:
node1:
routingNodeTypelikeRoutingNode;
node2:
routingNodeTypelikeRoutingNode;
//...
connectionsnocheck:
node1.out0-->node2.in0;
//...
endmodule
RoutingNode模块类型不必用C++语言实现,因为并不创建其实体,仅用于检查NED文件的正确性.
一方面,实际模块类型将被替代(如DistVecRoutingNode,AntNetRouting1Node等),不需要在NED文件中声明.
like短语可以用于创建模块族,服务类似的目的,实现相同的接口(相同的门和参数),在NED文件中交替使用.
3.5.4指定子模块参数的值
如果子模块的模块类型声明中含有参数,则可以在子模块声明的parameters域给其赋值,所赋值可以使用一个常量(比如42或"www.foo.org"),各种参数(常见的为复合模块参数),或任意表达式.
parameters域并不强制要求给每个参数赋值.未赋值的参数可以在运行时得到值,仿真器会交互地提示输入.当然为了灵活性,通常不在NED文件中为参数赋值,而是留给配置文件omnetpp.ini,这样改变起来更方便.例如:
moduleCompoundModule
parameters:
param1:
numeric,
param2:
numeric,
useParam1:
bool;
submodules:
submodule1:
Node
parameters:
p1=10,
p2=param1+param2,
p3=useParam1==true?
param1:
param2;
//...
endmodule
表达式语法非常类似于C.表达式可以包含常量和定义的复合模块.参数通过值或引用传递.后者的意思为每次访问表达式值时,是在运行时计算(比如从简单模块代码),为仿真打开可能感兴趣的.可以用语法submodule.parametername(或submodule[index].Parametername)来引用已经定义的子模块参数.在[3.7]详细描述了表达式.
关键字input
当一个参数并没有从NED文件和配置文件(omnetpp.ini)内获得值,在仿真开始时,将提示用户输入其值.如果计划使用交互式提示,可以指定提示文字和缺省值.
语法如下:
parameters:
numCPUs=input(10,"Numberofprocessors?
"),//defaultvalue,prompt
processingTime=input(10ms),//prompttext
cacheSize=input;
第三个形式实际上是省略参数,但是可以使用其明确你不想从NED文件中获得值.
3.5.5定义子模块门向量的大小
使用gatesizes关键字来定义门向量的大小.门向量大小可以是常量,参数或表达式.
例如:
simpleNode
gates:
in:
inputs[];
out:
outputs[];
endsimple
moduleCompoundModule
parameters:
numPorts:
const;
submodules:
node1:
Node
gatesizes:
//在这个地方指定了该节点的门大小只能是2
inputs[2],outputs[2];
node2:
Node
gatesizes:
inputs[numPorts],outputs[numPorts];
//...
endmodule
gatesizes并不是强制性的.如果一个门向量缺省gatesizes那么其大小为0.
省略gatesizes的一个原因是后面在连接域将使用gate++符号(新的门扩展的门向量).
3.5.6条件参数和gatesizes域
在一个子模块定义中可以存在多个参数和gatesizes域,它们中每个都有状态标志.
例:
moduleChain
parameters:
count:
const;
submodules:
node:
Node[count]
parameters:
position="middle";
parametersifindex==0:
position="beginning";
parametersifindex==count-1:
position="end";
gatesizes:
in[2],out[2];
gatesizesifindex==0||index==count-1:
in[1],in[1];
connections:
//...
endmodule
如果状态是不相交的,且参数值或门大小被定义两次,那么最后一次定义的有效,覆盖前面定义的.因此,缺省值将第一个在域中出现.
3.5.7连接
复合模块定义指定了复合模块的门如何与其直接子模块相连.
可以连接两个子模块或一个子模块与其上层的复合模块.(也可以在内部连接两个复合模块的门,但是很少用).这表示NED不允许跨越多个层次级别进行连接—这限制了复合模型实现自我包含,因此促进了可用性.必须遵守门方向,即不能连接两个输出门或两个输入门.
仅支持一对一的连接,于是门只能被用于某一个方向的链接.一对多或者多对一的链接可以利用复制消息或者合并消息流的简单模块实现,其基本原理是这种扇入或者扇出无论在模型的什么地方发生总是与一些处理过程相联系的.
连接在复合模块定义的onnections:
域指定,所列出的所有链接用分号隔开.
例:
moduleCompoundModule
parameters:
//...
gates:
//...
submodules:
//...
connections:
node1.output-->node2.input;
node1.input<--node2.output;
//...
endmodule
源门是一子模块的输出门或复合模块的输入门,目的门可以是一子模块的输入门或复合模块的输出门.箭头可以是左-右或右-左指向.
符号gate++可以扩展一个新门的门向量,在前面的gatesizes不需要预先声明其大小.这个特性非常有利于连接一个网络的节点.
simpleNode
gates:
in:
in[];
out:
out[];
endsimple
moduleSmallNet
submodules:
node:
Node[6];
connections:
node[0].out++-->node[1].in++;
node[0].in++<--node[1].out++;
node[1].out++-->node[2].in++;
node[1].in++<--node[2].out++;
node[1].out++-->node[4].in++;
node[1].in++<--node[4].out++;
node[3].out++-->node[4].in++;
node[3].in++<--node[4].out++;
node[4].out++-->node[5].in++;
node[4].in++<--node[5].out++;
endmodule
一个连接:
∙可能有属性(延迟,比特错误率或数据速率)或使用一个命名信道;
∙内部会出现一个for-loop循环(来创建多个连接);
∙可能会有条件.
这些连接类型在以下部分描述.
单连接和信道
如果不指定一个信道,连接将没有传播延迟,没有传输延迟,也没有比特错误率:
node1.outGate-->node2.inGate;
可以由名称指定一个信道:
node1.outGate-->Fiber-->node2.inGate;
在这种情况下NED源必须包含信道定义.
也可以直接指定信道参数:
node1.outGate-->error1e-9delay0.001-->node2.inGate;
参数可以被缺省,也可以以任何顺序出现.
循环连接
如果使用子模块或门向量,可以用一条语句声明多个连接.它们被称为multiple或loopconnection.
循环链接由for语句创建.
fori=0..4do
node1.outGate[i]-->node2[i].inGate
endfor;
以上的循环链接结果可以用下图描述.
Figure:
Loopconnection
在一个子for语句主体中可以有多个链接,用分号隔开.
在for语句中通过指定多个索引可以创建嵌套循环,第一变量形成最外层的循环.
fori=0..4,j=0..4do
//...
endfor;
也可以在并发索引的上下界表达式里使用一个索引:
fori=0..3,j=i+1..4do
//...
endfor;
条件连接
创建有条件的链接可以使用if关键