omnet++:使用教程
学习自:(6条消息) omnet++ 快速入门 | 计算机网络仿真 | omnet++ 入门教程_叶局长的博客-CSDN博客
1、使用omnet仿真的一般步骤
主要有3步:
- 使用ned(network description)定义网络拓扑结构;
- 利用C++编写实现网络的各种行为;
- 编写配置文件指定网络参数,利用配置文件启动项目;
2、新建项目
File->New Project->Omnet++ Project

项目新建之后,我们可以看到src、simulation文件夹:
simulation:存放项目配置文件;我们在配置文件中指定想要模拟的网络、网络中节点的位置等
src:存放所有源代码,包括ned文件、C++源文件等;

3、定义仿真网络的拓扑结构
使用omnet进行仿真,我们首先需要定义网络的拓扑结构
①新建空network
在src目录下,我们新建一个network,选择one item,此时我们就有了一个网络,当然现在里边什么都没有。点击Design标签,可以以GUI的形式查看ned文件当前的内容。
②Module
1)Module的概念
逻辑上,omnet++中的module相当于C++中的class,并且可以在module中定义属性,我们用module实例化出的module对象,又可以放到其他的模块中。
代码上,omnet++中的module就是C++中的class,在定义网络行为时,我们需要用到它的属性、参数等。
在omnet中,网络中的所有东西(如节点、服务器等)都以module形式定义:
- 最底层的module称为simple module;
- mudule可以添加到compound module中;
- module间可以互相嵌套,没有嵌套的层级限制;
- module间可以定义继承关系;
一个Node、很多个Nodes、一个Network,都可以是一个Module;Network的本质上就是compound module;

