写在最前

前一篇博客谢了关于ALOHA的一些原理,现在看OMNeT++这个网络仿真软件的sample是如何实现ALOHA网络的。

代码

Server.ned

simple Server
{parameters:@display("i=device/antennatower_l");@signal[receiveBegin](type="long");  // increases with each new frame arriving to the server and drops to 0 if the channel becomes finally idle@signal[receive](type="long");  // for successful receptions (non-collisions): 1 at the start of the reception, 0 at the end of the reception@signal[collision](type="long"); // the number of collided frames at the beginning of the collision period@signal[collisionLength](type="simtime_t");  // the length of the last collision period at the end of the collision period@signal[channelState](type="long");//source @statistic[serverChannelState](source="channelState";title="Channel state";enum="IDLE=0,TRANSMISSION=1,COLLISION=2";record=vector);@statistic[receiveBegin](source="receiveBegin"; record=vector?; interpolationmode=sample-hold; title="receive begin");@statistic[channelUtilization](source="timeavg(receive)"; record=last; interpolationmode=linear; title="channel utilization");@statistic[collisionMultiplicity](source=collision; record=vector?,histogram; title="collision multiplicity");@statistic[collisionLength](record=vector?,histogram,mean,sum,max; title="collision length");@statistic[receivedFrames](source="sum(receive)"; record=last; title="received frames");@statistic[collidedFrames](source="sum(collision)"; record=last; title="collided frames");gates:input in @directIn;
}

.ned文件一般是用于OMNeT中模块与仿真内核的配置,里面一般包含该模块的parameter,gates,connections等等。其中这里Server.ned文件中,开头定义了一些signal,主要是配合后面的statistic来使用,用于统计仿真过程中需要的统计指标(如时延,信道利用率等)。还定义了一个输入用的gate。


Server.h

//
// This file is part of an OMNeT++/OMNEST simulation example.
//
// Copyright (C) 1992-2008 Andras Varga
//
// This file is distributed WITHOUT ANY WARRANTY. See the file
// `license' for details on this and other legal matters.
//#ifndef __ALOHA_SERVER_H_
#define __ALOHA_SERVER_H_#include <omnetpp.h>namespace aloha {/*** Aloha server; see NED file for more info.*/
class Server : public cSimpleModule
{private:// state variables, event pointersbool channelBusy;cMessage *endRxEvent;long currentCollisionNumFrames;long receiveCounter;simtime_t recvStartTime;enum {IDLE=0, TRANSMISSION=1, COLLISION=2};simsignal_t channelStateSignal;// statisticssimsignal_t receiveBeginSignal;simsignal_t receiveSignal;simsignal_t collisionLengthSignal;simsignal_t collisionSignal;public:Server();virtual ~Server();protected:virtual void initialize();virtual void handleMessage(cMessage *msg);virtual void finish();
};}; //namespace#endif

有了.ned文件后,需要有相应的源代码来定义这个模块的逻辑行为,如处理gate传入的消息,初始化等。一般的模块都是继承cSimpleModule,cSimpleModule中有一些虚函数,需要继承的子类实现,如handleMessage()这个函数。handleMessage()相当于一个模块的main函数,每次消息(cMessage)的传入,都会激活handleMessage函数来进行处理(相当于异步callback)。所以handleMessage函数是掌控整个模块的转态转换的关键。其次,initialize一般做一些parameter的初始化工作,外加一些signal的初始化工作。

Server.h中的变量都顾名思义,就不啰嗦了。


Server.cc
由于代码较多,分开来说明。

//
// This file is part of an OMNeT++/OMNEST simulation example.
//
// Copyright (C) 1992-2008 Andras Varga
//
// This file is distributed WITHOUT ANY WARRANTY. See the file
// `license' for details on this and other legal matters.
//
#include "Server.h"namespace aloha {Define_Module(Server);Server::Server()
{endRxEvent = NULL;
}Server::~Server()
{cancelAndDelete(endRxEvent);
}

声明了namespace,这是个好习惯。注意到,代码调用了宏Define_Module(Server),这是每个模块所必须的,这是为了向simulation kernel登记。
然后就是构造函数和析构函数。endRxEvent是在头文件定义的cMessage类型的成员,cMessage用途可以很广泛。

In the model, message objects represent events,packets, commands, jobs, customers or other kinds of entities, depending on the model domain.
析构函数,cancelAndDelete函数,取消在schedule event list 中endRxEvent,并且删除这个message。

void Server::initialize()
{channelStateSignal = registerSignal("channelState");endRxEvent = new cMessage("end-reception");channelBusy = false;emit(channelStateSignal,IDLE);//setDeliverOnReceptionStartgate("in")->setDeliverOnReceptionStart(true);currentCollisionNumFrames = 0;receiveCounter = 0;WATCH(currentCollisionNumFrames);receiveBeginSignal = registerSignal("receiveBegin");receiveSignal = registerSignal("receive");collisionSignal = registerSignal("collision");collisionLengthSignal = registerSignal("collisionLength");emit(receiveSignal, 0L);emit(receiveBeginSignal, 0L);if (ev.isGUI())getDisplayString().setTagArg("i2",0,"x_off");
}

