Oment++ 初學者教程 第4節-將其轉變為真實網絡


4.1兩個以上的節點

現在,我們將邁出一大步:創建幾個tic模塊並將它們連接到網絡中。現在,我們將使它們的工作變得簡單:一個節點生成一條消息,其他節點繼續沿隨機方向扔消息,直到它到達預定的目標節點為止。NED文件將需要進行一些更改。首先,該Txc模塊將需要具有多個輸入和輸出門:

simple Txc10
{
    parameters:
        @display("i=block/routing");
    gates:
        input in[];  //聲明input,ouput兩種類型的gate數組
        output out[];
}

數組[ ]多個門變成gate向量。向量的大小(門數)將在我們使用Txc構建網絡的地方確定。

network Tictoc10
{
    submodules:
        tic[6]: Txc10;
    connections:
        tic[0].out++ --> {  delay = 100ms; } --> tic[1].in++;
        tic[0].in++ <-- {  delay = 100ms; } <-- tic[1].out++;

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

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

        tic[3].out++ --> {  delay = 100ms; } --> tic[4].in++;
        tic[3].in++ <-- {  delay = 100ms; } <-- tic[4].out++;

        tic[4].out++ --> {  delay = 100ms; } --> tic[5].in++;
        tic[4].in++ <-- {  delay = 100ms; } <-- tic[5].out++;
}

在這里,我們創建了6個模塊作為模塊向量,並將它們連接起來。
生成的拓撲如下所示:

在此版本中,tic[0]將生成要發送的消息。這是在函數initialize()的幫助下完成的,該getIndex()函數返回向量中模塊的索引。
代碼的forwardMessage()實質是handleMessage()每當消息到達節點時我們從中調用的函數。它繪制一個隨機的gate number,並在該gate上發送message。

void Txc10::forwardMessage(cMessage *msg)
{
    // 我們選擇隨機的一個gate發送信息
    // 我們在0~out[]數組長度之間選擇一個隨機數
    int n = gateSize("out");
    int k = intuniform(0, n-1);

    EV << "Forwarding message " << msg << " on port out[" << k << "]\n";
    send(msg, "out", k);
}

當消息到達時tic[3]handleMessage()它將刪除該消息。
請參閱txc10.cc中的完整代碼
練習
您會注意到,這種簡單的“路由”效率不是很高:通常,數據包會在兩個節點之間不斷跳動一段時間,然后再發送到另一個方向。如果節點不將數據包發送回發送方,則可以在某種程度上進行改進。實現這一點。提示:cMessage::getArrivalGate()cGate::getIndex()。請注意,如果消息不是通過門到達的,而是self-messages,則getArrivalGate()返回NULL
來源:tictoc10.nedtxc10.ccomnetpp.ini

4.2信道和內部類型定義

我們新的網絡定義變得非常復雜冗余,尤其是連接部分。讓我們嘗試簡化它。我們注意到的第一件事是,連接始終使用相同的delay參數。與簡單模塊類似,可以為連接創建類型(它們稱為信道)。我們應該創建一個指定延遲參數的信道類型,並將該類型用於網絡中的所有連接。

network Tictoc11
{
    types:
        channel Channel extends ned.DelayChannel {
            delay = 100ms;
        }
    submodules:

如您所見,我們通過添加一個types字段在網絡定義中定義了新的信道類型。此類型定義僅在網絡內部可見。它稱為局部或內部類型。如果願意,您也可以將簡單模塊用作內部類型。
筆記
我們通過專門內置來創建通道DelayChannel。(可以在ned包內找到內置信道。這就是為什么我們在extends關鍵字后使用完整類型名稱的ned.DelayChannel的原因
現在,讓我們檢查一下該connections部分是如何更改的。

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

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

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

        tic[3].out++ --> Channel --> tic[4].in++;
        tic[3].in++ <-- Channel <-- tic[4].out++;

        tic[4].out++ --> Channel --> tic[5].in++;
        tic[4].in++ <-- Channel <-- tic[5].out++;
}

如您所見,我們僅在連接定義內指定通道名稱。這樣可以輕松更改整個網絡的延遲參數。
來源:tictoc11.nedtxc11.ccomnetpp.ini

4.3使用雙向連接

如果再檢查一下該connections部分,我們將意識到每個節點對都通過兩個連接連接。每個方向一個。OMNeT ++ 4支持兩種方式的連接,因此讓我們使用它們。
首先,我們必須定義雙向(或所謂的inout)門,而不是之前使用的分離inputoutput門。

simple Txc12
{
    parameters:
        @display("i=block/routing");
    gates:
        inout gate[];  // declare two way connections
}

connections部分如下所示:

    connections:
        tic[0].gate++ <--> Channel <--> tic[1].gate++;//tic[0].gate[0]<-->tic[1].gate[0]
        tic[1].gate++ <--> Channel <--> tic[2].gate++;//tic[1].gate[1]<-->tic[2].gate[1]
        tic[1].gate++ <--> Channel <--> tic[4].gate++;
        tic[3].gate++ <--> Channel <--> tic[4].gate++;
        tic[4].gate++ <--> Channel <--> tic[5].gate++;
}

