RSS订阅信息安全技术跟踪与研究:技术、平台、会议、论文、产业
你现在的位置:首页 / 技术积累 / 正文

OMNet TicToc实例--网络模拟器

0 技术积累 | 2016年10月28日
转载申明:本站原创,欢迎转载。但转载时请保留原文地址。
原文地址:http://www.vonwei.com/post/omnettictoclearn.html

OMNet++是基于C++离散事件模拟器(仿真器),可以模拟通信网络、多处理器以及其他分布式或者并行系统OMNet++是开源的,可以免费供学术和非盈利性使用。OMNet++生成了一个功能强大的开源离散事件模拟工具,可以供学术、教育以及面向研究的商业机构进行计算机网络、分布式或者并行系统的建模。类似的软件包含面向研究的开源软件NS2,昂贵的商业软件OPNETOMNet++主要可以弥补两者之间的差距。

在研究中,通常设计各种协议,协议可以涉及到分布式网络,和大规模设备节点,为了评估整体协议的性能,可以在OMNet中进行模拟运行。在物理网、移动设备、车联网不断发展的今天,实用部署之前,模拟一下测试性能和可行性很有必要。

其中tictoc教程基本将如何模拟一个通信网络,以及对其进行数据采集和分析,描述的比较细致。值得手动编写源代码过一遍。下面总结过完一遍之后的要点:

Tictoc例子给出了如何一步一步模拟通信网络,从简单的两个节点,到多个节点;对通信网络数据进行统计,以及最后怎样使用集成IDE工具对统计数据进行分析和图表处理。

Tictoc1

         如何创建一个OMNet工程的各个步骤详解,本工程主要是两个简单模块构成的网络,两个简单节点相互传送消息。

         要点:

(1)       创建NED文件(在NED中给出网络的拓扑结构),拓扑结构包含简单模块(主要包含input门和output门)、复合模块、网络模块(包含子模块和连接)

(2)       创建C++文件*.cc)为每个简单模块实现功能,每个简单模块的类名必须与NED中简单模块的名字保持一致;简单模块类继承于系统库中提供的cSimpleModule类,类中一般方法包含初始化函数initialize(),以及接受到消息后的处理函数handleMessage();类定义完成后,必须使用宏Define_Module()进行注册

(3)       Build工程会自动生成makefile文件,并对源代码进行编译(命令行实际是调用opp_makemake工具来自动生成makefile文件),生成可执行程序

(4)       此时模拟程序还无法启动,需要创建omnetpp.ini文件ini文件中主要描述一下需要模拟定义的哪个网络(一个模拟程序中可以定义多个网络),已经如何给该网络模型传递参数等等

(5)       通过debugrun或者直接在命令行中运行生成的可执行程序,模拟就跑起来了。模拟中可以一步一步运行,可以调节运行的速度,以及动画的速度。

         容易出错的地方:

                  NEDcc文件中模型的类名必须保持一致;不要忘记Define_Module()cc文件中   不要忘记#include <omnetpp.h>using namespace omnetpp;

 

Tictoc2

         Tictoc1中的模型比较傻瓜,Tictoc2NED中的模块增加一点修饰。通过@display可以指定模块的icon图像以及背景颜色。如存在images/block/routing.png,可以@display("i=block/routing")这样修饰。

         另外,在C++文件中,通过EV也可以增加一些debug消息,EV使用与C++cout差不多,例如:EV << "Sending initial message\n"

                    

Tictoc3

         C++文件的类中增加状态变量,通过WATCH()可以在运行模拟模型时,查看变量的变化;状态变量为private,其初始化在initialize()函数中。

        

Tictoc4

         NED中编写模块时可以添加参数(模块参数),参数类型可以是数字、字符串、布尔和xml,比如定义了一个参数int limit;在对应的C++文件类中,通过par(“limit”)可以获得模块中对应参数的值。

         模块参数最好给一个默认值(default);模块中的参数可以在NED文件中赋值,也可以在omnetpp.ini中赋值,根据自己方便决定。

 

Tictoc5

         NED中的模块可以继承,继承的模块可以对原有模块中的部分参数进行覆写(override)。

 

