⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 token.cpp

📁 simulation tokenring network
💻 CPP
字号:
//
// This file is part of an OMNeT++/OMNEST simulation example.
//
// Copyright (C) 1992-2005 Andras Varga
//
// This file is distributed WITHOUT ANY WARRANTY. See the file
// `license' for details on this and other legal matters.
//


//
// Authors: Gabor Lencse, Andras Varga (TU Budapest)
// Based on the code by:
//          Maurits Andre, George van Montfort,
//          Gerard van de Weerd (TU Delft)
//

#include <omnetpp.h>
#include "token_m.h"


// Token length is 3 octets (24 bits)
#define TR_TOKEN_BITS  24

// Frame header and trailer are 21 octets (168 bits), with the following
// frame layout (lengths in parens):
//   SD(1), AC(1), FC(1), DEST(6), SOURCE(6), DATA(n), CS(4), ED(1), FS(1)
#define TR_HEADER_BITS 168

#define STACKSIZE 16384


/**
 * Token Ring MAC layer; see NED file for more info.
 */
class TokenRingMAC : public cSimpleModule
{
  private:
    // configuration
    int myAddress;
    long dataRate;
    simtime_t tokenHoldingTime;
    int queueMaxLen;
    bool debug;

    // state variables
    cQueue sendQueue;    // send buffer
    int sendQueueBytes;  // queue length in bytes

    cMessage *transmEnd; // self-message to signal end of transmission
    cMessage *recvEnd;   // self-message to signal end of reception

    TRToken *token;      // non-NULL while we're holding the token


    // statistics
    cOutVector queueLenPackets;
    cOutVector queueLenBytes;
    cOutVector queueingTime;
    int numPacketsToSend;
    int numPacketsToSendDropped;
    cOutVector queueDrops;

  public:
    TokenRingMAC();
    virtual ~TokenRingMAC();

  protected:
    virtual void activity();
    virtual void finish();
    virtual void handleMessagesWhileTransmitting();
    virtual void storeDataPacket(TRApplicationData *data);
    virtual void beginReceiveFrame(TRFrame *frame);
    virtual void endReceiveFrame(cMessage *data);
};


Define_Module( TokenRingMAC );


TokenRingMAC::TokenRingMAC() : cSimpleModule(STACKSIZE)
{
    transmEnd = recvEnd = token = NULL;
}

TokenRingMAC::~TokenRingMAC()
{
    cancelAndDelete(transmEnd);
    cancelAndDelete(recvEnd);
    delete token;
}