我們已經修改了門名稱,因此我們必須對C ++代碼進行一些修改。

void Txc12::forwardMessage(cMessage *msg)
{
    // In this example, we just pick a random gate to send it on.
    // We draw a random number between 0 and the size of gate `gate[]'.
    int n = gateSize("gate");
    int k = intuniform(0, n-1);

    EV << "Forwarding message " << msg << " on gate[" << k << "]\n";
    // $o and $i 后綴被用來識別門的雙向輸入輸出
    send(msg, "gate$o", k);
}

筆記
gate名稱后的特殊$i$o后綴允許我們分別使用連接的兩個方向。
來源:tictoc12.nedtxc12.ccomnetpp.ini

4.4定義我們的message class

在此步驟中,不再對目標地址進行硬編碼tic[3]-我們繪制一個隨機目標,然后將目標地址添加到消息中。

最好的方法是重寫cMessage的子類並將目標添加為數據成員。手動編碼消息類通常很乏味,因為它包含許多樣板代碼,因此我們讓OMNeT ++為我們生成該類。消息類規范位於tictoc13.msg

message TicTocMsg13
{
    int source;
    int destination;
    int hopCount = 0;
}

筆記
有關消息的更多詳細信息,請參見OMNeT ++手冊的第6節
設置makefile以便調用消息編譯器opp_msgc並生成消息聲明tictoc13_m.htictoc13_m.cc從消息聲明生成(文件名是根據tictoc13.msg文件名而不是消息類型名生成的)。它們將包含一個TicTocMsg13從[ cMessage]子類生成的類;該類將為每個字段提供getter和setter方法。
我們將tictoc13_m.h在我們的C ++代碼中包含該代碼,並且可以將其TicTocMsg13用作任何其他類。

	#include "tictoc13_m.h"

例如,我們使用以下幾行generateMessage()來創建消息並填寫其字段。

	TicTocMsg13 *msg = new TicTocMsg13(msgname);
    msg->setSource(src);
    msg->setDestination(dest);
    return msg;

然后,handleMessage()像這樣開始:

	void Txc13::handleMessage(cMessage *msg)
{
    TicTocMsg13 *ttmsg = check_and_cast<TicTocMsg13 *>(msg);

    if (ttmsg->getDestination() == getIndex()) {

在handleMessage()的參數中,我們將消息作為cMessage*指針。但是,只有TicTocMsg13將msg轉換為時,我們才能訪問在中定義的字段TicTocMsg13*。純C樣式的強制轉換((TicTocMsg13 *)msg)是不安全的,因為如果消息_不是_a TicTocMsg13,則程序最終將崩潰,從而導致錯誤,而這是很難發現的。
C ++提供了一種稱為的解決方案dynamic_cast。在這里,我們使用check_and_cast<>() OMNeT ++提供的功能:它嘗試通過強制轉換指針dynamic_cast,如果失敗,則會通過錯誤消息停止模擬,類似於以下內容:

在下一行中,我們檢查目標地址是否與節點的地址相同。該getIndex()成員函數返回子模塊向量模塊的索引(記住,在我們聲明是NED文件tic[6]: Txc13,所以節點地址0..5)。
為了使模型的執行時間更長,在消息到達其目標之后,目標節點將生成另一條具有隨機目標地址的消息,依此類推。閱讀完整的代碼:txc13.cc
運行模型時,它將如下所示:

您可以單擊消息以在檢查器窗口中查看其內容。雙擊將在新窗口中打開檢查器。(您必須為此暫時停止模擬,或者要非常快地處理鼠標)。檢查器窗口顯示許多有用的信息;消息字段可/以在“_目錄”_頁面上看到。

來源:tictoc13.nedtictoc13.msgtxc13.ccomnetpp.ini
練習
在此模型中,在任何給定時刻只有一條消息正在運行:節點僅在另一條消息到達它們時才生成一條消息。我們這樣做是為了使跟蹤仿真變得更加容易。更改模塊類,以便改為定期生成消息。消息之間的間隔應該是一個模塊參數,返回指數分布的隨機數。


免責聲明!

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



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