如今,咱們將邁出一大步:建立幾個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.inidom
咱們新的網絡定義變得很是複雜冗餘,尤爲是鏈接部分。讓咱們嘗試簡化它。咱們注意到的第一件事是,鏈接始終使用相同的delay
參數。與簡單模塊相似,能夠爲鏈接建立類型(它們稱爲信道)。咱們應該建立一個指定延遲參數的信道類型,並將該類型用於網絡中的全部鏈接。函數
network Tictoc11 { types: channel Channel extends ned.DelayChannel { delay = 100ms; } submodules:
如您所見,咱們經過添加一個types
字段在網絡定義中定義了新的信道類型。此類型定義僅在網絡內部可見。它稱爲局部或內部類型。若是願意,您也能夠將簡單模塊用做內部類型。
筆記
咱們經過專門內置來建立通道DelayChannel
。(能夠在ned
包內找到內置信道。這就是爲何咱們在extends
關鍵字後使用完整類型名稱的ned.DelayChannel的緣由
)
如今,讓咱們檢查一下該connections
部分是如何更改的。this
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編碼
若是再檢查一下該connections
部分,咱們將意識到每一個節點對都經過兩個鏈接鏈接。每一個方向一個。OMNeT ++ 4支持兩種方式的鏈接,所以讓咱們使用它們。
首先,咱們必須定義雙向(或所謂的inout
)門,而不是以前使用的分離input
和output
門。url
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 ++代碼進行一些修改。code
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
在此步驟中,再也不對目標地址進行硬編碼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 練習 在此模型中,在任何給定時刻只有一條消息正在運行:節點僅在另外一條消息到達它們時才生成一條消息。咱們這樣作是爲了使跟蹤仿真變得更加容易。更改模塊類,以便改成按期生成消息。消息之間的間隔應該是一個模塊參數,返回指數分佈的隨機數。