对于tictoc中18个简单样例的学习提炼
OMNet++文件主要有三种
- .ned文件:用于构建网络拓扑,包括节点端口和节点之间的连接的各种信息。如节点的输入输出端口名称、在图上的颜色位置,节点之间的延迟、距离等。
- .cc文件:节点的类文件,包含节点的字段以及各项函数
- .ini文件:设置整个网络,可以在这里设置网络中全部或某个字段的值
在cc文件中如果需要调用ini中设置的参数,可使用par函数
//ini中 TicTok.tic.t = 1//TicTok是网络名,tic是节点名字,这里都是名字不是类型 //cc中 int t = par("t)
1、涉及到的方法
OMNeT++ Simulation Library: Class List (omnetpp.org)这里有官方的api可以自行查看,这里只涉及案例中提到的。
send(msg,"out") | 从out端口发送消息 |
scheduleAt(simTime()+time,event) | 经过time事件后的自发送消息 |
cancelEvent(event) | 取消准备发送的自发送消息 |
bubble("msg lost") | 在拓扑图上弹窗提醒 |
exponential(n) //如exponrntial(2s) | 指数分布的随机数 |
truncnormal(a,b)// 如truncnormal(3s,1s) | [a,b]之间的离散正态分布随机数 |
uniform(a,b)/intuniform(a,b) | [a,b]之间随机实数/整数 |
cMessage类:
cMessage可以被分配一个名称(这是从cNamedObject继承的属性);其他属性包括消息类型、优先级和时间戳。可以使用
方法:dup()
函数克隆消息。控制信息字段方便了协议层之间的通信建模。上下文指针字段使得同时处理多个定时器(自消息)更容易。消息还存储了关于其最后一次发送的信息,包括发送时间、到达时间、到达模块和门。
cMessage(const char *name=nullptr,short kind=0) 带有名字和类型的构造函数 dup() 创建并返回该对象的精确副本,但消息ID除外(克隆将被分配一个新的ID)。
2、如何模拟消息发生的各种情况
- 消息丢包(节点内部处理)
void Txc::handleMessage(cMessage *msg) { //使用随机数模拟90%的丢包率 if (uniform(0, 1) < 0.1) { EV << "\"Losing\" message\n"; delete msg; } else { //正常处理 } }
- 消息超时重传(tictoc8)
- 消息发送端同时发送两条消息,一条给目标节点,一条设定超时时间后自发送。
- 如在超时时间内收到回复消息,则取消自发送。
- 为在超时时间内收到消息,则会受到自发送消息,此时重新发送消息。
下为具体代码,在TicTok8的基础上略改动
void Tic8::initialize() { //设置超时时间为1S,并生成超时消息和发送消息 timeout = 1.0; timeoutEvent = new cMessage("timeoutEvent"); cMessage *msg = new cMessage("tictocMsg"); //发送消息到目标节点和自己 send(msg, "out"); scheduleAt(simTime()+timeout, timeoutEvent); } //重写的消息接收函数 void Tic8::handleMessage(cMessage *msg) { if (msg == timeoutEvent) { //如果收到的是自己的消息,则证明消息超时,这里重传 cMessage *newMsg = new cMessage("tictocMsg"); send(newMsg, "out"); scheduleAt(simTime()+timeout, timeoutEvent); } else { //收到目标节点回信,取消发送的自发送消息 cancelEvent(timeoutEvent); delete msg; // 继续发送下一条消息 cMessage *newMsg = new cMessage("tictocMsg"); send(newMsg, "out"); scheduleAt(simTime()+timeout, timeoutEvent); } }
- 自定义通道类型(tictoc11)
在tictoc10中引入的一个类型节点的多个门,在11中进行改进,使用了自定义通道。10和11的整体逻辑是:生成6个节点,且每个节点由一个或多个出、入门。在0号节点初始化时发送一条消息到随机节点(可以到的节点),之后这条消息在各个节点之间随机传送,直到发送到3号节点。
network Tictoc11 { types: channel Channel extends ned.DelayChannel { delay = 100ms; } submodules: tic[6]: Txc11; connections://注意这里是++,在连接完后出入门会+1, //在这个案例中0号由出入门各一个,1号有出入门各三个 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++; }
这里使用自定义channel替换了原来的{delay=100ms},使得仿真图中的各个节点分开,不在重合。此外还有其它类型的通道定义方法如下:
- 理想通道
channel IdealChannel extends ned.DatarateChannel { datarate = 1Gbps; // 数据传输速率 }
- 错误率设置
channel WirelessChannel extends ned.ErrorRateChannel { error = 0.01; // 通道中的错误率 }
- 输入门和输出门 合并(tictok12)
直接设置inout门替换之前的in/out门
simple Txc12 { parameters: @display("i=block/routing"); gates: inout gate[] } network Tictoc12 { @display("bgb=550,332"); types: channel Channel extends ned.DelayChannel { delay = 100ms; } submodules: tic[6]: Txc12 { @display("p=165,143"); } 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++; }
在选择需要发送的门是入门还是出门时使用如下代码
send(msg, "gate$o", k);//表示出门 send(msg, "gate$i", k);//表示入门