Tictoc6

         网络中每个节点可能会处理一些操作,这个操作可能有一定的时间,在实际设备中获取时间后,在模拟时可以直接将时间写为该节点的处理时间。主要是使用scheduleAt()函数发送self-message;如scheduleAt(simTime()+1.0, msg)表示该节点在当前模拟时间的基础上延长1.0s后(该延长时间相当于该节点的处理时间),然后将msg发送给自己。

 

Tictoc7

         主要说明如何使用随机数OMNet++使用一个确定算法(Mersenne Twister RNG)来产生随机数,如果种子不变,可能导致每次模拟运行的结果一样。当然,可以在omnetpp.ini中指定种子,不同的模拟运行时,可以手动修改种子,如:

            [General]

            seed-0-mt=532569  # or any other 32-bit value

随机数使用,如在NED的某个模块中定义一个参数:

   volatile double delayTime @unit(s);   // delay before sending back message

omnetpp.ini文件中可以指定一定的分布来生成随机数赋值,如:

         *.delayTime = exponential(3s)

         *.delayTime = truncnormal(3s,1s)

在对应的C++文件中可以如下使用:

         simtime_t delay = par("delayTime"); //获取每次的随机处理时间

         scheduleAt(simTime()+delay, msg); //延迟delay后,再发生self-message msg

 

Tictoc8

         主要说明定时器和timeout的使用该例子根据定时器给出了一个超时处理的逻辑。定时器相当于一个事件,OMnet++中事件和消息一样表示。

         C++类的private中创建一个变量,分别表示timeout时间间隔和事件(事件用消息即可),如下:

         private:

             simtime_t timeout;  // timeout

             cMessage *timeoutEvent;  // holds pointer to the timeout self-message

         在类的构造函数中,对消息指针进行空指针初始化:timeoutEvent = nullptr;

         在类的析构函数中,取消并删除事件:cancelAndDelete(timeoutEvent);

         initialize()函数中,对timeouttimeoutEvent进行赋初值和初始化处理;

         在其它函数中,可以使用定时器,如:

                   scheduleAt(simTime()+timeout, timeoutEvent);

         不需要定时器时,可以取消定时器:cancelEvent(timeoutEvent);

 

Tictoc9

         描述了如何重新传送相同的消息。结合Tictoc8给出了超时重发的逻辑源码。主要是采用了消息的复制机制:

         cMessage *copy = (cMessage *)msg->dup();

         为了能够支持重传相同的消息,本地节点保持原来的包,发送出去其一个copy;对原包的删除需要收到ack后才执行。

 

Tictoc10

         之前的网络模型都是只包含两个节点,这里扩充成多个节点。在NED中定义时,每个简单模块的门可以支持多个,如:

         input in[];

         Output out[]

[]可以将门gates变成门向量,具体门的个数在具体网络模型中确定,即网络定义中有多少个连接连到该节点。

         c++文件中,通过gateSize(“out”)可以返回输出门的个数;通过intuniform(0, n-1)可以随机选择一个门传送消息。

 

Tictoc11

         这个例子主要描述网络中的通道定义。之前的通道指定都比较傻瓜,如:

            tic[0].out++ --> {  delay = 100ms; } --> tic[1].in++;

在定义网络模块时,可以通过inner type定义一个通道,如:

         network Tictoc11

         {

             types:

                 channel Channel extends ned.DelayChannel {

                     delay = 100ms;

                 }

             submodules:

                   …

然后在定义连接connections时,可以直接调用,如:

         tic[0].out++ --> Channel --> tic[1].in++;

 

Tictoc12

         之前的连接都是单向连接,导致简单模块处既有输入门,又有输出门,比较繁琐。其实可以直接使用双向门inout gate[]

         gates:

        inout gate[];  // declare two way connections,支持多个门

         connections:

        tic[0].gate++ <--> Channel <--> tic[1].gate++;

         C++文件中,通过n = gateSize("gate"); 可以获得对应模块实例门的个数。

 

Tictoc13

         自定义消息类message class。之前消息都是采用库中提供的cMessage,实际网络模拟中,传送的消息可以带其他信息,如源地址、目标地址、跳数(hop count)等。可以采用自构建的消息类。IDE支持创建msg文件,如创建networkMsg.msg文件如下:

         message networkMsg

         {

             int source;

             int destination;

             int hopCount = 0;

         }

         创建.msg文件后,要立即build一下,会自动生成msg对应的c++文件和头文件,不要先使用msg后才想起build,要不然build一直出错,其对应的源文件也无法自动生成。生成的文件为:networkMsg_m.ccnetworkMsg_m.h,将getset函数都自动配置好了,比较方便。

         C++类中,需要#include “networkMsg_m.h”,然后就可以使用自定义的消息类了,如:

         networkMsg *msg = new networkMsg (msgname);

    msg->setSource(src);

    msg->setDestination(dest);

    return msg;

         另外,handleMessage默认的参数为cMessage在进行类型转换时需要使用check_and_cast,如下:

         cMessage *msg

         networkMsg *ttmsg = check_and_cast< networkMsg *>(msg);

 

Tictoc14

         增加一些简单的统计信息,如某个节点发送了多少个包,接受了多少个包。本例子直接在C++类中加变量(long numSent;  long numReceived;)进行统计,没有太多可说的。

 

Tictoc15

         omnetpp.ini文件中加入“record-eventlog = true”,OMNet++在模拟运行时,内部内核会自动记录消息交换的详情,在result目录下会生成一个elog文件,在GUI中双击打开可以看到消息的详细传递过程,如下图:

         本节对经过多少跳数(hopCount)消息才能达到目的地址进行了统计。不过统计也是在C++类中定义变量,采用库中自带的cLongHistogramcOutVector类;还需要自己在相应的逻辑出采集数据,在模拟结束时也需要自己编写finish()函数来手动记录scalar数据。

         采集的数据在result目录的vec文件中,而finish()函数记录的数据在result目录中的sca文件中。

 

Tictoc16

         上面统计数据采集信息相对比较复杂。OMNet++内部其实提供了‘signals’信号机制来记录值或者事件。用户只需要指定emit啥信号,在信号上附加啥数据,以及什么时候emit数据即可。同样统计跳数,采用signal的方式如下:

         C++类中,定义private信号:

                  private:

                      simsignal_t arrivalSignal;

在使用信号前,必须注册,因此需要在模块的initialize()方法中注册信号:

                  arrivalSignal = registerSignal("arrival");

在需要的地方emit数据即可(消息达到目的地址时,获取其hopcount值并emit):

                   int hopcount = ttmsg->getHopCount();

                  emit(arrivalSignal, hopcount);

最后,在对应的NED文件中也要对应的signal

                   parameters:

                 @signal[arrival](type="long");

                 @statistic[hopCount](title="hop count"; source="arrival"; record=vector,stats; interpolationmode=none);

                 @display("i=block/routing");

         record告诉需要对接受到的数据进行哪些处理,vector表示每个值必须存储在一个vector文件中,stats表示需要计算min,max,mean,count等统计信息。

         统计记录还可以omnetpp.ini文件中进行修改,如:

         **.tic[1].hopCount.result-recording-modes = +histogram  //看第一个模块的hopCount的直方图histogram

         **.tic[0..2].hopCount.result-recording-modes = -vector //为了节省空间,对0,1,2三个模块的vector数据不感兴趣

 

         收集的数据都存储在项目的results目录下,一般包含.vec文件和.sca文件Vec文件(vectors)以a function of time的形式记录数据值,而sca文件(scalar data)典型的在模拟运行结束时记录合计值aggregate values。在IDE中,双击打开任何一个文件,就可以在自带的分析工具中加载数据,选择数据可以采用逻辑语言的形式进行,根据数据可以制定各种统计表格,如直方图、散点图、分布图等。




  • ------------------分隔线----------------

  • 如果感兴趣,欢迎关注本站微信号,跟踪最新博文信息,手机微信扫一扫下面的二维码,即可关注!
  • 微月信公众号
  • 推荐您阅读更多有关于“ 分布式模拟   ”的文章

    请填写你的在线分享代码
    上一篇:[转]bss,data,text,rodata,堆,栈,常量段下一篇:中国可信计算技术与产业化论坛参会总结

    猜你喜欢

    评论列表:

    发表评论

    必填

    选填

    选填

    必填,不填不让过哦,嘻嘻。

    记住我,下次回复时不用重新输入个人信息

    本站介绍
    最近发表
    本年最热文章
    本月最热文章
    网站分类
    文章归档