主要做了初始化的工作。注意到,setDeliverOnReceptionStart在手册中的描述如下:

it instructs the simulation kernel to deliver packets arriving through that gate at the simulation time that corresponds to the beginning of the reception process.

simtime_t startTime, endTime;
if (pkt->isReceptionStart())
{
// gate was reprogrammed with setDeliverOnReceptionStart(true)startTime = pkt->getArrivalTime(); // or: simTime();endTime = startTime + pkt->getDuration();
}
else
{
// default caseendTime = pkt->getArrivalTime(); // or: simTime();startTime = endTime - pkt->getDuration();
}
ev << "interval: " << startTime << ".." << endTime << "\n";

从代码可以看出,这函数的意思就是,数据包到达模块的in gate 的时间是取值为first bit(true)或者 last bit(false)到达的时间。


void Server::handleMessage(cMessage *msg)
{if (msg==endRxEvent){EV << "reception finished\n";channelBusy = false;emit(channelStateSignal,IDLE);// update statisticssimtime_t dt = simTime() - recvStartTime;if (currentCollisionNumFrames==0){// start of reception at recvStartTimecTimestampedValue tmp(recvStartTime, 1l);emit(receiveSignal, &tmp);// end of reception nowemit(receiveSignal, 0);}else{// start of collision at recvStartTimecTimestampedValue tmp(recvStartTime, currentCollisionNumFrames);emit(collisionSignal, &tmp);emit(collisionLengthSignal, dt);}//reset the parameter of the statisticscurrentCollisionNumFrames = 0;receiveCounter = 0;emit(receiveBeginSignal, receiveCounter);// update network graphicsif (ev.isGUI()){getDisplayString().setTagArg("i2",0,"x_off");getDisplayString().setTagArg("t",0,"");}}else{//cast the packet to cPacket, return a pointercPacket *pkt = check_and_cast<cPacket *>(msg);//if not setDeliverOnReceptionStart in the initialize(), throw a exceptionASSERT(pkt->isReceptionStart());//see the manual in P83, the simulation start the reception when the first bit arrive//each arriving packet, compute the sim_time which ends in the futuresimtime_t endReceptionTime = simTime() + pkt->getDuration();emit(receiveBeginSignal, ++receiveCounter);if (!channelBusy){EV << "started receiving\n";recvStartTime = simTime();//change the state of the channelchannelBusy = true;emit(channelStateSignal, TRANSMISSION);//send a msg to myself when sim_time() arrive at endReceptionTimescheduleAt(endReceptionTime, endRxEvent);if (ev.isGUI()){getDisplayString().setTagArg("i2",0,"x_yellow");getDisplayString().setTagArg("t",0,"RECEIVE");getDisplayString().setTagArg("t",2,"#808000");}}else{EV << "another frame arrived while receiving -- collision!\n";//channelState is busy , then emit the COLLISION StateSignalemit(channelStateSignal, COLLISION);//sum the CollisionFrameif (currentCollisionNumFrames==0)currentCollisionNumFrames = 2;elsecurrentCollisionNumFrames++;if (endReceptionTime > endRxEvent->getArrivalTime()){//because setDeliverOn..Start(true), thus//endRxEvent->getArrivalTime() = the start time receive the packet//if the last endRxEvent receive time(first bit) after the time the current packet endReception time,//re-Schedule the endRxEvent with the new endReceptionTime//which mean until no more collision frame arrive, the period of receiving packet end(calculate the statistics)cancelEvent(endRxEvent);scheduleAt(endReceptionTime, endRxEvent);}// update network graphicsif (ev.isGUI()){getDisplayString().setTagArg("i2",0,"x_red");getDisplayString().setTagArg("t",0,"COLLISION");getDisplayString().setTagArg("t",2,"#800000");char buf[32];sprintf(buf, "Collision! (%ld frames)", currentCollisionNumFrames);bubble(buf);}}channelBusy = true;delete pkt;}
}void Server::finish()
{EV << "duration: " << simTime() << endl;recordScalar("duration", simTime());
}}; //namespace

这些代码已经添加了一些注释,在此基础上简略的讲讲。
server 的 handleMessage主要完成了以下的一些功能:

  • 以endRxEvent作为触发事件,当server完成了接收packet的过程后,就开始统计相关数据(冲突的frame或者成功接收packet),并将一些变量重置(channelBusy等)
  • 当msg 不为endRxEvent时,即为其他模块(host)发送过来的packet。需要进行统计,是否冲突,以channelBusy为参考。
  • 其实可以看出,代码并有论文所说的进行校验码校验(也就是没有对数据域消息进行仿真),仅从信道是否被占用来验证是否存在冲突。(仿真的一些指导经验)

handleMessage里常用的一些函数:

  • int scheduleAt(simtime_t t, cMessage *msg):用于向自身模块发送消息,类似于定时器触发事件一样。
  • cancelEvent(cMessage *msg):取消在FES(future event set)中的msg事件。