2)Module的定义步骤
一个module的定义分为3步:
- 在ned中定义;
- 使用C++继承omnet的cModule或cSimpleModule类,定义一个Module类;
- 将ned文件中定义的Module与C++中定义的Module联系起来;
①ned文件中的定义
1)simple module
定义一个simple module的语法如下:
simple Host
{
...
parameters://定义该module的参数,如传输速率等
...
gates: //定义该module的输入、输出口及个数
...
}
2)compound module
定义一个compound module的一般语法如下,所有的sections都是可选的:
module Host
{
types: //定义module类型(在submodules中使用),信道类型(在connections中使用)等
...
parameters://定义该moduel的参数,如传输速率、节点个数等
...
gates: //定义该module的输入和输出口以及个数
...
submodules://定义submodule实例
...
connections://定义submodule间的链接方式
...
}
②C++文件中的定义
对于simple module,我们继承自cSimpleModule;
对于compound module,我们继承自cModule;
我们来定义一个C++ Module类:
#include<omnetpp/csimplemodule.h>
class ExampleModule:public omnetpp::cSimpleModule{
public:
ExampleModule();
virtual ~ExampleModule();
}; Define_Module(ExampleModule);//Module与其对应class之间的联系
③将C++文件与ned文件联系起来:Define_Module
在类定义的后面,添加Define_Module(module名);,将ned文件中的module与指定的C++文件中的Module类联系起来
③元数据注释(属性)
NED属性是元数据注释,这些属性可以被附加到modules、parameters、gates、connections、NED files、packages和NED中的一切虚拟事物。
@display、@class、@namespace、@unit、@prompt、@loose、@directIn都是属性,这些属性我们已经在之前的几节中说过了,但是那些例子只抓住了表面,给出的是这些属性的基本使用方法。
使用属性,我们就可以为NED属性添加额外的信息。一些属性已经被NED仿真内核给解释了;另一些属性从仿真模型中读入并使用,并且提供给NED编辑工具使用。
将这些属性添加到某个类型中,之后我们在定义每个实例时就不能使用不同的属性了。所有module、connections、parametes等实例,都是由NED文件中的特定位置创建出来的,它们都有其特有的属性。
下面是一个使用元数据注释的例子:
@namespace(foo);//文件属性
module Example
{
parameters:
@node;//module属性
@display("i=device/pc");//module属性
int a @unit(s)=default(1);//parameter属性
gates:
output out @loose @labels(pk);//gate属性
submodules:
src:Source{
parameters:
@display("p=150,100");//submodule属性
count @prompt("Enter count:");//为parameter添加一个属性
gates:
out[] @loose;//为gate添加一个属性
}
...
connections:
src.out++ -->{@display("ls=green,2");}--> sink1.in;//connection属性
src.out++ --> Channel{@display("ls=green,2");}--> sink2.in;
}
④信道
在ned文件中,我们可以定义信道,定义的一般语法如下:
channel 信道名 extends 继承的信道
{
...信道属性...
}
大多数情况下,我们不用去定义信道,oomnet++自带了三个信道ned.IdealChannel,ned.DelayChannel和ned.DatarateChannel,详细可以看:https://doc.omnetpp.org/omnetpp/manual/#sec:ned-lang:channels
我们也可以直接在connections中写出信道的属性,省去了定义信道的步骤。
⑤配置文件
定义在parameters中的属性,在配置文件.ini中指定。
4、几个例子
omnet++根目录的sample目录下官方提供了许多例子供我们参考,这里挑选几个比较经典的例子:
ALOHA
tictoc
SimpleNode和Sink
先看一个RIMAC的节点,SimpleNode:
package RIMAC.simplenode;
simple SimpleNode
{
parameters:
double x @unit(m);
double y @unit(m);
double txRange @unit(m);//数据传输距离
double senRange @unit(m);//数据感知距离
double Twait @unit(s);//事件等待时间
double bitRate;//传输速率
double animationHoldTimeOnCollision @unit(s);//碰撞时动画持续时间
volatile double frameTime=uniform(0.5s,1.5s) @unit(s);//一帧的时间
double sleepTime @unit(s);//睡眠时间
double sendConsumption @unit(W);//发送功耗
double recvConsumption @unit(W);//接收功耗
double sleepConsumption @unit(W);//睡眠功耗
double idleConsumption @unit(W);//空闲功耗
double energy @unit(J);//初始能量
int packetSize @unit(B);//数据包大小
@display("p=$x,$y");
@class(RIMAC::simpleNode);
@signal[energyLeft](type="double");
@staticstic[energyLeftStat](title="energyLeft";source="energyLeft";record=vector,stats);
gates:
input in @directIn; }
Sink定义:
package RIMAC;
import RIMAC.simplenode.SimpleNode;
simple Sink extends SimpleNode
{
parameters:
@class(RIMAC::Sink);
@display("p=$x,$y;i=device/terminal;r=$txRange");
@signal[e2etd](type="double");
@statistic[e2etdStat](title="e2etd";source="e2etd";record=vector,stats);
@signal[ae2etd](type="double");
@statistic[ae2etdStat](title="ae2etd";source="ae2etd";record=vector,stats);
}
5、控制网络仿真时的行为
①omnet仿真原理
1)离散事件模拟
- 离散事件系统(Discrete Event System)是指事件发生在时间线中离散的部分,对于计算机网络而言正像是如此;
- 离散事件模拟系统通过在称为FES(Future Event Set)或FEL(Future Event List)的数据结构中保存未来事件的集合来实现;
- omnet++底层使用二叉堆实现的优先级队列和事件循环(Eventloop)来实现这一套模拟机制。

