期末了,怕老师偷袭检查大作业,快速搞了搞实验,花了几天看了看c++,又花了一两天看omnet++的使用和tictoc例程。开始写,记录一下。(菜鸟的记录)
项目目录如下:
table文件:路由表及相关操作
dsdv_table文件:路由之间传递的链路信息及相关操作
data文件:模拟发送的分组
dsdvnet.cpp:路由类的相关操作
dsdvnet.ned:模块属性和网络拓扑描述
omnetpp.ini:仿真设置
dsdvnet.ned:
simple DsdvHost
{
@display("i=device/pc_s");
gates:
inout gate[];
}//路由模块,gates设成inout双向,gate[ ]形式使门的数量根据拓扑改变
network Dsdvnet
{
types:
channel Channel extends ned.DelayChannel {
delay = 100ms;
}//定义延迟为100ms的链路
submodules:
dsdvhost[10]:DsdvHost;//定义10个主机
connections:
dsdvhost[0].gate++ <--> Channel <--> dsdvhost[1].gate++;
dsdvhost[1].gate++ <--> Channel <--> dsdvhost[2].gate++;
dsdvhost[1].gate++ <--> Channel <--> dsdvhost[4].gate++;
dsdvhost[3].gate++ <--> Channel <--> dsdvhost[4].gate++;
dsdvhost[4].gate++ <--> Channel <--> dsdvhost[5].gate++;
dsdvhost[6].gate++ <--> Channel <--> dsdvhost[0].gate++;
dsdvhost[7].gate++ <--> Channel <--> dsdvhost[4].gate++;
dsdvhost[8].gate++ <--> Channel <--> dsdvhost[4].gate++;
dsdvhost[9].gate++ <--> Channel <--> dsdvhost[8].gate++;
dsdvhost[8].gate++ <--> Channel <--> dsdvhost[2].gate++;
dsdvhost[5].gate++ <--> Channel <--> dsdvhost[3].gate++;
}
简单的了解下:ned构建网络拓扑时,是从上到下构建的。dsdvnet构建时,先设好submodule和connections,这个时候就知道每个submodule需要多少个gate。
得到的仿真时拓扑如图:
omnetpp.ini:
[General]
record-eventlog = true
[Config Dsdvnet]
network =Dsdvnet
record-eventlog = true可以在仿真完成后产生记录事件的文件,如下图,位置在results文件夹
table.h:
#ifndef TABLE_H_
#define TABLE_H_
#define MAXSIZE 20
#include "dsdv_table_m.h"
typedef struct{
int destination; //目的主机
int nextgate; //下一跳走的gate
int nextnode; //下一个主机
int metric; //路径代价
int seq_no; //目的主机的序号
}table;
class Table{
public:
table T[MAXSIZE];
int length=0;
bool addTable(const table* t); //新加一个表项
bool deleteTable(int index); //删除一个表项
int findTable(int dest); //找到表项对应的位置
int campare(int index,const table* t); //和原路径相比较,如果不需要更新,返回0;要添加表项,返回2;删除表项,返回-1;更改表项,返回1
void renewTable(const table* t);//根据t的值更行路由表表
void renewItem(int index,const table* t);//更新表项
void copytotable(int index,const dsdv_table *msg);
void copytomsg(int index,dsdv_table *msg);//将表项复制给msg消息
void printTable();//打印路由表
};
#endif /* TABLE_H_ */
table.c:
#include <stdio.h>
#include <string.h>
#include <omnetpp.h>
using namespace omnetpp;
#include "table.h"
bool Table::addTable(const table* t){
if(this->length==MAXSIZE)
return false;//如果超过表最大长度,返回false
this->T[this->length].destination=t->destination;
this->T[this->length].metric=t->metric;
this->T[this->length].nextgate=t->nextgate;
this->T[this->length].nextnode=t->nextnode;
this->T[this->length].seq_no=t->seq_no;
this->length++;//将表项添加到表中,表长+1
return true;
}
bool Table::deleteTable(int index){
if(index>=length||index<0){
return false;
}//如果index超过表长,或index小于0,返回false
int i;
for(i=index;i<length-1;i++){
renewItem(i,&T[i+1]);
}
this->length--;//删除表项,表长-1
return true;
}
int Table::findTable(int dest){
int i;
for(i=0;i<this->length;i++){
if(this->T[i].destination==dest)
return i;
}
return -1;
}//在路由表中寻找destination为dest的表项,并返回位置;找不到则返回-1
int Table::campare(int index,const table* t){
if(index==-1)
return 2;//如果index为-1,说明表中没有该项,需要添加表项
if((t->seq_no)>(this->T[index].seq_no)){
if(t->metric==-1)
return -1;
else
return 1;
}//如果新来的消息中,目的主机序号seq_no比表项中对应的seq_no大,有两种可能:
//一、metric==-1代表主机断开连接,无法到达,此时应该删除表项
//二、该主机更新了路由信息,此时应该更新表项
else if(t->seq_no==this->T[index].seq_no)
if(t->metric<this->T[index].metric)
return 1;//如果目的主机序号seq_no相等,则选择metirc代价小的路线
return 0;
}
void Table::renewTable(const table* t){
int index=findTable(t->destination);//找到t->dest在路由表中的位置
int k=campare(index,t);//与表对比,得出下一步处理的类型
switch(k)
{ case 2:
addTable(t); break;
case -1:
deleteTable(index); break;
case 0:
break;
case 1:
renewItem(index,t); break;
}
}
void Table::renewItem(int index,const table* t){
this->T[index].destination=t->destination;
this->T[index].metric=t->metric;
this->T[index].nextgate=t->nextgate;
this->T[index].nextnode=t->nextnode;
this->T[index].seq_no=t->seq_no;
}
void Table::copytotable(int index,const dsdv_table *msg){}
void Table::copytomsg(int index,dsdv_table *msg){
msg->setDestination(this->T[index].destination);
msg->setMetric(this->T[index].metric);
msg->setSeq_no(this->T[index].seq_no);
}
void Table::printTable(){
int i=0;
EV<<"Route table:"<<endl;
for(i=0;i<length;i++){
EV<<"dest:"<<T[i].destination<<" "
<<"metric:"<<T[i].metric<<" "
<<"nextgate:"<<T[i].nextgate<<" "
<<"nextnode:"<<T[i].nextnode<<" "
<<"seq_no:"<<T[i].seq_no<<endl;
}
}
以上就是对路由表的一些操作,路由表作为路由类的成员,可方便在路由类中使用各种操作。
dsdv_table.msg:
message dsdv_table
{
int source; //源主机
int destination; //目的主机
int metric; //路径代价
int seq_no; //目的主机的序号
}
data.msg:
message data{
int source;//源地址
int destination;//目的地址
int hopCount = 0;//经过的跳数
}
dsdv_table和data的.h 和.cpp文件不需要自己写,只要建好msg文件后build一下就可以了。(我开始看了例程还傻乎乎的自己建了两个文件,build了之后才发现多了两个文件。)
另外,data我用来模拟分组测试各节点之间传送分组,貌似cPacket类才是真的分组。
dsdvnet.cpp:
#include <stdio.h>
#include <string.h>
#include <omnetpp.h>
using namespace omnetpp;
#include "table.h"
#include "dsdv_table_m.h"
#include "data_m.h"//记得include创建的消息类
class DsdvHost:public cSimpleModule{
private:
Table dsdv_t;//路由表
dsdv_table *msg_t = nullptr;//路由表项指针
cMessage *event = nullptr;//事件event用做自消息,提醒自己按时向其他路由器发送路由表
cMessage *data_event=nullptr;//事件data_event用作自消息
//我将它用作60s后路由表稳定后,开始测试传送分组
protected:
virtual ~DsdvHost();
virtual void sendMessage(dsdv_table *msg,int k);//用来发送路由表
virtual void initialize() override;//初始化,网络创建后会调用
virtual void handleMessage(cMessage * msg) override;//接受消息,顾名思义,收到消息时调用
virtual void forwardMessage(data *msg);//收到分组后,选择合适的gate,向前发送
virtual data *generateMessage();//产生一个目的随机的分组
};
Define_Module(DsdvHost);
DsdvHost::~DsdvHost(){
cancelAndDelete(event);
}
void DsdvHost::sendMessage(dsdv_table *msg,int k){
send(msg,"gate$o",k);
}
void DsdvHost::initialize(){
//将自己添加到表中
table *t;
t=new table;
t->destination=getIndex();
t->nextgate=-1;
t->nextnode=getIndex();
t->metric=0;
t->seq_no=100;
dsdv_t.addTable(t);
delete t;
//预定事件event,定时发送路由表
event=new cMessage("event");
scheduleAt(getIndex(),event);
//开始由0主机发送分组
if(getIndex()==0){
data_event=new cMessage("send_data");
scheduleAt(60.0,data_event);//60s时,路由表都稳定时发送
}
}
void DsdvHost::handleMessage(cMessage * msg){
if(strcmp("send_data", msg->getName()) == 0){
data* d=generateMessage();
forwardMessage(d);
}//如果是send_data事件,产生一个分组并发送
else if(strcmp("event", msg->getName()) == 0){
int j,i;
int n=gateSize("gate"),m=dsdv_t.length;
for(i=0;i<n;i++){
for(j=0;j<m;j++){
msg_t=new dsdv_table("table");
msg_t->setSource(getIndex());
dsdv_t.copytomsg(j,msg_t);
sendMessage(msg_t,i);
}
}
scheduleAt(simTime()+10.0, event);
}//如果是event事件,向所有邻居路由发送路由表
else if(strcmp("table", msg->getName()) == 0){
dsdv_table *ttmsg = check_and_cast<dsdv_table *>(msg);
EV<<"recieved"<<endl;
cGate *g=msg->getArrivalGate();
EV<<"message is from:"<<ttmsg->getSource()<<" "<<"gate["<<g->getIndex()<<"] received message"<<endl;
table *t;
t=new table;
t->destination=ttmsg->getDestination();
t->nextgate=g->getIndex();
t->nextnode=ttmsg->getSource();
t->metric=ttmsg->getMetric()+1;
t->seq_no=ttmsg->getSeq_no();
dsdv_t.renewTable(t);
delete t;
dsdv_t.printTable();
delete msg;
delete ttmsg;
}//如果收到dsdv_table消息,更新路由表
else{
data *ttmsg = check_and_cast<data *>(msg);
if (ttmsg->getDestination() == getIndex()) {
// Message arrived.
EV << "Message " << ttmsg << " arrived after " << ttmsg->getHopCount() << " hops.\n";
bubble("ARRIVED, starting new one!");
delete ttmsg;
// Generate another one.
EV << "Generating another message: ";
data *newmsg = generateMessage();
EV << newmsg << endl;
forwardMessage(newmsg);
}
else {
// We need to forward the message.
forwardMessage(ttmsg);
}
}//当收到data分组时,如果目的地址是本机,收到并删除消息;否则,用forwardMessage按路由表继续转发
}
void DsdvHost::forwardMessage(data *msg){
int index=dsdv_t.findTable(msg->getDestination());//找到对应的路由表项
msg->setHopCount(msg->getHopCount()+1);//消息跳数+1
send(msg,"gate$o",dsdv_t.T[index].nextgate);//发送出去
}//对分组进行转发
data * DsdvHost::generateMessage(){
// Produce source and destination addresses.
int src = getIndex(); // our module index
int n = getVectorSize(); // module vector size
int dest = intuniform(0, n-2);
if (dest >= src)
dest++;
char msgname[20];
sprintf(msgname, "tic-%d-to-%d", src, dest);
// Create message object and set source and destination field.
data *msg = new data(msgname);
msg->setSource(src);
msg->setDestination(dest);
return msg;
}//这里直接抄tictoc例程
仿真运行:
部分主机路由表(稳定后):
主机1:
主机3:
主机5:
主机8:
一些分组的发送结果:
待实现的方面:
动态的添加,删除主机和链路。可能打算水一下作业,就不做这个了。估计就是在构造、析构或者initial、finish函数里写一些消息发送的代码吧。
注:本人菜鸟,就是应付一下作业,也没有深入学习。