tictoc 6-9
- tictoc 6 自消息实现计时
- tictoc 7 节点等待时延随机,丢失包概率
- tictoc 8 两个节点分别定义两个类
- tictoc 9 保留原始包副本,从而不需要重新构建包
 
tictoc 6 自消息实现计时
- 在前面的模型中,’ tic’和’ toc’立即将收到的消息发送回。这里将添加一些计时:tic和toc将在将消息发送回之前模拟地保持消息1秒。
 在omnet++中,这种计时是通过模块向自身发送消息来实现的。
 这样的消息称为自消息(但仅仅是因为它们的使用方式,否则它们就是完全普通的消息)或事件。
- 可以使用scheduleAt()函数“发送”自消息,并且您可以指定它们应该在何时返回模块。
- 我们不会立即开始,而是向自己发送一条信息(“自我信息”)——当它返回给我们时,我们会在模拟时间t=5.0时进行第一次发送。(tictocMsg = new cMessage("tictocMsg"); scheduleAt(5.0, event);)
- 自我消息到达了,所以我们可以发送tictocMsg和nullptr它的指针,这样以后就不会让我们感到困惑了。(send(tictocMsg, "out"); tictocMsg = nullptr;)
- 如果我们收到的信息不是我们的自我信息,那么它一定是我们的伴侣发来的信息。我们记住它在tictocMsg变量中的指针,然后安排我们的自消息在模拟的1s时间内返回给我们。(scheduleAt(simTime()+1.0, event);)
ned文件(还是两个结点不变)
simple Txc6
{
    parameters:
        @display("i=block/routing");
    gates:
        input in;
        output out;
}
network Tictoc6
{
    submodules:
        tic: Txc6 {
            parameters:
                @display("i=,cyan");
        }
        toc: Txc6 {
            parameters:
                @display("i=,gold");
        }
    connections:
        tic.out --> {  delay = 100ms; } --> toc.in;
        tic.in <-- {  delay = 100ms; } <-- toc.out;
}
cc文件
#include <stdio.h>
#include <string.h>
#include <omnetpp.h>
using namespace omnetpp;
/**
 * In the previous models, `tic' and `toc' immediately sent back the
 * received message. Here we'll add some timing: tic and toc will hold the
 * message for 1 simulated second before sending it back. In OMNeT++
 * such timing is achieved by the module sending a message to itself.
 * Such messages are called self-messages (but only because of the way they
 * are used, otherwise they are completely ordinary messages) or events.
 * Self-messages can be "sent" with the scheduleAt() function, and you can
 * specify when they should arrive back at the module.
 *
 * We leave out the counter, to keep the source code small.
 * 在前面的模型中,' tic'和' toc'立即将收到的消息发送回。这里我们将添加一些计时:tic和toc将在将消息发送回之前模拟地保持消息1秒。在omnet++中,这种计时是通过模块向自身发送消息来实现的。这样的消息称为自消息(但仅仅是因为它们的使用方式,否则它们就是完全普通的消息)或事件。可以使用scheduleAt()函数“发送”自消息,并且您可以指定它们应该在何时返回模块。
 */