Host 的文件不再描述,与server非常相似。host在IDLE和TRANSMIT这两个状态中切换,值得一说的函数为:

  • int sendDirect(cMessage *msg, simtime_t propagationDelay, simtime_t duration, cGate *inputGate);
    直接向inputGate发送Message。

下一篇写这个sample仿真,看看统计的信息如何在IDE中显示,并分析结果数据。

参考文献

Parkman C. The OMNET manual[J]. CERN DD Division document.

OMNeT++ ALOHA sample代码阅读相关推荐

  1. 菜鸟笔记-DuReader阅读理解基线模型代码阅读笔记(八)—— 模型训练-训练

    系列目录: 菜鸟笔记-DuReader阅读理解基线模型代码阅读笔记(一)--数据 菜鸟笔记-DuReader阅读理解基线模型代码阅读笔记(二)-- 介绍及分词 菜鸟笔记-DuReader阅读理解基线模 ...

  2. VITAL Tracker Pytorch 代码阅读笔记

    VITAL Tracker Pytorch 代码阅读笔记 论文链接:https://arxiv.org/pdf/1804.04273.pdf 代码链接:https://github.com/abner ...

  3. StyleGAN2代码阅读笔记

    源代码地址:https://github.com/NVlabs/stylegan2-ada-pytorch 这是一篇代码阅读笔记,顾名思义是对代码进行阅读,讲解的笔记.对象是styleGAN2的pyt ...

  4. ORB_SLAM2代码阅读(5)——Bundle Adjustment

    ORB_SLAM2代码阅读(5)--Bundle Adjustment 1. 说明 2. Bundle Adjustment(BA)的物理意义 3. BA的数学表达 4. BA的求解方法 4.1 最速 ...

  5. ORB_SLAM2代码阅读(3)——LocalMapping线程

    ORB_SLAM2代码阅读(3)--LocalMapping线程 1.说明 2.简介 3.处理关键帧 4. 地图点剔除 5. 创建新的地图点 6.相邻搜索 6.剔除冗余关键帧 1.说明 本文介绍ORB ...

  6. ORB_SLAM2代码阅读(4)——LoopClosing线程

    ORB_SLAM2代码阅读(4)--LoopClosing线程 1.说明 2.简介 3.检测回环 4.计算Sim3 4.1 为什么在进行回环检测的时候需要计算相似变换矩阵,而不是等距变换? 4.2 累 ...

  7. ORB_SLAM2代码阅读(2)——tracking线程

    ORB_SLAM2代码阅读(2)--Tracking线程 1. 说明 2. 简介 2.1 Tracking 流程 2.2 Tracking 线程的二三四 2.2.1 Tracking 线程的二种模式 ...

  8. ORB_SLAM2代码阅读(1)——系统入口

    ORB_SLAM2代码阅读(1)--系统简介 1.说明 2.简介 3.stereo_kitti.cc 4.SLAM系统文件(System.cc) 4.1 构造函数System() 4.2 TrackS ...

  9. 深度学习项目代码阅读建议

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达本文转自|机器学习实验室 犹豫很久要不要把读代码这个事情专门挑出来写 ...

最新文章

  1. 阔力梯的树(2020 CCPC Wannafly Winter Camp Day2 Div.12 )dsu on tree
  2. 字符设备驱动笔记——中断方式按键驱动之linux异常处理结构(四)
  3. wxWidgets:wxPGMultiButton类用法
  4. “智物 智造”亮相云栖大会 远程操控工厂震撼骨灰级程序员
  5. C#: switch语句的重构
  6. 算法题5 用数组实现队列
  7. 最新版Byte Buddy完全支持Java 11
  8. 底大一级压死人!华为Mate 30 Pro主摄CMOS或将达到1/1.5英寸
  9. 软件测试基础知识(一)
  10. php代码正确 插不进表,在表中插入值在PHP中不工作,使用
  11. bzoj 4033: [HAOI2015]树上染色(树形DP)
  12. uni-app 条形码(一维码)/二维码生成实现
  13. 【大数据部落】银行信用数据SOM神经网络聚类实现
  14. 181226每日一句
  15. MongoDB介绍与部署使用
  16. 【自动驾驶决策规划】RRT算法
  17. python定义结构体_python中定义结构体的方法
  18. t检验比较两种算法的性能
  19. 12306余票查询(二)——获取余票数据
  20. PHP前一页 后一页 切换

热门文章

  1. 自学python要看哪些书-想学习Python做数据分析,应该看哪些书?
  2. 免费python网络课程-2019年10种免费的Python学习课程
  3. python是什么类型的编程语言-Python在编程语言中是什么地位?
  4. python开发软件的实例-由Python编写的MySQL管理工具代码实例
  5. python爬虫教程-Python爬虫五大零基础入门教程
  6. 语音识别双十一优惠活动
  7. 计算机网络实验5以太网链路帧实验,计算机网络实验-使用Wireshark分析以太网帧与ARP协议.docx...
  8. 手机端页面自适应解决方案—rem布局进阶版
  9. 【黑马JS笔记】JavaScript基础语法
  10. LeetCode 101对称二叉树