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.ned,txc10.cc,omnetpp.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.ned,txc11.cc,omnetpp.ini

4.3使用雙向連接

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

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.ned,txc12.cc,omnetpp.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.h並tictoc13_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.ned,tictoc13.msg,txc13.cc,omnetpp.ini
練習
在此模型中,在任何給定時刻只有一條消息正在運行:節點僅在另一條消息到達它們時才生成一條消息。我們這樣做是為了使跟蹤模擬變得更加容易。更改模組類,以便改為定期生成消息。消息之間的間隔應該是一個模組參數,返回指數分布的隨機數。