class Txc6 : public cSimpleModule
{
  private:
    cMessage *event;  // pointer to the event object which we'll use for timing,指向我们将用于计时的事件对象的指针
    cMessage *tictocMsg;  // variable to remember the message until we send it back,变量来记住消息,直到我们将其发送回
  public:
    Txc6();
    virtual ~Txc6();
  protected:
    virtual void initialize() override;
    virtual void handleMessage(cMessage *msg) override;
};
Define_Module(Txc6);
Txc6::Txc6()
{
    // Set the pointer to nullptr, so that the destructor won't crash
    // even if initialize() doesn't get called because of a runtime
    // error or user cancellation during the startup process.
    //将指针设置为nullptr,这样即使在启动过程中由于运行时错误或用户取消而没有调用initialize(),析构函数也不会崩溃。
    event = tictocMsg = nullptr;
}
Txc6::~Txc6()
{
    // Dispose of dynamically allocated the objects,处理动态分配的对象
    cancelAndDelete(event);
    delete tictocMsg;
}
void Txc6::initialize()
{
    // Create the event object we'll use for timing -- just any ordinary message.创建用于计时的事件对象——任何普通消息。
    event = new cMessage("event");
    // No tictoc message yet.
    tictocMsg = nullptr;
    if (strcmp("tic", getName()) == 0) {
        // We don't start right away, but instead send an message to ourselves
        // (a "self-message") -- we'll do the first sending when it arrives
        // back to us, at t=5.0s simulated time.我们不会立即开始,而是向自己发送一条信息(“自我信息”)——当它返回给我们时,我们会在模拟时间t=5.0时进行第一次发送。
        EV << "Scheduling first send to t=5.0s\n";
        tictocMsg = new cMessage("tictocMsg");
        scheduleAt(5.0, event);
    }
}
void Txc6::handleMessage(cMessage *msg)
{
    // There are several ways of distinguishing messages, for example by message
    // kind (an int attribute of cMessage) or by class using dynamic_cast
    // (provided you subclass from cMessage). In this code we just check if we
    // recognize the pointer, which (if feasible) is the easiest and fastest
    // method.
    //有几种方法来区分消息,例如通过消息类型(cMessage的int属性)或通过使用dynamic_cast的类(提供来自cMessage的子类)。在这段代码中,我们只是检查是否识别了指针,这(如果可行)是最简单和最快的方法。
    if (msg == event) {
        // The self-message arrived, so we can send out tictocMsg and nullptr out
        // its pointer so that it doesn't confuse us later. 自我消息到达了,所以我们可以发送tictocMsg和nullptr它的指针,这样以后就不会让我们感到困惑了。
        EV << "Wait period is over, sending back message\n";
        send(tictocMsg, "out");
        tictocMsg = nullptr;
    }
    else {
        // If the message we received is not our self-message, then it must
        // be the tic-toc message arriving from our partner. We remember its
        // pointer in the tictocMsg variable, then schedule our self-message
        // to come back to us in 1s simulated time.如果我们收到的信息不是我们的自我信息,那么它一定是我们的伴侣发来的一字合一的信息。我们记住它在tictocMsg变量中的指针,然后安排我们的自消息在模拟的1s时间内返回给我们。
        EV << "Message arrived, starting to wait 1 sec...\n";
        tictocMsg = msg;
        scheduleAt(simTime()+1.0, event);
    }
}

tictoc 7 节点等待时延随机,丢失包概率
- 这一步我们引入随机数。我们将延迟从1更改为一个可以从NED文件或omnetpp.ini中设置的随机值。此外,我们会以很小的概率“丢失”(删除)数据包。
- ini初始化中在等待自消息结束后,其中一个节点开始向对方发送消息
- 处理消息时候,如果是自消息事件,则继续发送消息出去。否则会有个丢失概率为0.1 的判断if (uniform(0, 1) < 0.1),可能会丢失消息
- “delayTime"模块参数可以设置为"exponential(5)”(tictoc7。Ned, omnetpp.ini),然后在这里我们每次都会得到不同的延迟。
ini配置
[Config Tictoc7]
network = Tictoc7
# argument to exponential() is the mean; truncnormal() returns values from
#指数()的参数是平均值;Truncnormal()返回来自的值
# the normal distribution truncated to nonnegative values
#正态分布截断为非负值
Tictoc7.tic.delayTime = exponential(3s)
Tictoc7.toc.delayTime = truncnormal(3s,1s)
ned文件
simple Txc7
{
    parameters:
        volatile double delayTime @unit(s);   // delay before sending back message,发送回消息前的延迟
        @display("i=block/routing");
    gates:
        input in;
        output out;
}
network Tictoc7
{
    submodules:
        tic: Txc7 {
            parameters:
                @display("i=,cyan");
        }
        toc: Txc7 {
            parameters:
                @display("i=,gold");
        }
    connections:
        tic.out --> {  delay = 100ms; } --> toc.in;
        tic.in <-- {  delay = 100ms; } <-- toc.out;
}
cc文件
#include <stdio.h>
#include <string.h>
#include <omnetpp.h>
using namespace omnetpp;
/**
 * In this step we'll introduce random numbers. We change the delay from 1s
 * to a random value which can be set from the NED file or from omnetpp.ini.
 * In addition, we'll "lose" (delete) the packet with a small probability.
 * 这一步我们引入随机数。我们将延迟从1更改为一个可以从NED文件或omnetpp.ini中设置的随机值。此外,我们会以很小的概率“丢失”(删除)数据包。
 */
class Txc7 : public cSimpleModule
{
  private:
    cMessage *event;
    cMessage *tictocMsg;
  public:
    Txc7();
    virtual ~Txc7();
  protected:
    virtual void initialize() override;
    virtual void handleMessage(cMessage *msg) override;
};
Define_Module(Txc7);
Txc7::Txc7()
{
    event = tictocMsg = nullptr;
}
Txc7::~Txc7()
{
    cancelAndDelete(event);
    delete tictocMsg;
}
void Txc7::initialize()
{
    event = new cMessage("event");
    tictocMsg = nullptr;
    if (strcmp("tic", getName()) == 0) {
        EV << "Scheduling first send to t=5.0s\n";
        scheduleAt(5.0, event);
        tictocMsg = new cMessage("tictocMsg");
    }
}
void Txc7::handleMessage(cMessage *msg)
{
    if (msg == event) {
        EV << "Wait period is over, sending back message\n";
        send(tictocMsg, "out");
        tictocMsg = nullptr;
    }
    else {
        // "Lose" the message with 0.1 probability:“丢失”信息的概率为0.1:
        if (uniform(0, 1) < 0.1) {
            EV << "\"Losing\" message\n";
            delete msg;
        }
        else {
            // The "delayTime" module parameter can be set to values like
            // "exponential(5)" (tictoc7.ned, omnetpp.ini), and then here
            // we'll get a different delay every time.
            //"delayTime"模块参数可以设置为"指数(5)"(tictoc7。Ned, omnetpp.ini),然后在这里我们每次都会得到不同的延迟。
            simtime_t delay = par("delayTime");
            EV << "Message arrived, starting to wait " << delay << " secs...\n";
            tictocMsg = msg;
            scheduleAt(simTime()+delay, event);
        }
    }
}

tictoc 8 两个节点分别定义两个类
- 让我们退一步,从代码中去除随机延迟。然而,我们会离开,以很小的可能性失去这个包。我们会做一些在电信网络中很常见的事情:如果数据包在一定时间内没有到达,我们就会假设它丢失了,并创建另一个。超时将使用(还有什么?)一条自消息来处理。
 ned文件,tic 和toc 分开各自定义
simple Tic8
{
    parameters:
        @display("i=block/routing");
    gates:
        input in;
        output out;
}
simple Toc8
{
    parameters:
        @display("i=block/process");
    gates:
        input in;
        output out;
}
network Tictoc8
{
    submodules:
        tic: Tic8 {
            parameters:
                @display("i=,cyan");
        }
        toc: Toc8 {
            parameters:
                @display("i=,gold");
        }
    connections:
        tic.out --> {  delay = 100ms; } --> toc.in;
        tic.in <-- {  delay = 100ms; } <-- toc.out;
}
cc文件
#include <stdio.h>
#include <string.h>
#include <omnetpp.h>
using namespace omnetpp;
/**
 * Let us take a step back, and remove random delaying from the code.
 * We'll leave in, however, losing the packet with a small probability.
 * And, we'll we do something very common in telecommunication networks:
 * if the packet doesn't arrive within a certain period, we'll assume it
 * was lost and create another one. The timeout will be handled using
 * (what else?) a self-message.
 * 让我们退一步,从代码中去除随机延迟。然而,我们会离开,以很小的可能性失去这个包。我们会做一些在电信网络中很常见的事情:如果数据包在一定时间内没有到达,我们就会假设它丢失了,并创建另一个。超时将使用(还有什么?)一条自消息来处理。
 */
