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; }
// 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);
// 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); }
// 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); }
// 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);