2)omnet事件循环
启动仿真后,事件执行的伪代码如下:
初始化(initialize) //包括构建模型,添加初始化事件到FES中 while(FES不为空&&仿真未结束)
{
从FES中取出事件
t := 该事件发生时间
执行事件
(事件执行过程中,可能往FES中添加事件,也可能往FES中删除事件)
}
结束仿真(写入统计数据,etc.)
②网络的初始化和结束原理
omnet网络的整个过程如下:
perform simulation run:
build network
(i.e. the system module and its submodules recursively)
insert starter messages for all submodules using activity()
do callInitialize() on system module
enter event loop
if (event loop terminated normally)
do callFinish() on system module
clean up 模拟运行:
构造网络
(递归构造系统module和每个module的submodule)
用activity()为所有submodule插入开始消息 在系统module中运行callInitialize():
进入事件循环
if(事件循环正常结束)
在系统mudule中运行callFinish()
清理
其中callInitialize()和callFinish()的伪代码如下:
callInitialize()
{
call to user-defined initialize() function
if (module is compound)
for (each submodule)
do callInitialize() on submodule
} {
调用用户自定义的initialize()函数
if (module是compound module)
for(each submodule)
在每个submodule中调用callInitialize()
} callFinish()
{
if(module is compound)
for(each submodule)
do callFinish() on submodule
call to user-defined finish() function
}
1)模块的初始化
从上边的执行过程可知,module是有初始化事件的,我们通过父类cSimpleModule的initialize()方法来进行初始化。
2)模块的多阶段初始化
可以重写两个方法来进行多阶段的初始化,在numInitStages中返回阶段的个数,一般来说,我们可以在第一个初始化阶段进行变量赋值等操作,后面的阶段可以进行周期计算等:
virtual void initialize(int stage);
virtual int numInitStages() const;
3)模块的结束
模块通过调用finish()来进行仿真结束的工作
③消息的发送与接收
消息的发送由sendXXX系列函数完成,消息的接收基本都由handleMessage完成
1)默认的消息cMessage类
cMessage类是所有消息类的父类,我们可以自定义一个消息类(继承自cMesaage),也可以直接使用这个类:
cMessage(const char *name=nullptr , short kind=0)
2)sendXXX()
Message sending.
virtual void send (cMessage *msg, int gateid)
virtual void send (cMessage *msg, const char *gatename, int gateindex=-1)
virtual void send (cMessage *msg, cGate *outputgate)
virtual void sendDelayed (cMessage *msg, simtime_t delay, int gateid)
virtual void sendDelayed (cMessage *msg, simtime_t delay, const char *gatename, int gateindex=-1)
virtual void sendDelayed (cMessage *msg, simtime_t delay, cGate *outputgate)
virtual void sendDirect (cMessage *msg, cModule *mod, const char *inputGateName, int gateIndex=-1)
virtual void sendDirect (cMessage *msg, cModule *mod, int inputGateId)
virtual void sendDirect (cMessage *msg, cGate *inputGate)
virtual void sendDirect (cMessage *msg, simtime_t propagationDelay, simtime_t duration, cModule *mod, const char *inputGateName, int gateIndex=-1)
virtual void sendDirect (cMessage *msg, simtime_t propagationDelay, simtime_t duration, cModule *mod, int inputGateId)
virtual void sendDirect (cMessage *msg, simtime_t propagationDelay, simtime_t duration, cGate *inputGate)
3)handleMessage(Msg *)
4)ScheduleAt():自消息的发送
④仿真的主要参考资料
- 当我们不知道一个函数的作用时,绝大多数情况下,都是去查cSimpleModule类:cSimpleModule
- 其次会去SimulationManual中去查找,其中会有一些实际应用的例子
omnet++:使用教程的更多相关文章
- OMNeT++安装教程
前提及注意事项: 1) 安装之前首先要确定已经安装好GCC编译环境(例如:MinGW.Cygwin,选择一种安装); (否则OMNeT++会安装不成功),具体安装教程详见另一篇文章 MinGW安装教程 ...
- OMnet++ 初学者教程 第一节 入门
第1部分-入门 1.1模型 首先,让我们从一个包含两个节点的"network"开始.节点将做一些简单的事情:一个是节点将创建一个数据包,而两个节点将继续来回传递相同的数据包.我们将 ...
- Problem "g++" ("gcc") not found in PATH [ in omnet++ ] ---- 关于OMNeT++软件使用问题
出现的问题就像下面这样: 解释一下我出现这种情况的背景: 1. 首先安装好了OMNeT++软件,关于OMNeT++软件是否安装成功详见另一篇文章 OMNeT++安装教程 2. 也安装好了GCC编译环境 ...
- Omnet++ 4.0 入门实例教程
http://blog.sina.com.cn/s/blog_8a2bb17d01018npf.html 在网上找到的一个讲解omnet++的实例, 是4.0下面实现的. 我在4.2上试了试,可以用. ...
- MinGW安装教程
首先说明一下 1) MinGw只是其中一种GCC编译环境的安装程序,还有像Cygwin也是差不多的; 2) 由于安装的时候有些地方忘了截图,所以图有些是借鉴别人的; 3) 还要就是安装MinGw,最好 ...
- Veins(车载通信仿真框架)入门教程(四)——调试及记录结果
Veins(车载通信仿真框架)入门教程(四)——调试及记录结果 在Veins入门教程(三)最后的动图中(如下图)可以看到大大小小的光圈,这个怎么实现的呢? 很简单,以收到RTS消息为例,通过finHo ...
- Veins(车载通信仿真框架)入门教程(三)——多跳路由实现指导
Veins(车载通信仿真框架)入门教程(三)——多跳路由实现指导 Veins(车载通信仿真框架)入门教程(三)——多跳路由实现指导 必要的message类实现 从下面开始是在veins/src/vei ...
- Veins(车载通信仿真框架)入门教程(二)——调用第三方库
Veins(车载通信仿真框架)入门教程(二)——调用第三方库 在借助Veins进行自己的研究时我们经常需要实现一些比较复杂的功能,有时就需要借助第三方库的帮助. 博主的研究需要使用神经网络,但是自己编 ...
- Veins(车载通信仿真框架)入门教程
Veins入门教程——教你如何下手研究 目录 Veins入门教程——教你如何下手研究 目录 废话少说! 讲解omnetpp.ini!(挑关键的) 讲解RSUExampleScnario.ned! 注意 ...
随机推荐
- JavaCV的摄像头实战之四:抓图
欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本文是<JavaCV的摄像头实战> ...
- Nginx怎么处理请求的?
nginx接收一个请求后,首先由listen和server_name指令匹配server模块,再匹配server模块里的 location,location就是实际地址. server { # 第 ...
- 学习JAVAWEB第十五天
今天跟着视频做一个简单的登录界面用到javabean,servlet,数据库等知识,还没做完,明天接着做.
- 在ajax请求中,contentType 和 dataType 的区别?
一.在ajax请求中,contentType 和 dataType 的区别? 1.contentType 内容类型. 1.1默认是 "application/x-www-form-urlen ...
- Python调用windows下DLL详解 - ctypes库的使用
在python中某些时候需要C做效率上的补充,在实际应用中,需要做部分数据的交互.使用python中的ctypes模块可以很方便的调用windows的dll(也包括linux下的so等文件),下面将详 ...
- 服务器性能测试利器之sysbench
前言 sysbench是一个开源的.模块化的.跨平台的多线程性能测试工具,可以用来进行CPU.内存.磁盘I/O.线程.数据库的性能测试.sysbench是基于LuaJIT的可编写脚本的多线程基准测试工 ...
- php解决抢购秒杀抽奖等大流量并发入库导致的库存负数的问题
我们知道数据库处理sql是一条条处理的,假设购买商品的流程是这样的: sql1:查询商品库存 1 if(库存数量 > 0) 2 { 3 //生成订单 4 //库存-1 5 > 当没有并发时 ...
- java file已存在,新建流写入此文件是否会覆盖原本file信息
java中建立文件输出流,当文件不存在时会新建一个文件:如果有同名文件,自动覆盖.不存在时自动建立.FileOutputStream的默认构造方法是直接覆盖掉原来的文件,而FileOutputStre ...
- Python—列表元组和字典
Python-列表元组和字典 列表 元组 字典 列表: 列表是Python中的一种数据结构,他可以存储不同类型的数据.尽量存储同一种类型 列表索引是从0开始的,我们可以通过索引来访问列表的值. 列表的 ...
- Python接口自动化测试_悠悠
https://yuedu.baidu.com/ebook/585ab168302b3169a45177232f60ddccda38e695###