class Tic8 : public cSimpleModule
{
  private:
    simtime_t timeout;  // timeout
    cMessage *timeoutEvent;  // holds pointer to the timeout self-message 保持指向超时自消息的指针
  public:
    Tic8();
    virtual ~Tic8();
  protected:
    virtual void initialize() override;
    virtual void handleMessage(cMessage *msg) override;
};
Define_Module(Tic8);
Tic8::Tic8()
{
    timeoutEvent = nullptr;
}
Tic8::~Tic8()
{
    cancelAndDelete(timeoutEvent);
}
void Tic8::initialize()
{
    // Initialize variables.
    timeout = 1.0;
    timeoutEvent = new cMessage("timeoutEvent");
    // Generate and send initial message.
    EV << "Sending initial message\n";
    cMessage *msg = new cMessage("tictocMsg");
    send(msg, "out");
    scheduleAt(simTime()+timeout, timeoutEvent);
}
void Tic8::handleMessage(cMessage *msg)
{
    if (msg == timeoutEvent) {
        // If we receive the timeout event, that means the packet hasn't
        // arrived in time and we have to re-send it.
        EV << "Timeout expired, resending message and restarting timer\n";
        cMessage *newMsg = new cMessage("tictocMsg");
        send(newMsg, "out");
        scheduleAt(simTime()+timeout, timeoutEvent);
    }
    else {  // message arrived
            // Acknowledgement received -- delete the received message and cancel
            // the timeout event.
        EV << "Timer cancelled.\n";
        cancelEvent(timeoutEvent);
        delete msg;
        // Ready to send another one.
        cMessage *newMsg = new cMessage("tictocMsg");
        send(newMsg, "out");
        scheduleAt(simTime()+timeout, timeoutEvent);
    }
}
/**
 * Sends back an acknowledgement -- or not.
 */
class Toc8 : public cSimpleModule
{
  protected:
    virtual void handleMessage(cMessage *msg) override;
};
Define_Module(Toc8);
void Toc8::handleMessage(cMessage *msg)
{
    if (uniform(0, 1) < 0.1) {
        EV << "\"Losing\" message.\n";
        bubble("message lost");  // making animation more informative...使动画更加翔实..
        delete msg;
    }
    else {
        EV << "Sending back same message as acknowledgement.\n";
        send(msg, "out");
    }
}

tictoc 9 保留原始包副本,从而不需要重新构建包
- 在前面的模型中,如果需要重传,我们只创建另一个包。这是可以的,因为包包含的内容并不多,但在现实生活中,通常更实际的做法是保留原始包的副本,这样我们就可以重新发送它,而不需要重新构建它。
- 复制包:
void Tic9::sendCopyOf(cMessage *msg)
{
    // Duplicate message and send the copy.
    cMessage *copy = (cMessage *)msg->dup();
    send(copy, "out");
}
创建并返回此对象的精确副本,但消息ID除外(克隆被分配了一个新ID)。注意,消息的创建时间也会被复制,因此相同消息对象的克隆具有相同的创建时间。参见cObject了解更多细节。
/**
     * Creates and returns an exact copy of this object, except for the
     * message ID (the clone is assigned a new ID). Note that the message
     * creation time is also copied, so clones of the same message object
     * have the same creation time. See cObject for more details.
     * 创建并返回此对象的精确副本,但消息ID除外(克隆被分配了一个新ID)。
     * 注意,消息的创建时间也会被复制,因此相同消息对象的克隆具有相同的创建时间。
     * 参见cObject了解更多细节。
     */
    virtual cMessage *dup() const override  {return new cMessage(*this);}
ned文件
simple Tic9
{
    parameters:
        @display("i=block/routing");
    gates:
        input in;
        output out;
}
simple Toc9
{
    parameters:
        @display("i=block/process");
    gates:
        input in;
        output out;
}
//
// Same as Tictoc8.
//
network Tictoc9
{
    submodules:
        tic: Tic9 {
            parameters:
                @display("i=,cyan");
        }
        toc: Toc9 {
            parameters:
                @display("i=,gold");
        }
    connections:
        tic.out --> {  delay = 100ms; } --> toc.in;
        tic.in <-- {  delay = 100ms; } <-- toc.out;
}
cc文件
#include <stdio.h>
#include <string.h>
#include <omnetpp.h>
using namespace omnetpp;
/**
 * In the previous model we just created another packet if we needed to
 * retransmit. This is OK because the packet didn't contain much, but
 * in real life it's usually more practical to keep a copy of the original
 * packet so that we can re-send it without the need to build it again.
 * 在前面的模型中,如果需要重传,我们只创建另一个包。这是可以的,因为包包含的内容并不多,但在现实生活中,通常更实际的做法是保留原始包的副本,这样我们就可以重新发送它,而不需要重新构建它。
 */
class Tic9 : public cSimpleModule
{
  private:
    simtime_t timeout;  // timeout
    cMessage *timeoutEvent;  // holds pointer to the timeout self-message
    int seq;  // message sequence number
    cMessage *message;  // message that has to be re-sent on timeout
  public:
    Tic9();
    virtual ~Tic9();
  protected:
    virtual cMessage *generateNewMessage();
    virtual void sendCopyOf(cMessage *msg);
    virtual void initialize() override;
    virtual void handleMessage(cMessage *msg) override;
};
Define_Module(Tic9);
Tic9::Tic9()
{
    timeoutEvent = message = nullptr;
}
Tic9::~Tic9()
{
    cancelAndDelete(timeoutEvent);
    delete message;
}
void Tic9::initialize()
{
    // Initialize variables.
    seq = 0;
    timeout = 1.0;
    timeoutEvent = new cMessage("timeoutEvent");
    // Generate and send initial message.
    EV << "Sending initial message\n";
    message = generateNewMessage();
    sendCopyOf(message);//拷贝并发送
    scheduleAt(simTime()+timeout, timeoutEvent);
}
void Tic9::handleMessage(cMessage *msg)
{
    if (msg == timeoutEvent) {
        // If we receive the timeout event, that means the packet hasn't
        // arrived in time and we have to re-send it.
        EV << "Timeout expired, resending message and restarting timer\n";
        sendCopyOf(message);
        scheduleAt(simTime()+timeout, timeoutEvent);
    }
    else {  // message arrived
            // Acknowledgement received!
        EV << "Received: " << msg->getName() << "\n";
        delete msg;
        // Also delete the stored message and cancel the timeout event.
        EV << "Timer cancelled.\n";
        cancelEvent(timeoutEvent);
        delete message;
        // Ready to send another one.
        message = generateNewMessage();
        sendCopyOf(message);
        scheduleAt(simTime()+timeout, timeoutEvent);
    }
}
cMessage *Tic9::generateNewMessage()
{
    // Generate a message with a different name every time.
    char msgname[20];
    sprintf(msgname, "tic-%d", ++seq);
    cMessage *msg = new cMessage(msgname);
    return msg;
}
void Tic9::sendCopyOf(cMessage *msg)
{
    // Duplicate message and send the copy.
    cMessage *copy = (cMessage *)msg->dup();
    send(copy, "out");
}
/**
 * Sends back an acknowledgement -- or not.
 */
class Toc9 : public cSimpleModule
{
  protected:
    virtual void handleMessage(cMessage *msg) override;
};
Define_Module(Toc9);
void Toc9::handleMessage(cMessage *msg)
{
    if (uniform(0, 1) < 0.1) {
        EV << "\"Losing\" message " << msg << endl;
        bubble("message lost");
        delete msg;
    }
    else {
        EV << msg << " received, sending back an acknowledgement.\n";
        delete msg;
        send(new cMessage("ack"), "out");
    }
}



















