Oment++初学者教程第4节-将其转变为真实网络
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
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()它将删除该消息。
请参阅的完整代码
练习
您会注意到,这种简单的“路由”效率不是很⾼:通常,数据包会在两个节点之间不断跳动⼀段时间,然后再发送到另⼀个⽅向。
如果节点不将数据包发送回发送⽅,则可以在某种程度上进⾏改进。
实现这⼀点。
提⽰:cMessage::getArrivalGate(),cGate::getIndex()。
请注意,如果消息不是通过门到达的,⽽是self-messages,则getArrivalGate()返回NULL。
来源:,,
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++;
}
如您所见,我们仅在连接定义内指定通道名称。
这样可以轻松更改整个⽹络的延迟参数。
来源:,,
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后缀允许我们分别使⽤连接的两个⽅向。
来源:,,
4.4定义我们的message class
在此步骤中,不再对⽬标地址进⾏硬编码tic[3]-我们绘制⼀个随机⽬标,然后将⽬标地址添加到消息中。
最好的⽅法是重写cMessage的⼦类并将⽬标添加为数据成员。
⼿动编码消息类通常很乏味,因为它包含许多样板代码,因此我们让OMNeT ++为我们⽣成该类。
消息类规范位于tictoc13.msg:
message TicTocMsg13
{
int source;
int destination;
int hopCount = 0;
}
笔记
有关消息的更多详细信息,请参见OMNeT ++⼿册的。
设置makefile以便调⽤消息编译器opp_msgc并⽣成消息声明tictoc13_m.h并tictoc13_从消息声明⽣成(⽂件名是根据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)。
为了使模型的执⾏时间更长,在消息到达其⽬标之后,⽬标节点将⽣成另⼀条具有随机⽬标地址的消息,依此类推。
阅读完整的代码:
运⾏模型时,它将如下所⽰:
您可以单击消息以在检查器窗⼝中查看其内容。
双击将在新窗⼝中打开检查器。
(您必须为此暂时停⽌模拟,或者要⾮常快地处理⿏标)。
检查器窗⼝显⽰许多有⽤的信息;消息字段可/以在“_⽬录”_页⾯上看到。
来源:,,,
练习
在此模型中,在任何给定时刻只有⼀条消息正在运⾏:节点仅在另⼀条消息到达它们时才⽣成⼀条消息。
我们这样做是为了使跟踪仿真变得更加容易。
更改模块类,以便改为定期⽣成消息。
消息之间的间隔应该是⼀个模块参数,返回指数分布的随机数。