1.1 OMNeT++为何物?
OMNeT++是一款面向对象的离散事件网络模拟器,可以实现的功能如下:
.无线电通信网络信道模拟
• 协议模拟
• 模拟队列网络
• 模拟多处理器和其他分布式硬件系统
• 确认硬件结构
• 测定复杂软件系统多方面的性能
• 模拟其他的任何一种合适的离散事件系统
一款 OMNeT++模拟器包括一些分层次的嵌入式模型,嵌入式模型的深度是无限的,即允许用
户在模拟环境中绘制实际系统的逻辑结构.各模块通过信息的传输进 行通信,其信息可以包
括任意复杂的数据结构,各模块均可以通过门或者线路直接发送信息给目标点或者也可以通
过预先的路径进行传输.
各个模块可以有自己的参数集,参数集可以被用于定制模块行为,或者可以用于确定模拟拓
扑图的参数.
模拟网络最底层的模块可以嵌入行为,这些模块被称为基本模块,它可以利用模拟器的库函
数在 C++进行编程.
OMNeT ++模拟器可以在根据不同的目的来改变用户接口: 调试、实例和批量执行。高级用户
的接口可以把模块透明的交给用户,即允许控制模拟器执行以及可以通过改变模块中的变量
/对象来干涉模拟器的执行,这在开发 /调试模拟器工程师非常有用的,用户接口也促进了
模块工作的实现。
模拟器的接口和工具都非常轻便:目前得知它可以在 Windows和各种 UNIX操作系统下利用
c++进行编译。
OMNeT ++还支持分布式并行仿真,OMNeT++可以利用多种机制来进行用于几个并联的分布式
模拟器之间的通信仿真,比如 MPI和指定的通道。这种并行仿真算法 可以很容易的进行扩
展,也很容易加入新的模块。各个模块不必须要特定的结构来并行运行,这只是一个配置的
问题。OMNeT++甚至还可以被用于并行模拟仿真算法的多层次描述,因为模拟器可以在 GUI
下并行运行,这种 GUI为运行过程提供了详细的反馈。
OMNEST是 OMNeT++的一个商业版本,OMNeT++只在学术和非盈利性活动免费,在进行商业性
研究时需要从 Global公司获得 OMNEST许可证。
1.2本手册的组织结构
本手册的组织结构如下:
第[1],[2]章包括介绍性的资料
第二组章节,[3],[4],和[6]是编程向导.他们提出了 NED语言,仿真的概念和他们在 OMNet++
中的执行,解释了如何写一个简单的模块并描述了类库.
第[9],[11]进一步阐述了主题,通过解释如何定制网络图,从产生的方件中,如何写 NED源代
码注释.
[7],[8],[10]处理了实际的问题,比如建立,运行仿真器,分析结果,提出了 OMNet++工具提
供的所支持的任务.
[12]章支持分布式执行
最后[13]解释了 OMNet++内部结构
附录[14]提供了参考的 NED语言
第二章 概述
2.1 建模的概念
OMNeT++为用户提供了有效的用于描述实际系统结构的工具。一些主要的特征表现如下:
(1) 分层次嵌入式模块
(2) 各模块以模块类型分类
(3) 模块之间通过信号在通道上的传输进行通信
(4) 灵活的模块参数
(5)拓扑描述语言
2.1.1 分层次的各模块
OMNeT ++模块包括分层次的嵌入式模块,这些模块通过彼此之间传输消息来进行通信。
OMNeT++经常被描述成网络结构,最顶层的模块称为系统模块,系统模块包括子模块,其子
模块还可以包括本身的子模块,模块嵌入的深度是没有限制的,它允许用户在模块结构中根
据实际系统来绘制逻辑结构图。
模块结构利用 OMNeT++ 的 NED语言进行描述。
包含子模块的模块称为混合模块,与在层次模块最底层的简单模块相反.在模型中简单模块
包括算法.使用 OMNet++的仿真类库, 用户通过 C++执行简单模块.
2.1.2 模块类型
基本模块和复合模块都是模块类型的实例。在描述模块时,用户定义了模块类型;这些模块类
型的实例用于组成更复杂的模块类型.最终,用户创建系统模块为前面所定义的模块类型的
实例;所有的网络模块都被实例为系统模块的子模块和子子模块.
当一种模块类型被用作一个建立块,则不管是基本模块和复合模块都没有区别。,这使用户
在不影响现有的模块类型用户的条件下,可以将一个基本模块分割成多个基本模块嵌入至一
个复合模块,或者相反,集成一个复合模块的功能为单个基本模块.
模块类型可以存储于文件中,并且可以保证与它实际的用法分别开来,这就意味着用户可以
通过存在的模块类型进行分组,也可以创造组成库,这一特征在后面第[8]章将会给出详细
的介绍。
2.1.3 消息、门、链路
模块之间通过交换消息进行通信,在一个实际的模拟器中,可以使用计算机网络中的帧和包
来替代消息,在队列网络中可以用作业或消费者来替代消息,或者其他的移动实体类型。消息
可以包括任意复杂的数据结构.基本模块可以通过门或连接,直接发消息至目的地,也可以通
过预先确定的路径发送消息.
当模块接收一个消息时,模块的”本地仿真时间”前进.消息能够从其他的模块或从相同的
模块抵达(自身的消息用于执行定时器).
门是模块的输入/输出接口,消息通过输出门发送出去,通过输入门进行接收。
每个连接(也称之为链接)被创建成一个单一层次的模块层次:在一个复合模块中,可以连接
相应的两个子模块的门,或一个子模块的门和一个复合模块的门.
子模块彼此连接 子模块连接父模块
由于模块的层次结构,典型的消息传输是通过一系列的连接,开始和到达都在简单模块中.这
些连接系列从简单模块到简单模块,被称之为路由.在模块中的复合模块可以看成”纸盒”,
在其内部和外部世界之间透明地转播消息.
2.1.4 包输出的建模
连接被分配三个参数,用于方便通信网络的建模,但是在其他的建模中也是有用的:传播延迟,
比特错误率和数据率,所有三个都是可选的.对每个连接都可以分别指定链接参数,或者定义
链接类型,在整个网络中使用.
传播延迟是指由于通过通道传输,消息抵达的延迟的时间数.
位错误率指一比特数据被错误传输的概率,允许简单的噪音通过建模.
数据率 bit/second,用于计算传输一个包的时间.
当数据率在使用的时候,模块中发送的消息对就于传输的第一个比特,消息接收对应于接收
的最后一个比特.这个模块不是总是可用的,例如,类似于 Token环和 FDDI协议,不等待结构
到达其实体,而是开始重复它的第一个比特,然后他们到达—换句话说,”流量通过”结构,
仅存在很少的延迟.如果你想模块化这些网络,OMNet++的数据率建模特征将不能使用.
2.1.5 参数表
模块可以有参数表,参数表可以在 NED文件中指定,也可以在 omnetpp.ini中进行配置。
参数可以用于定制简单模块行为,也可以参数化模型拓扑.
参数可以是 string, numeric或 boolean值,或者也可以包括 XML数据等.numeric值包含使
用其他参数的表达式以及调用 C函数,不同分类的随机变量,和由用户交互输入的值.
Numeric值的参数可以以灵活的方式构成拓扑结构.在一个复合模块中,其参数定义子模块
数,门数,和形成内部连接的方法.
2.1.6 拓扑描述方法
用户使用 NED描述语言定义了模型的结构.NED语言将在第[3]章讨论.
2.2 设计算法
一个模型的简单模块包括像 C++函数的算法.使用设计语言的灵活性和能力,支持 OMNet++的
仿真类库.仿真程序员可以选择事件驱动或进程式的描述,可以自由使用面向对象概念(继承,
多态等)和设计模式来扩展仿真功能.
仿真对象(消息,模块,队列等)由 C++类表示.他们被设计成有效地共同工作,创建一个有力
的仿真设计结构.以下的类是仿真类库中的一部分:
modules, gates, connections etc.
parameters ( 界限)
messages
container classes (e.g. queue, array)
data collection classes
statistic and distribution estimation classes (histograms(柱状物), P2 algorithm
for calculating quantiles etc.)
transient (短暂的) detection and result accuracy(精确性) detection classes .
这些类是一个特殊的工具,允许运行的仿真对象的移动,显示他们的信息如,名称,类名,状态
变量或内容.这个特点使他可能创建一个仿真 GUI,其中所有的仿真内在都是可见的.
2.3 使用 OMNeT++
2.3.1 新建运行模拟器
这节提供了在实践中观察 OMNet++的工作:比如讨论了模型文件,编译,运行仿真器等问题.
一个 OMNet++模型包括以下几部分:
NED语言拓扑描述(.ned文件),其使用参数,门等描述了模块结构.NED文件可以使用任何文
本编辑器或 GNED图形化编辑器来编写.
消息定义(.msg文件).可以定义变量消息类型,以及在其上添加数据文件.OMNet++将消息定
义转化成完全的 C++类.
简单模块源.他们是 C++文件,.h或.cc后缀.
仿真系统提供了以下的组件:
仿真内核.这包含用 C++编写的管理仿真和仿真类库的代码,编译使其形成一个库文件(扩展
名为.a或.lib).
用户接口.OMNet++用户接口在仿真执行的时候使用,用于方便调试,演示或者批处理仿真的
执行.有许多用 C++编写的用户接口, 编译使其形成一个库文件(扩展名为.a或.lib).
从以上的组件中创建仿真程序.首先,使用 opp_msgc.程序将.msg文件转化成 C++代码.然后
编译所有的 C++源文件,链接仿真内核和用户的接口库,形成一个仿真可执行文件.NED文件
可以转化成 C++文件(使用 nedtool)进行链接,当仿真程序开始执行时,也可在他们原始的文
本里动态加载.
仿真器的运行和结果分析
仿真执行文件是一个单独的程序,因此它可以运行在没有 OMNet++,或正在显示模型文件的
其他机器上.当程序开始执行,它读一个配置文件(通常为 omnetpp.ini)这个文件包括设置,
它控制了仿真如何被执行,模型参数的值,等.配置文件也指定了许多仿真运行;在最简单的
情况下,他们将被仿真程序接连地执行.
仿真的输出写入一个数据文件:输出向量文件,输出标量文件,以及用户自己的输出文
件.OMNet++提供一个 GUI工具 Plove来查看,制出输出向量文件的内容图.它不希望仅仅使用
OMNet++来处理结果文件:输出文件的格式是一个文本文件,可以读进数学包像 Matlab或
Octave,或导入电子数据表像 OpenOffice Calc, Gnumeric 或 MS Excel(许多预处理将需要
sed,awk,perl,这将在后面讨论).所有这些外部的程序提供了丰富的功能用于统计分析和可
视化,OMNet++范围之外的程序使他们的成就加倍.本手册简单描述了许多数据测绘程序,以
及如何使用 OMNet++.
输出标量文件使用标量工具可视化.它可以画出柱形统计图表,x-y图表(比如吞吐量 VS提供
的负载),或导出数据通过剪贴板至电子数据表和其他的程序进行更详细的分析.
用户接口
用户接口的基本目的是使模型的内部对用户可视,控制仿真执行,通过改变模型内部的变量/
对象允许用户干涉.这在项目仿真的开发/调试阶段非常重要的.一个传递下去的经验允许用
户得到一个模型行为的”感觉”也同样重要.图形用户接口可以用于证明一个模型的操作.
相同的仿真模型在模型文件本身不做任何改变的情况下被不同的用户执行.用户可以使用一
个有力的图形化用户接口进行测试调试仿真,最终使用一个简单快速的支持批处理执行的用
户接口运行.
组件库
存储在文件的模块类型从他们实际使用的地方分离出来.这个使用用户组合现有的模块类型,
创建组件库.
通用的单独仿真程序
仿真执行文件可以存储许多独立的模型,使用用相同的简单模块集.用户可以在配置文件中
指定运行哪个模型.允许创建一个包括许多仿真模型的大的可执行文件,发布为一个单独的
传感器工具.拓扑描述语言的灵活性也支持这种方法.
2.3.2 各分类的内容
如果安装了发布的源程序,你系统上的 omnetpp目录将包括以下的子目录.(如果你安装了一
个预处理发布,将缺少一些目录,或者会有额外的目录,比如 包括 OMNet++绑定的软件).
仿真系统本身:
omnetpp/
bin/
include/
OMNeT++ 根目录
OMNeT++ 可执行文件目录(GNED, nedtool等)
仿真模块的头文件
lib/
库文件
bitmaps/
图形会网络中使用的图标
doc/
手册(PDF),readme, license等
manual/ HTML帮助文件
tictoc-tutorial/ 介绍使用 OMNeT++
应用程序接口)
api/ 参考的 HTML API(Application Program Interface
nedxml-api/ API参考 NEDXML库
src/ 文件源
src/
OMNeT++ 源
nedc/
nedtool,消息编译器
sim/
仿真内核
parsim/
发布执行的文件
netbuilder/
动态读取 NED文件的文件
envir/
用户接口的公共代码
cmdenv/
用户接口命令行
tkenv/ 基于 Tcl/Tk的用户接口
gned/
图形化 NED编辑器
plove/
输出向量分析器和制图工具
scalars
输出标量分析器和制图工具
nedxml/
NEDXML库
utils/
makefile创建器,文档工具等
test/
回归测试
core/
仿真库的回归测试
distrib/
创建发布的回归测试
...
在 samples目录中的是仿真例子
samples/
aloha/
仿真例子的目录
Aloha协议模型
cqn/
关闭的队列网络
...
contrib目录包括 OMNeT++的贡献内容.
contrib/
octave/
emacs/
贡献内容目录
用于结果处理的 Octave脚本
Emacs高亮显示 NED语法
你也会发现一些附加的目录,像 msvc/, 其包括 VC++的综合组件等.
3 NED语言
3.1 NED 概述
模型的拓扑结构可以使用 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"; // imports ethernet.ned
3.3 信道定义
信道定义是详细说明链接类型的特征(属性). 信道名可用于后面的 NED描述来创建这些参
数的连接.语法:
channel ChannelName
//...
endchannel
在信道描述中,三个可选属性可以被赋值:延迟,比特错误率,和数据速率.延迟是传播延迟,
以仿真秒为单位.比特错误率是比特数据传输时发生错误的概率;数据速率是指信息的带宽
(比特/秒),用于计算数据包的传输时间,三个属性可以以任何顺序出现,所赋值应为常数.
例如:
channel LeasedLine
delay 0.0018 // sec
error 1e-8
datarate 128000 // bit/sec
endchannel
3.4 简单模块定义
简单模块是其他(复合)模块的基本构建块.简单模块类型由名称标识.惯例是,模块名以大定
字母开头.
简单模块通过声明参数和门来定义.简单模块由发下语法来声明:
simple SimpleModuleName
parameters:
//...
gates:
//...
endsimple
3.4.1 简单模块参数
参数是属于模块的变量.简单模块参数可以被简单模块算法使用.例如,TrafficGen模块可
能有参数 numOfMessages,该参数决定多少消息将被产生.
参数由名称标识.按惯例,参数名以小写字母开头.
Parameters域列出其名字即可声明参数.参数类型可以被指定为: numeric, numeric const
(或 simply const), bool, string, 或 xml, numeric为缺省类型.
例如:
simple TrafficGen
parameters:
interarrivalTime,