omnet++:官方文档翻译总结(三)
翻譯總結(jié)自:Turning it Into a Real Network - OMNeT++ Technical Articles
接官方文檔翻譯總結(jié)(二),本節(jié)主要是真實(shí)網(wǎng)絡(luò)的搭建
Part 4 - Turning it Into a Real Network
①多于兩個(gè)節(jié)點(diǎn)的網(wǎng)絡(luò):Tictoc10
現(xiàn)在我們要邁出一大步了:創(chuàng)造多個(gè)tic module并把它們連入網(wǎng)絡(luò)。
現(xiàn)在,我們構(gòu)建一個(gè)簡(jiǎn)單的多節(jié)點(diǎn)網(wǎng)絡(luò):其中一個(gè)節(jié)點(diǎn)產(chǎn)生消息發(fā)往一個(gè)隨機(jī)方向,該節(jié)點(diǎn)繼續(xù)隨機(jī)發(fā)送,……,剩下的節(jié)點(diǎn)執(zhí)行同樣的行為,直到它到達(dá)一個(gè)預(yù)先確定好的目的節(jié)點(diǎn)。
NED文件需要一些改變:
Txc module需要有多個(gè)input、output gates
simple Txc10
{
parameters:
@display("i=block/routing");
gates:
input in[];//定義in[]和out[]標(biāo)注一系列的進(jìn)出口
output out[];
}
[ ]把單個(gè)gate變成了gate數(shù)組。數(shù)組大小(數(shù)組中g(shù)ate的數(shù)量)決定了網(wǎng)絡(luò)中輸入輸出端口的數(shù)量:
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++;
}
上段NED代碼中我們構(gòu)建了6個(gè)module作為一個(gè)module vector,并將它們相連接,結(jié)果拓?fù)淙缦拢?/p>
其中tic[0]產(chǎn)生消息。這一步是在initialize()中實(shí)現(xiàn)的,實(shí)現(xiàn)過程中需要借助函數(shù)getIndex()——這個(gè)函數(shù)返回module在vector中的下標(biāo)。
代碼的核心是forwardMessage()函數(shù),當(dāng)一個(gè)消息到達(dá)時(shí),我們?cè)谔幚硐⒌膆andleMessage()中調(diào)用這個(gè)函數(shù)。這個(gè)方法中產(chǎn)生了一個(gè)隨機(jī)數(shù),并將消息從這個(gè)隨機(jī)數(shù)代表的gate中發(fā)送出去:
void Txc10::forwardMessage(cMessage * msg){
//在本例中,我們選擇一個(gè)隨機(jī)gate將消息發(fā)送出去
//這個(gè)隨機(jī)數(shù)的取值范圍為0~size(out[])-1
int n=gateSize("out");
int k=intuniform(0,n-1);
EV<<"Forward message "<<msg<<" on port out["<<k<<"]\n";
send(msg,"out",k);
}
當(dāng)消息到達(dá)tic[3]時(shí),它的handleMessage()將會(huì)刪除該消息(即目標(biāo)節(jié)點(diǎn)是tic[3])
補(bǔ)充:使用過程中,你可能會(huì)發(fā)現(xiàn)這個(gè)簡(jiǎn)單的路由算法并不是十分有效的——包會(huì)經(jīng)常在兩個(gè)節(jié)點(diǎn)間循環(huán)反彈一會(huì)兒再發(fā)送到別的節(jié)點(diǎn)。我們可以改進(jìn)這個(gè)算法——通過某些中間節(jié)點(diǎn)后不從輸入端口發(fā)送出去。提示:cMessage::getArrivalGate(),cGate::getIndex()。另外,如果某個(gè)消息不經(jīng)過端口發(fā)送出去,也就是說這個(gè)消息是一個(gè)self-message,那么getArrivalGate()將返回null。
總結(jié):tictoc10
- 當(dāng)一個(gè)simple module有多個(gè)輸入輸出端口時(shí),在NED文件中,定義simple module文件時(shí),gates關(guān)鍵字中的端口,不能定義為類似 input : in 這樣的一般單個(gè)變量,而應(yīng)該定義成 input : in[ ] 這樣的vector變量,表明一個(gè)simple module有多個(gè)in端口。
另外,這種形式布置的端口,在network的connections中進(jìn)行連接時(shí),就不能用之前的例子中所寫的諸如 xxx.out --> { ... } --> xxx.in;而應(yīng)該是xxx.out++ --> { ... } --> xxx.in++ - 在network的構(gòu)建中,如果想快速定義多個(gè)同類型simple module節(jié)點(diǎn),可以使用vector變量(也就是數(shù)組變量):
submodules:
tic[6] : Txc10;只是這樣定義的話,我們無法在Design模式下設(shè)置每一個(gè)節(jié)點(diǎn)的位置,而只能讓IDE運(yùn)行時(shí)自行布置。
- 如果我們有一個(gè)module vector(比如上文的tic[6]),需要根據(jù)module號(hào)來決定消息處理方式,那么可以在handleMessage中,用以下語(yǔ)句加以判斷:
if(getIndex()==0){
//0號(hào)module
...
} - 如果采用總結(jié)1中那種vector型多端口,發(fā)送消息時(shí)應(yīng)該指定從哪個(gè)端口發(fā)出去:send( msg , "out" , k )
- 使用gateSize("out")可以知道這個(gè)module有多少個(gè)out gate
- 在ned文件中通過vector一次定義了多個(gè)simple module:tic[6] : Txc10,這些節(jié)點(diǎn)無法在運(yùn)行時(shí)手動(dòng)在Design模式下設(shè)置它們的位置;只能在運(yùn)行時(shí)讓IDE自行布局;如果對(duì)布局不滿意的話,可以通過“Re-layout”按鈕進(jìn)行重布局,不過樣式有限,多次重布局后就會(huì)回到最初的布局結(jié)構(gòu)了。
②通道channel和內(nèi)部類型定義:tictoc11
我們的網(wǎng)絡(luò)定義已經(jīng)變得非常復(fù)雜和龐大了,特別是在connections這一節(jié)。我們可以對(duì)其嘗試優(yōu)化:首先,我們注意到connections中總是用到了delay parameter。我們可以為connections創(chuàng)造相關(guān)types(這里是所謂channels),就像我們給simple modules添加para那樣。我們可以創(chuàng)造一個(gè)channel類型指定delay,之后我們就可以使用它來構(gòu)建網(wǎng)絡(luò)中的connections
network Tictoc11
{
types:
channel Channel extends ned.DelayChannel{
delay=100ms;
}
submodules:
我們?cè)趎etwork中添加了types關(guān)鍵字,并在其中定義了新的channel。types關(guān)鍵字只能用在network中。它是一種局部的、內(nèi)部的type。如果我們想要的話,我們可以使用simple modules作為內(nèi)部type。
之后connections中的代碼就變成了:
connections:
tic[0].out++ --> Channel --> tic[1].in++;
tic[0].in++ <-- Channel <-- tic[1].out++; ... tic[4].out++ --> Channel --> tic[5].in++;
tic[4].in++ <-- Channel <-- tic[5].out++;
}
我們?cè)赾onnections中通過channel名指定了這個(gè)channel標(biāo)記的delay,這樣,我們就可以在隨后為整個(gè)網(wǎng)絡(luò)輕松修改所有delay了。
總結(jié):tictoc11
- 本例中,我們用channel代替之前寫的delay=100ms;
- channel定義在ned文件下network中的types關(guān)鍵字中,用以實(shí)現(xiàn)信道時(shí)延的channel都是繼承自ned.DelayChannel,定義方式如下:
network Tictoc11
{
types:
channel Channel extends ned.DelayChannel{
delay=100ms;
} - channel的使用,用在network下的connections關(guān)鍵字中,用來對(duì)端口與端口間的信道進(jìn)行某些規(guī)定:不是xxx.out、xxx.in而是xxx.in++、xxx.out++
connections:
tic[0].out++ --> Channel --> tic[1].in++;
tic[0].in++ <-- Channel <-- tic[1].out++;
... - 在ned文件中對(duì)network的channel進(jìn)行修改,可以實(shí)現(xiàn)同時(shí)對(duì)整個(gè)鏈路修改的目的
③雙向連接:tictoc12
你可能發(fā)現(xiàn)了,connections中每個(gè)節(jié)點(diǎn)對(duì)都有兩個(gè)連接,每個(gè)代表一個(gè)方向。OMNET++支持雙向連接,所以我們可以用以下方法使用它。
我們通過inout gate定義雙向連接,而不是用input和output gate這種我們之前使用的形式:
simple Txc12
{
parameters:
@display("i=block/routing");
gates:
inout gate[];
}
修改后的connections就將像下邊這樣:
connections:
tic[0].gate++ <--> Channel <--> tic[1].gate++;
tic[1].gate++ <--> Channel <--> tic[2].gate++;
...
tic[4].gate++ <--> Channel <--> tic[5].gate++;
}
由于我們修改了gate名,所以我們需要在C++中進(jìn)行修改:
void Txc12::forwardMessage(cMessage * msg)
{
int n = gateSize("gate");
int k = intuniform(0,n-1); EV<<"Forwarding message " <<msg<<" on gate["<<k<<"]\n";
//$o與$i后綴用以區(qū)分一個(gè)雙向gate的output/input端口
send(msg,"gate$o",k);
}
總結(jié):tictoc12
- inout gate,相當(dāng)于某個(gè)gate即是input又是output,用起來比單個(gè)input和output方便多了;
- 如果某個(gè)節(jié)點(diǎn)有多個(gè)inout gate,可以定義一個(gè)vector類型的inout gate,實(shí)現(xiàn)起來像下邊這樣:
simple Txc12
{
...
gates:
inout gate[];
}這種vector,就像我們?cè)趖ictoc11的總結(jié)3中所說,在使用時(shí)也要用到++符號(hào),就像gate++這樣;
- 與之前的單向收發(fā)的節(jié)點(diǎn)相比,使用時(shí)的信道連接方式,也是雙向的,即<-->這樣,而不是<--、-->這樣:
connections:
tic[0].gate++ <--> Channel <-->tic[1].gate++; - 使用send發(fā)送消息時(shí),需要指明通過后綴$i與$o指明發(fā)送端口
send(msg,"gate$o",k)
- 如果要想知道有多少個(gè)雙向端口,也是用gateSize,就像我們?cè)趖ictoc10總結(jié)5中所說:
int n = gateSize("gate");
④消息類(message class):tictoc13
在本節(jié)中,目的節(jié)點(diǎn)不再是固定的tic[3]——我們用一個(gè)隨機(jī)的目的地,我們把目的地址添加到message中。
最好的方法是繼承cMessage得到新的message子類,并將目的地指定為成員屬性。手寫全部代碼通常不太現(xiàn)實(shí),因?yàn)樗颂嗟臉影娲a,所以我們可以用OMNET++來為我們生成class。本例中我們?cè)趖ictoc13.msg中指定message class:
message TicTocMsg13
{
int source;
int destination;
int hopCount=0;
}
生成文件tictoc13.msg建立后,message編譯器就會(huì)自動(dòng)生成tictoc13_m.h與tictoc13_m.cc(從文件名而不是message class名中創(chuàng)建)。這兩個(gè)文件中將自動(dòng)生成一個(gè)繼承自cMessage的子類TicTocMsg13。該class將對(duì)每個(gè)字段生成getter與setter方法。
我們?cè)趯慍++代碼的cc文件中,需要引入tictoc13_m.h,這樣我們就可以使用TicTocMsg13這個(gè)message class了。
#include <tictoc13_m.h>
例如,我們可以在generateMessage()中通過如下代碼生成message,并填充它的各個(gè)字段:
TicTocMsg * 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中,我們接受一個(gè)消息作為參數(shù),其類型是cMessage *指針。只是,我們當(dāng)我們將普通的cMessage轉(zhuǎn)化為TicTocMsg*后,就只能訪問TicTocMsg13中定義的那些字段。我們經(jīng)常使用的那種消息類型轉(zhuǎn)化方式,如(TicTocMsg13 *) msg并不安全,因?yàn)槿绻S后的程序中得到的msg并不是TicTocMsg13類型,就會(huì)報(bào)錯(cuò)。
C++用dynamic_cast機(jī)制來解決這種問題。本例中我們使用check_and_cast<>(),該方法嘗試通過dynamic_cast的方式傳遞指針,如果方法失敗,它就會(huì)終止仿真并彈出錯(cuò)誤消息,類似下邊這樣:
下一行中,我們檢查目的地址是否和節(jié)點(diǎn)地址相同。為了使model執(zhí)行的更長(zhǎng)遠(yuǎn),在一個(gè)消息到達(dá)目的地時(shí),目的節(jié)點(diǎn)將生成另一條包含著隨機(jī)目的地址的消息,發(fā)送出去……
當(dāng)我們運(yùn)行model,它看起來像下邊這樣:
我們可以點(diǎn)擊消息(就是圖中的小紅點(diǎn))在左下角的窗口中查看它的內(nèi)容。
在本model中,在任意指定的時(shí)候只有一個(gè)正在運(yùn)行著的消息:當(dāng)另一個(gè)消息到達(dá)時(shí),節(jié)點(diǎn)只生成一個(gè)消息。我們之所以這樣做,是為了使仿真更簡(jiǎn)單。如果想讓消息的產(chǎn)生存在間隔,我們可以修改module以達(dá)成這一目的。消息間隔應(yīng)該是一個(gè)module parameter,返回指數(shù)分布的隨機(jī)數(shù)。
總結(jié):tictoc13
- 在msg文件中指定message class,每個(gè)message中有一些信息字節(jié):
message TicTocMsg13
{
int source;
int destination;
int hopCount=0;
}msg文件名為xxx.msg格式;message class定義時(shí)用message關(guān)鍵字;
- xxx.msg文件建立后,編譯器自動(dòng)生成xxx_m.h與xxx_m.cc(與msg文件名而不是message名相對(duì)應(yīng))。這兩個(gè)文件中會(huì)自動(dòng)生成一個(gè)繼承自cMessage的消息類,這個(gè)消息類就是我們?cè)趍sg文件中用關(guān)鍵字message建立的那個(gè)消息。此外,這個(gè)消息類中,對(duì)每個(gè)字段都實(shí)現(xiàn)了getter與setter方法。
- 在負(fù)責(zé)整個(gè)網(wǎng)絡(luò)邏輯的cc文件中,通過#include<xxx_m.h>引入之前創(chuàng)建的message,在其中訪問和設(shè)置字段值,通常,在生成message的代碼之后,通過msg->setXXX()設(shè)置值,在handleMessage()中,通過msg->getXXX()獲取這些值。
通常,我們可以單獨(dú)寫一個(gè)產(chǎn)生消息的函數(shù)generateMessage()函數(shù),在其中實(shí)現(xiàn)創(chuàng)建新消息、設(shè)置字段值、返回創(chuàng)建的新消息的功能:
xxxMsg * Txc13 :: generateMessage()
{
...
xxxMsg * msg = new xxxMsg( msgname );
msg->setSource(src);
msg->setDestination(dest);
return msg;
}上文中的xxxMsg就是我們?cè)趍sg文件中指定的message類。
- 在handleMessage()中,用xxxMsg處理收到的普通message的代碼為:
void handleMessage(cMessage * msg){
xxxMsg * xmsg = check_and_cast <xxxMsg *>(msg);
if( xmsg->getXXX()==getIndex() )用check_and_cast < xxxMsg *> (msg)可以安全地把一個(gè)普通的cMessage類型,變?yōu)槲覀冃枰哪欠NxxxMsg。轉(zhuǎn)換完成后,就可以用getter方法提取我們之前定義的和設(shè)置了值的字段。
由于tictoc13這個(gè)例子很有代表性,現(xiàn)對(duì)其代碼逐句加以分析解釋。
NED文件:tictoc13.ned
simple Txc13
{
parameters:
@display("i=block/routing");
gates:
inout gate[];
} network Tictoc13
{
types:
channel Channel extends ned.DelayChannel{
delay = 100ms;
}
submodules:
tic[6] : Txc13;
connections:
tic[0].gate++ <--> Channel <--> tic[1].gate++;
tic[1].gate++ <--> Channel <--> tic[2].gate++;
tic[1].gate++ <--> Channel <--> tic[4].gate++;
tic[3].gate++ <--> Channel <--> tic[4].gate++;
tic[4].gate++ <--> Channel <--> tic[5].gate++;
}
ned文件比較簡(jiǎn)單,沒什么需要多說的,需要注意的地方都在上個(gè)代碼中給標(biāo)紅了。
msg文件:tictoc13.msg
message TicTocMsg13
{
int source;
int destination;
int hopCount = 0;
}
message定義了每個(gè)節(jié)點(diǎn)發(fā)送、接收的消息的格式。
本例中,每個(gè)接收、發(fā)送、在信道中傳輸?shù)南⒅卸加腥齻€(gè)字段:source、destination、hopCount;分別標(biāo)識(shí)源地址(創(chuàng)建新消息的節(jié)點(diǎn)地址)、目的地址、當(dāng)前跳數(shù)。由于每個(gè)新消息的hopCount都是0,所以可以在此處直接將hopCount在定義時(shí)初始化為0。而source、destination都需要在消息傳遞過程中動(dòng)態(tài)確定,所以此處并不初始化,而是在cc文件中建立消息時(shí),通過setter方法設(shè)置。在cc文件中訪問這些字段時(shí),通過getter方法設(shè)置。
cc文件:txc13.cc
#include<stdio.h>
#include<string.h>
#include<omnetpp.h>
using namespace omnetpp;
#include<tictoc13_m.h> //① class Txc13 : public cSimpleModule
{
protected:
virtual TicTocMsg13 * generateMessage(); //②
virtual void forwardMessage(TicTocMsg13 * msg);
virtual void initialize() override;
virtual void handleMessage(cMessage * msg) override;
};
Define_Module(Txc13); void Txc13::initialize() //③
{
if(getIndex() == 0){
TicTocMsg13 * msg = generateMessage();
scheduleAt(0.0 , msg);
}
} void Txc13::handleMessage(cMessage * msg){ //④
TicTocMsg13 * ttmsg = check_and_cast <TicTocMsg13 *>(msg); if(ttmsg->getDesination()==getIndex()){
EV<<"Message "<<ttmsg<<" arrived after "<<ttmsg->getHopCount()<<" hops.\n";
bubble("ARRIVED, starting new one!");
delete ttmsg; EV<<"Generating another message: ";
TicTocMsg * newmsg = generateMessage();
EV<<newmsg <<endl;
forwardMessage(newmsg);
}
else{
forwardMessage(ttmsg);
}
} TicTocMsg13 * Txc13::generateMessage() //⑤
{
int src = getIndex();
int n = getVectorSize();
int dest = intuniform(0,n-2);
if(dest >= src)
dest++; char msgname[20];
sprintf(msgname,"tic-%d-to-%d",src,dest); TicTocMsg13 * msg = new TicTocMsg13(msgname);
msg->setSource(src);
msg->setDestination(dest);
return msg;
} void Txc13 :: forwardMessage(TicTocMsg13 * msg) //⑥
{
msg->setHopCount(msg->getHopCount()+1); int n = gateSize("gate");
int k = intuniform(0,n-1);
EV<<"Forwarding message "<<msg<<" on gate["<<k<<"]\n";
send(msg,"gate$o",k);
}
①引入之前message所在的文件
#include<tictoc13_m.h>
在我們完成xxx.msg之后,IDE就會(huì)自動(dòng)生成一個(gè)xxx_m.h和xxx_m.cc,在其中自動(dòng)實(shí)現(xiàn)了我們自己寫的message,使用時(shí)需要用#include引入,之后才能使用。
②
virtual TicTocMsg13 *generateMessage();
virtual void forwardMessage(TicTocMsg13 *msg);
virtual void initialize() override;
virtual void handleMessage(cMessage *msg) override;
除了我們最常用、也是最常見的initialize()和handleMessage()方法之外,我們又加入了兩個(gè)方法generateMessage()、forwardMessage().。這兩個(gè)函數(shù)的作用分別是創(chuàng)建新消息、轉(zhuǎn)發(fā)消息。
③initialize()
void Txc13::initialize()
{
if (getIndex() == 0) {
TicTocMsg13 *msg = generateMessage();
scheduleAt(0.0, msg);
}
}
在初始化函數(shù)中,我們指定了消息的起點(diǎn)——節(jié)點(diǎn)號(hào)為0的點(diǎn),這個(gè)點(diǎn)是開啟整個(gè)仿真的地方。
if(getIndex()==0)
對(duì)每一個(gè)節(jié)點(diǎn)初始化時(shí),都會(huì)檢查它的節(jié)點(diǎn)號(hào),如果是0,就進(jìn)行如下操作:
TicTocMsg13 * msg = generateMessage();
scheduleAt(0.0,msg);
第一句是,該節(jié)點(diǎn)創(chuàng)建了新消息,這個(gè)消息也是整個(gè)網(wǎng)絡(luò)的起始消息,由它激活整個(gè)網(wǎng)絡(luò)。
第二句話是這個(gè)消息被創(chuàng)建后直接發(fā)給自己,是一個(gè)self-message。這樣,我們就不用在初始化函數(shù)中指定這個(gè)消息從哪里發(fā)出去,而是采用handleMessage()方法中跟普通消息一樣的轉(zhuǎn)發(fā)方式。省卻了很多代碼。
④我們把handleMessage()方法放在最后說,先說另外兩個(gè)方法。
⑤generateMessage()
TicTocMsg13 * Txc13::generateMessage()
{
int src = getIndex(); // our module index
int n = getVectorSize(); // module vector size
int dest = intuniform(0, n-2);
if (dest >= src)
dest++; char msgname[20];
sprintf(msgname, "tic-%d-to-%d", src, dest); TicTocMsg13 *msg = new TicTocMsg13(msgname);
msg->setSource(src);
msg->setDestination(dest);
return msg;
}
在generateMessage()中我們創(chuàng)建并返回了一個(gè)新消息,由于需要返回新消息,所以函數(shù)類型就是TicTocMsg13 *,而不同于另外三個(gè)方法的void。
1)
int src = getIndex();
int n = getVectorSize();
int dest = intuniform(0, n-2);
if (dest >= src)
dest++;
第一部分,我們指定了源地址和目的地址,源地址也就是創(chuàng)建消息的節(jié)點(diǎn)的地址(其實(shí)就是節(jié)點(diǎn)號(hào)),通過getIndex()直接獲取到,其實(shí)也就是該節(jié)點(diǎn)的節(jié)點(diǎn)號(hào)。目的地址是除了該節(jié)點(diǎn)以外的任意其他節(jié)點(diǎn)(通過隨機(jī)數(shù)函數(shù)intuniform()來確定),至于dest >= src的判斷,個(gè)人認(rèn)為應(yīng)該是用 ==。
2)
char msgname[20];
sprintf(msgname,"tic-%d-to-%d",src,dest);
TicTocMsg13 * msg = new TicTocMsg13(msgname);
第二部分,我們根據(jù)源地址和目的地址的不同,創(chuàng)造了不同的消息,其中用sprintf創(chuàng)建消息名的語(yǔ)句,我們會(huì)經(jīng)常用到。
3)
msg->setSource(src);
msg->setDestination(dest);
return msg;
第三部分,我們?yōu)橄⒌牟糠肿侄芜M(jìn)行賦值,通過setter方法。
消息創(chuàng)建完了,消息內(nèi)的各字段也有了,就完成的新消息的創(chuàng)建,將它return。
⑥forwardMessage()
void Txc13::forwardMessage(TicTocMsg13 *msg)
{
msg->setHopCount(msg->getHopCount()+1); int n = gateSize("gate");
int k = intuniform(0, n-1);
EV << "Forwarding message " << msg << " on gate[" << k << "]\n";
send(msg, "gate$o", k);
}
1)
msg->setHopCount(msg->getHopCount()+1);
消息轉(zhuǎn)發(fā)前,使該消息的跳數(shù)加一
2)
int n = gateSize("gate");
int k = intuniform(0, n-1);
EV << "Forwarding message " << msg << " on gate[" << k << "]\n";
send(msg, "gate$o", k);
選擇合適端口(第一二行)把消息轉(zhuǎn)發(fā)(第四行)出去,轉(zhuǎn)發(fā)前向控制臺(tái)輸出信息(第三行),表明已經(jīng)進(jìn)行了消息轉(zhuǎn)發(fā)。
通過gateSize("gate")我們知道了這個(gè)節(jié)點(diǎn)有多少可供使用的端口。再通過intuniform(0,n-1)我們選擇了一個(gè)隨機(jī)的和正常的端口以供消息轉(zhuǎn)發(fā),這里的正常是指,不會(huì)選擇大于端口數(shù)量的端口號(hào)進(jìn)行轉(zhuǎn)發(fā)(由gateSize進(jìn)行保證)。
④handleMessage
void Txc13::handleMessage(cMessage *msg)
{
TicTocMsg13 *ttmsg = check_and_cast<TicTocMsg13 *>(msg); if (ttmsg->getDestination() == getIndex()) {
// Message arrived.
EV << "Message " << ttmsg << " arrived after " << ttmsg->getHopCount() << " hops.\n";
bubble("ARRIVED, starting new one!");
delete ttmsg; // Generate another one.
EV << "Generating another message: ";
TicTocMsg13 *newmsg = generateMessage();
EV << newmsg << endl;
forwardMessage(newmsg);
}
else {
// We need to forward the message.
forwardMessage(ttmsg);
}
}
消息處理函數(shù)一直是鏈路轉(zhuǎn)發(fā)的核心函數(shù),所以我們放在最后來說。
1)
TicTocMsg13 *ttmsg = check_and_cast<TicTocMsg13 *>(msg);
由于本例中我們的消息都是之前自己建立的消息TicTocMsg13這種類型,而handleMessage默認(rèn)收到的消息是cMessage類型,所以我們要進(jìn)行類型轉(zhuǎn)換,這就是這句話的目的。
轉(zhuǎn)換之后,我們就得到自定義的message ttmsg。
2)
if (ttmsg->getDestination() == getIndex())
如果消息的目的地字段(即destination字段)是當(dāng)前節(jié)點(diǎn),那么說明該節(jié)點(diǎn)就是該消息的終點(diǎn),我們就可以在其中寫消息到達(dá)目的節(jié)點(diǎn)后的相關(guān)處理了;否則本節(jié)點(diǎn)就是消息傳遞的中間節(jié)點(diǎn),就需要做另一些處理了。
3)
if(ttmsg->getDestination() == getIndex()) {
// Message arrived.
EV << "Message " << ttmsg << " arrived after " << ttmsg->getHopCount() << " hops.\n";
bubble("ARRIVED, starting new one!");
delete ttmsg;
// Generate another one.
EV << "Generating another message: ";
TicTocMsg13 *newmsg = generateMessage();
EV << newmsg << endl;
forwardMessage(newmsg);
}
消息到達(dá)終點(diǎn)時(shí),終點(diǎn)節(jié)點(diǎn)要做兩件事——I、顯示消息到達(dá)的信息;II、刪除該消息(因?yàn)闆]用了);III、產(chǎn)生另一個(gè)新消息,繼續(xù)之前的轉(zhuǎn)發(fā)過程。
EV << "Message " << ttmsg << " arrived after " << ttmsg->getHopCount() << " hops.\n";
bubble("ARRIVED, starting new one!");輸出消息和經(jīng)歷的跳數(shù)到控制臺(tái)日志中;彈出一個(gè)bubble,告訴人們消息已經(jīng)到達(dá)了;
delete ttmsg;
刪除舊的消息,因?yàn)橐呀?jīng)沒用了;
EV << "Generating another message: ";
TicTocMsg13 *newmsg = generateMessage();
EV << newmsg << endl;
forwardMessage(newmsg);通過generateMessage()生成新消息,通過forwardMessage把它轉(zhuǎn)發(fā)出去;整個(gè)網(wǎng)絡(luò)會(huì)一直重復(fù)這一創(chuàng)建——轉(zhuǎn)發(fā)——?jiǎng)h除過程,過程中只有一個(gè)消息在網(wǎng)絡(luò)上傳播。
4)
else{
forwardMessage(ttmsg);
}
如果節(jié)點(diǎn)是中間節(jié)點(diǎn),就只需要轉(zhuǎn)發(fā)消息forwardMessage就可以了。
總結(jié)
以上是生活随笔為你收集整理的omnet++:官方文档翻译总结(三)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 为什么那么多人想开发一元夺宝类app?
- 下一篇: C#设计模式之代理模式(四)