void TokenRingMAC::activity()
{
    dataRate = par("dataRate");     // 4 or 16 Mbit/s
    tokenHoldingTime = par("THT");   // typically 10ms
    myAddress = par("address");
    queueMaxLen = par("queueMaxLen");

    debug = true;
    WATCH(debug);

    sendQueue.setName("sendQueue");
    sendQueueBytes = 0;
    WATCH (sendQueueBytes);
    queueLenPackets.setName("Queue length (packets)");
    queueLenBytes.setName("Queue length (bytes)");
    queueingTime.setName("Queueing time (sec)");

    numPacketsToSend = 0;
    WATCH (numPacketsToSend);
    numPacketsToSendDropped = 0;
    WATCH (numPacketsToSendDropped);
    queueDrops.setName("App data packets dropped");

    char msgname[30];

    transmEnd = new cMessage("transmEnd");
    recvEnd = new cMessage("recvEnd");

    // station 0 issues the token
    if (myAddress == 0)
    {
        TRToken *token = new TRToken("token", TR_TOKEN);
        token->setLength(TR_TOKEN_BITS);
        send(token, "phy_out");
    }

    // enter token ring protocol
    for(;;)
    {
        cMessage *msg = receive();

        // data from higher layer?
        if (dynamic_cast<TRApplicationData *>(msg)!=NULL)
        {
            // store packet in queue and update statistics
            storeDataPacket((TRApplicationData *)msg);
        }
        // token arrived?
        else if (dynamic_cast<TRToken *>(msg)!=NULL)
        {
            token = (TRToken *)msg;
            if (debug)
            {
                ev << "Token arrived (we can keep it for THT=" << simtimeToStr(tokenHoldingTime) << ")" << endl;
                if (ev.isGUI())
                {
                    parentModule()->displayString().setTagArg("i",1,"gold");
                    parentModule()->displayString().setTagArg("t",0,"ACTIVE");
                    parentModule()->displayString().setTagArg("t",2,"#707000");
                    parentModule()->bubble(sendQueue.empty() ? "Nothing to send!" : "Captured token.");
                }
            }


            // if we have messages to send, send them now, within the tokenHoldingTime
            simtime_t tokenHoldingTime_expires = simTime()+tokenHoldingTime;
            while (!sendQueue.empty())
            {
                // peek at next data packet and see if it can be sent within the tokenHoldingTime
                TRApplicationData *data = (TRApplicationData *) sendQueue.tail();
                simtime_t transmission_time = (TR_HEADER_BITS+data->length())/(double)dataRate;
                if (simTime()+transmission_time > tokenHoldingTime_expires)
                {
                    // no time left for this packet
                    if (debug)
                    {
                        ev << "Data packet \"" << data->name() << "\" cannot be sent within THT, skipping" << endl;
                    }
                    break;
                }

                // remove data packet from the send buffer
                sendQueue.pop();
                sendQueueBytes -= data->length()/8;
                queueLenPackets.record(sendQueue.length());
                queueLenBytes.record(sendQueueBytes);

                // write queueing time statistics
                queueingTime.record(simTime() - data->timestamp());

                // create Token Ring frame, and send data in it
                sprintf(msgname, "%d-->%d", myAddress, data->getDestination());
                TRFrame *frame = new TRFrame(msgname, TR_FRAME);
                frame->setLength(TR_HEADER_BITS);
                frame->setSource(myAddress);
                frame->setDestination(data->getDestination());
                frame->encapsulate(data);

                if (debug)
                {
                    ev << "Begun transmitting \"" << data->name() << "\""
                          " in frame \"" << frame->name() << "\"" << endl;
                }
                send(frame, "phy_out");

                simtime_t transmStartTime = simTime();

                // we're busy until we finished transmission
                scheduleAt(simTime()+transmission_time, transmEnd);
                handleMessagesWhileTransmitting();

                if (debug)
                {
                    ev << "End transmission " << simtimeToStr(transmStartTime) << endl;
                }
            }

            // release token
            if (debug)
            {
                ev << "Releasing token." << endl;
                if (ev.isGUI())
                {
                    parentModule()->displayString().setTagArg("i",1,"");
                    parentModule()->displayString().setTagArg("t",0,"");
                }
            }
            send(token, "phy_out");
            token = NULL;
        }

        // frame arrived from network?
        else if (dynamic_cast<TRFrame *>(msg)!=NULL)
        {
            TRFrame *frame = (TRFrame *)msg;
            beginReceiveFrame(frame);
        }
        // end receiving a packet?
        else if (msg==recvEnd)
        {
            cMessage *data = (cMessage *) recvEnd->contextPointer();
            endReceiveFrame(data);
        }
        else
        {
            throw new cRuntimeError("unexpected message arrived: (%s)%s", msg->className(), msg->name());
        }
    }
}

void TokenRingMAC::handleMessagesWhileTransmitting()
{
    cMessage *msg;
    while ((msg = receive())!=transmEnd)
    {
        // while we are transmitting, a token cannot arrive (because
        // we hold it), but any of the other events may occur:

        // data from higher layer
        if (dynamic_cast<TRApplicationData *>(msg)!=NULL)
        {
            // store packet in queue and update statistics
            storeDataPacket((TRApplicationData *)msg);
        }
        // frame from network (must be one of our own frames)
        else if (dynamic_cast<TRFrame *>(msg)!=NULL)
        {
            TRFrame *frame = (TRFrame *)msg;
            beginReceiveFrame(frame);
        }
        // end receiving a packet (if we sent a frame to ourselves,
        // its reception may end while we're still transmitting)
        else if (msg==recvEnd)
        {
            cMessage *data = (cMessage *) recvEnd->contextPointer();
            endReceiveFrame(data);
        }
        else
        {
            throw new cRuntimeError("unexpected message arrived: (%s)%s", msg->className(), msg->name());
        }
    }
}

