omnet++:使用教程


學習自:(6條消息) omnet++ 快速入門 | 計算機網絡仿真 | omnet++ 入門教程_葉局長的博客-CSDN博客

1、使用omnet仿真的一般步驟

主要有3步:

  1. 使用ned(network description)定義網絡拓撲結構;
  2. 利用C++編寫實現網絡的各種行為
  3. 編寫配置文件指定網絡參數,利用配置文件啟動項目;

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步:

  1. ned定義
  2. 使用C++繼承omnet的cModulecSimpleModule類定義一個Module類;
  3. 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、packagesNED中的一切虛擬事物

@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.DelayChannelned.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)離散事件模擬

  1. 離散事件系統(Discrete Event System)是指事件發生在時間線中離散的部分,對於計算機網絡而言正像是如此;
  2. 離散事件模擬系統通過在稱為FES(Future Event Set)FEL(Future Event List)的數據結構中保存未來事件的集合來實現;
  3. 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是有初始化事件的,我們通過父類cSimpleModuleinitialize()方法來進行初始化。

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():自消息的發送

④仿真的主要參考資料

  1. 當我們不知道一個函數的作用時,絕大多數情況下,都是去查cSimpleModule類cSimpleModule
  2. 其次會去SimulationManual中去查找,其中會有一些實際應用的例子

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM