NS2的有一个入门级的无线网络MFLood例子,可以很好的学习NS的一些基本的功能。很可惜,opnet没有,所以在学习opnet的过程中,做了下面这个基于有线网络的flood工程,分享出来,欢迎下载测试,提意见,改进,分享!
下载地址:http://download.csdn.net/detail/yanhc519/6584655
网络层如下,一个3x4的简单的有线网络
需要说明的是无线网络一般需要处理同步的问题,即周边节点收到泛洪包后,需要各自错开发送,实现时通过随机延时实现,因为如果周边节点收到泛洪包后同时发送会造成无线包的碰撞(刚看了一下NS的MFLood里自己产生的包会马上发送,转发的包会随机延时Random::uniform(0.01*2),自己实现的有线网络flood时候,所有的都对齐了)。
对于有线网络没有碰撞的问题,但需要实现slotted,就像slotted aloha一样,因为如果不是slotted:
假设节点5是源,那么节点6、9会同时收到包,然后同时发送给节点10,但是由于opnet的离散时间仿真机制,经同时收到了节点6、9的包,但节点10是按顺序处理6、9发来的包的,假设6发来的包事件先响应,那么根据flood原理,会往6转发包,而这是不应该的,造成泛洪的开销变大。
通过采用slotted packet system可以解决这个问题。这个在介绍process时会看到。
节点层通过module的摆放,可以反映分层的思想,application,network,link层。
对于process层,采用了slotted packet system
ARV表示接收到了自己节点app产生的包,设置源地址和序号,然后插入subq(由于时隙系统,需要引入队列机制)。
RCV表示接收到了其它节点的包,需要提取源地址和序号,进行泛洪路由的处理机制。仿照了Mflood的流程:
如果源地址不存在路由表中,新建一个新的路由表项,并初始化序号和流号,将包插入subq。
如果存在源地址路由表项,序号是新的,那么添加新的序号,初始化流号,将包插入subq。
如果存在源地址路由表项,序号也是旧的,更新流号,丢弃包。
SRV表示slotted系统响应时间到了:
读取subq的包,获取源地址和序号:
如果是自己的地址,发往所有link;
否则,从路由表中获取流号,发往其他link。
包定义如下图,只包含源地址和序号。
路由表定义:
// routing table entry definition
typedef struct{
int seq_number;
int in_strm[4]; //1 means in, 0 means no in
}structseq;
typedef struct{
int srcaddr;
structseq seq_num[MAX_SEQ];
int seq_it; // iterator
}rttable_entry;
其中in_strm用于记录 源地址-序号对应包从那个流号的链路收到。路由表采用opnet自带的链表实现。
下面是代码罗列:
SV
HB
#define APP_STRM 4
#define ARV (op_intrpt_type()==OPC_INTRPT_STRM && \
op_intrpt_strm()==APP_STRM)
#define RCV (op_intrpt_type()==OPC_INTRPT_STRM && \
op_intrpt_strm()!=APP_STRM)
#define SRV (op_intrpt_type()==OPC_INTRPT_SELF)
#define MAX_SEQ 255
// routing table entry definition
typedef struct{
int seq_number;
int in_strm[4]; //1 means in, 0 means no in
}structseq;
typedef struct{
int srcaddr;
structseq seq_num[MAX_SEQ];
int seq_it; // iterator
}rttable_entry;
FB:
// Routing table manipulating functions
rttable_entry * rttable_lookup(int src_addr)
{
int rt_size, i;
rttable_entry * rt_entry;
FIN(rttable_lookup(src_addr));
rt_size = op_prg_list_size(list_rttable);
for(i=0; i<rt_size; i++)
{
rt_entry = op_prg_list_access(list_rttable, i);
if(rt_entry->srcaddr == src_addr)
{
FRET(rt_entry);
}
}
FRET(OPC_NIL);
}
void rttable_addEntry(int src_addr, int seq, int instrm)
{
rttable_entry * rt_entry;
int i;
FIN(rttable_addEntry(src_addr, seq, instrm));
rt_entry = (rttable_entry *)op_prg_mem_alloc(sizeof(rttable_entry));
rt_entry->srcaddr = src_addr;
rt_entry->seq_it = 1;
for(i=0; i<MAX_SEQ; i++)
{
rt_entry->seq_num[i].seq_number = 0xFFFF;
}
rt_entry->seq_num[0].seq_number = seq;
rt_entry->seq_num[0].in_strm[instrm] = 1;
op_prg_list_insert(list_rttable, rt_entry, OPC_LISTPOS_TAIL);
FOUT;
}
int rttable_isnewSeq(rttable_entry * rt_entry, int seq)
{
int i;
FIN(rttable_isnewSeq(rt_entry, seq));
for(i=0; i<MAX_SEQ; i++)
{
if(rt_entry->seq_num[i].seq_number == seq)
FRET(0);
}
FRET(1);
}
void rttable_addSeq(rttable_entry * rt_entry, int seq, int instrm)
{
FIN(rttable_addSeq(rt_entry, seq, instrm));
rt_entry->seq_num[rt_entry->seq_it].seq_number = seq;
rt_entry->seq_num[rt_entry->seq_it].in_strm[instrm] = 1;
rt_entry->seq_it = (rt_entry->seq_it + 1) % 0xFFFF;
FOUT;
}
void rttable_addinstrm(rttable_entry * rt_entry, int seq, int instrm)
{
int i;
FIN(rttable_addinstrm(rt_entry, seq, instrm));
for(i=0; i<MAX_SEQ; i++)
{
if(rt_entry->seq_num[i].seq_number == seq)
rt_entry->seq_num[i].in_strm[instrm] = 1;
}
FOUT;
}
void rttable_getstrm(int src_addr, int seq, int in_strm[])
{
int i;
rttable_entry * rt_entry;
FIN(rttable_getstrm(src_addr, seq, in_strm));
rt_entry = rttable_lookup(src_addr);
for(i=0; i<MAX_SEQ; i++)
{
if(rt_entry->seq_num[i].seq_number == seq)
{
in_strm[0] = rt_entry->seq_num[i].in_strm[0];
in_strm[1] = rt_entry->seq_num[i].in_strm[1];
in_strm[2] = rt_entry->seq_num[i].in_strm[2];
in_strm[3] = rt_entry->seq_num[i].in_strm[3];
}
}
FOUT;
}
init:
// get node id, init the seq
node_id = op_topo_parent(op_id_self()) - 2;
seq_no_self = 0;
list_rttable = op_prg_list_create();
op_intrpt_schedule_self(op_sim_time()+0.5, 0);
Send:
// app gen pkt, set addr and seq
// insert to subq
Packet * pk;
pk = op_pk_get(op_intrpt_strm());
op_pk_nfd_set_int32(pk, "src addr", node_id);
op_pk_nfd_set_int32(pk, "sequence", seq_no_self++);
if(op_subq_pk_insert(0, pk, OPC_QPOS_TAIL) != OPC_QINS_OK)
{
op_pk_destroy(pk);
}
Receive:
// a pkt rcv from other node
// operation refered to the flood example in ns
// get the src addr and seq
// if new src addr, add to route table, insert to subq
// else if old addr, new seq, add seq, insert to subq
// else if old addr, old seq, add strm, destroy
int instrm;
Packet *pk;
int src_addr, seq;
rttable_entry * rt_entry = OPC_NIL;
instrm = op_intrpt_strm();
pk = op_pk_get(instrm);
op_pk_nfd_get_int32(pk, "src addr", &src_addr);
op_pk_nfd_get_int32(pk, "sequence", &seq);
rt_entry = rttable_lookup(src_addr);
if(rt_entry == OPC_NIL) // new src addr
{
rttable_addEntry(src_addr, seq, instrm);
if(op_subq_pk_insert(0, pk, OPC_QPOS_TAIL) != OPC_QINS_OK)
{
op_pk_destroy(pk);
}
}
else if(rttable_isnewSeq(rt_entry, seq)) // new sequence
{
rttable_addSeq(rt_entry, seq, instrm);
if(op_subq_pk_insert(0, pk, OPC_QPOS_TAIL) != OPC_QINS_OK)
{
op_pk_destroy(pk);
}
}
else // duplicated
{
rttable_addinstrm(rt_entry, seq, instrm);
op_pk_destroy(pk);
}
Foward_slot
// periodically check subq to implement slotted packet system
// if src addr == self, send to all links
// else send to all other links
Packet * pk, * cpk;
int i;
int src_addr, seq;
int instrm[4];
while(!op_subq_empty(0))
{
pk = op_subq_pk_remove(0, OPC_QPOS_HEAD);
op_pk_nfd_get_int32(pk, "src addr", &src_addr);
op_pk_nfd_get_int32(pk, "sequence", &seq);
if(src_addr == node_id)
{
for(i=0; i<4; i++)
{
cpk = op_pk_copy(pk);
op_pk_send(cpk, i);
}
op_pk_destroy(pk);
}
else
{
rttable_getstrm(src_addr, seq, instrm);
for(i=0; i<4; i++)
{
if(instrm[i] != 1)
{
cpk = op_pk_copy(pk);
op_pk_send(cpk, i);
}
}
op_pk_destroy(pk);
}
}
op_intrpt_schedule_self(op_sim_time()+0.5, 0);