void TokenRingMAC::storeDataPacket(TRApplicationData *msg)
{
    if (debug)
    {
        ev << "App data received from higher layer: \"" << msg->name() << "\", "
              "length=" << msg->length()/8 << "bytes" << endl;
    }

    // inc counter
    numPacketsToSend++;

    // if queue is full, we have to drop it
    if (sendQueue.length() >= queueMaxLen)
    {
        if (debug)
        {
            ev << "Queue full, DROPPED!" << endl;
        }
        delete msg;
        numPacketsToSendDropped++;
        queueDrops.record(numPacketsToSendDropped);
        return;
    }

    // mark enqeueing time, we'll need it for calculating time spent in queue
    msg->setTimestamp();

    // insert message into send buffer
    sendQueue.insert( msg );
    sendQueueBytes += msg->length()/8;
    queueLenPackets.record( sendQueue.length() );
    queueLenBytes.record(sendQueueBytes);

    if (debug)
    {
        ev << "Enqueued, queue length=" << sendQueue.length() << endl;
    }

}

void TokenRingMAC::beginReceiveFrame(TRFrame *frame)
{
    if (debug)
    {
        ev << "Received beginning of frame \"" << frame->name() << "\"" << endl;
    }

    // extract source and destination
    int dest = frame->getDestination();
    int source = frame->getSource();

    // is this station the addressee?
    if (dest == myAddress)
    {
        if (debug)
        {
            ev << "We are the destination: as soon as we fully received the frame," << endl;
            ev << "we'll pass up a copy of the payload \"" <<
                  frame->encapsulatedMsg()->name() << "\" to the higher layer." << endl;
            ev << "Frame will be extracted from the ring by the sender." << endl;
        }

        // some sanity check: because of rounding errors in double arithmetic,
        // it is possible that the "beginning of a frame" event arrives earlier
        // than the "end of receiving the previous frame" (recvEnd) event.
        // In this case, we do as if we've'd just received the recvEnd event
        // (as we should have, ideally).
        if (recvEnd->isScheduled())
        {
            // make sure our assumption is right
            ASSERT(fabs(recvEnd->arrivalTime()-simTime())<1e-10);

            if (debug)
            {
                ev << "'recvEnd' event should have occurred already, do it now" << endl;
            }

            // then remedy the situation
            cancelEvent(recvEnd);
            cMessage *data = (cMessage *) recvEnd->contextPointer();
            endReceiveFrame(data);
        }

        // make a copy of the payload in the frame -- we'll send this one
        // to the higher layer
        cMessage *data2 = (cMessage *) frame->encapsulatedMsg()->dup();

        // The arrival of a message in the model represents the arrival
        // of the first bit of the packet. It has to be completely received
        // before we can pass it up to the higher layer. So here we compute
        // when receiving will finish, and schedule an event for that time.
        //
        recvEnd->setContextPointer(data2);
        scheduleAt(simTime()+frame->length()/(double)dataRate, recvEnd);
    }

    // In the Token Ring protocol, a frame is stripped out from the ring
    // by the source of the frame when the frame arrives back to its
    // originating station. The addresse just repeats the frame, like
    // any other station in the ring.
    if (source == myAddress)
    {
        if (debug)
        {
            ev << "Arrived back to sender, stripping it out of the ring" << endl;
        }
        delete frame;
    }
    else
    {
        if (debug)
        {
            ev << "Forwarding to next station" << endl;
        }
        send(frame, "phy_out");
    }
}

void TokenRingMAC::endReceiveFrame(cMessage *data)
{
    if (debug)
    {
        ev << "End receiving frame containing \"" << data->name() << "\", passing up to higher layer." << endl;
    }
    send(data, "to_hl");
}

void TokenRingMAC::finish()
{
    ev << "Module: " << fullPath() << endl;
    ev << "Total packets received from higher layer: " << numPacketsToSend << endl;
    ev << "Higher layer still in queue: " << sendQueue.length() << endl;
    ev << "Higher layer packets dropped: " << numPacketsToSendDropped << endl;
    if (numPacketsToSend>sendQueue.length())
    {
        ev << "Percentage dropped: " << (100*numPacketsToSendDropped/(numPacketsToSend-sendQueue.length())) << "%" << endl;
    }
    ev << endl;
}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -