1、 网络中的节点按照一定的规律进行休眠调度,节点维护的邻居相关信息除了最小跳步数、剩余能量、链路质量等常用选路困素外,还包括计算其醒来的时间差。网络不需要全局或局部的时间同步,也不要求节点修改内部时钟。而是通过记录的与邻居节点的时间差,决定发送数据包的时刻。此外,可以通过发送的数据包和接收节点回馈的ACK进行时间差修补。对下一跳节点进行选择时,加入对邻居节点醒来先后顺序的考虑。为了简单起见,路由方面借鉴经典的基于地理位置路由的选路策略,如贪婪路由、对网络空洞的处理。休眠调度也是利用简单的调度策略,实现定义节点的睡眠和活跃周期。 SDRAD 路由协议是对DRAD协议的简写,简化了的DRAD 协议。
2、SDRAD 主要实现了建立网络结构,收集数据信息的功能3。第二章 协议设计SDRAD 协议分两个阶段:网络拓扑形成阶段和数据收集阶段。接下来将对这两个阶段进行详细说明。2.1 网络拓扑形成阶段当节点部署到网络并开启电源后,并不是立即进入数据收集。而是首先由基站发送Hello 包,节点接受到Hello 包后,更新自己的邻居节点信息,从而建立树状的网络结构。协议刚启时,所有节点的跳步数都为无穷大。首先,由基站广播Hello 包,为了简单,本例中将基站固定为序列号为0 的节点。节点接收到Hello 包后,更新本节点跳步数和邻居列表,广播自身。 Hello包的分组头包类型(Packet type)跳步
3、数(Hopcount)源节点序列号(Source node sequence)节点的分布及形成的拓扑关系:图1 结点分布如图1,网络中共有07 个节点,其中节点0 为基站,其跳步数为0。节点1,2 的跳步数为1,节点3,4,5 的跳步数为2,节点6 的跳步数为3。在网络形成阶段由基站发送Hello 包,节点1,2 接收到Hello 包,将节点0加入到它们的邻居表中,同时节点1,2 重新向外发送Hello 包,被节点3,4,5接收,依次建立邻居表,形成SDRAD 的拓扑关系。结点结点0结点1结点2结点3结点4结点5结点6123452.2 数据收集阶段进入数据收集阶段后,当网络中某一节点接受到数据
4、包后,该节点就会向邻居表中的某一节点发送数据收集包(collect 包),最终将接收到的数据信息发送到基站,传给应用程序进行处理。选择哪一个邻居节点呢?协议将随机选择邻居表的一个节点进行转发。图2 数据转发路径图如图2,节点6 接收到数据信息,节点6将该数据封装成Collect 包,依次传送给节点5、节点1、在到基站(节点0)。路径中结点5与结点1都是随机选择的。第三章 协议实现3.1 SDRAD协议类为了实现SDRAD 协议类, 我们编写了4 个程序文件, 分别是sdrad.h、sdrad.cc(SDRAD 协议的定义和实现)、sdrad_packet.h(SDRAD 新增包头的定义)、sd
5、rad_nbtable.h(邻居表的定义和实现)。在ns2 中,所有路由协议都是从Agent 类继承而来的,实现协议时主要关心的是节点对包的接收和发送,即recv 函数和send 函数。Recv 函数一般从Agent 类继承而来,send 函数根据需要自己编写。下面给出SDRAD 协议类的定义:class SDRAD: public Agent friend class SDRAD_Neighbor; /SDRAD_Neighbor 类是邻居表类friend class SDRAD_HelloTimer; /Hello 定时器类public:SDRAD(nsaddr_t id); /含一个参数
6、的构造函数void recv(Packet *p, Handler*); /接收上层协议送下来的数据并处理protected:/命令处理函数,实现Tcl 和C+之间的信息交换int command(int ,const char* const*);inline int initialized() return 1 & target_; /对上层发送的数据进行处理void resolve(Packet *p);/邻居表的信息维护void nb_insert(u_int32_t seqno, u_int8_t hop); /插入SDRAD_Neighbor* nb_lookup(u_int32_t
7、 seqno); /查找void nb_delete(u_int32_t seqno); /删除void nb_purge(); /清空void nb_print(); /打印,检验协议所建立的拓扑是否符合要求void forward(u_int32_t seqno,Packet *p, double delay); /转发函数void sendHello(bool isbase); /发送Hello 包/Packet RX Routinesvoid recvHello(Packet *p); /接收Hello 包/接收SDRAD 包(包括Hello 包和Collect 包)void recv
8、SDRAD(Packet*p);/Packet collect Routines,发送、接收Collect 包void sendCollect(u_int32_t ipdst);void recvCollect(Packet *p);/TimersSDRAD_HelloTimer htimer; /定义定时器private:/本协议中为了简化处理,将IP 地址和序列号设置为同一唯一值nsaddr_t index_; /本节点的IP 地址u_int32_t seqno_; /本节点的序列号u_int8_t hop_count_; /节点跳步数SDRAD_nbtable nbthead_; /定义
9、邻居表/为调试和跟踪定义的变量Trace *logtarget_;NsObject *uptarget_;NsObject *port_dmux_;其构造函数的实现:voidSDRAD:SDRAD(nsaddr_t id):Agent(PT_SDRAD),port_dmux_(0),htimer(this)index_ = id;seqno_ = id; /hop_count_ = INFINITY; /跳步数为无穷大logtarget_ = 0;LIST_INIT(&nbthead_);length = 0; /邻居表长度3.2 数据包头现在,我们为SDRAD 协议新建包头,对应实现协议中的
10、分组头。下述代码在sdrad_packet.h 中:/SDRAD包头:hdr_sdradstruct hdr_sdrad u_int8_t dh_type; /分组类型 static int offset_; inline static int& offset() return offset_; inline static hdr_sdrad* access(const Packet* p) return (hdr_sdrad*) p-access(offset_);Hello包头:hdr_sdrad_hellostruct hdr_sdrad_hello u_int8_t hh_type;
11、u_int8_t hh_hop_count; /跳步数 u_int32_t hh_src_seq; /源节点序列号 /计算包头大小 inline int size() int sz = 0; sz = sizeof(u_int8_t) + sizeof(u_int8_t) + sizeof(u_int32_t); return sz;Collect包头:hdr_sdrad_collectstruct hdr_sdrad_collect u_int8_t hc_type; u_int8_t hc_hop_count; u_int32_t hc_src_seq; u_int32_t hc_dst_
12、seq; /目的节点序列号 inline int size() /计算包头大小 + sizeof(u_int32_t)/联合SDRAD 的分组头,节约空间便于使用union hdr_all_sdrad hdr_sdrad dh; hdr_sdrad_hello hh; hdr_sdrad_collect hc;3.3 邻居表在ns2 中内置了一个链表结构list(源码在ns/lib/bsd-list.h 中),在此使用这个list 结构实现邻居类(sdrad_nbtable.h):#include /包含头文件class SDRAD_Neighbor friend class SDRAD; /
13、设置SDRAD 为友元 SDRAD_Neighbor(u_int32_t s, u_int8_t hop) /构造函数 seqno_ = s; hop_count_ = hop; /链表结构 LIST_ENTRY(SDRAD_Neighbor) nb_link; /邻居结点中的字段 u_int32_t seqno_; /序列号 u_int8_t hop_count_;/定义链表结构LIST_HEAD(SDRAD_nbtable, SDRAD_Neighbor);解释类的定义和编译类的联接解释类和编译类的连接方法比较固定,对于只关心协议内容的人,可参考ns2 中同层协议的实现方法。Tcl Hoo
14、ks到目前为止,我们的SDRAD 协议还不能被ns 所认可,还需要其它定义。下面部分是不可缺少的,而且通常只需要按照这个典型模式实现。其中AgentSDRAD 指定了C+中的SDRAD 类和Tcl 部分中的Agent/SDRAD 绑定在了一起。/sdrad.cc 文件中:/TCL Hooksstatic class SDRADclass : public TclClass SDRADclass():TclClass(Agent/SDRAD) TclObject* create(int argc,const char* const* argv) assert(argc = 5); return(
15、new SDRAD(u_int32_t)atoi(argv4);class_rtProtoSDRAD;3.4 SDRAD协议类的实现3.4.1 邻居表管理本部分功能实现对邻居表的增删查改等,方便代理类的使用。1 插入新建一个邻居节点,插入nbtable 中。void SDRAD:nb_insert(u_int32_t seqno, u_int8_t hop) 2 查找查找序列号为seqno 的节点SDRAD_Neighbor* SDRAD:nb_lookup(u_int32_t seqno)3 删除删除序列号为seqno 的节点nb_delete(u_int32_t seqno) 4 清空清空
16、邻居表nb_purge() 5 打印输出邻居表的跳步数和序列号nb_print() 3.4.2 SDRAD路由协议中的关键函数 command 函数 int SDRAD:command(int argc,const char*const*argv)command 函数的写法固定,主要实现Otcl 和C+的交互,对Otcl 命令进行解析。用来解析模拟器类create-sdrad-agent 函数中的命令。Simulator instproc create-sdrad-agent node #Create SDRAD routing agentset ragent new Agent/SDRAD
17、$node idputs =$node id= ;#测试$self at 0.0 $ragent start# 在0.0s 启动协议$node set ragent_ $ragentreturn $ragent recv函数recv(Packet*p,Handler*)新协议类重载recv 函数,判别分组包类型,并对其进行转发、更新、丢弃、重发等处理,来实现具体协议所要求的内容。 sendHello函数sendHello(bool isbase)发送hello数据包。基站只处理发送一次Hello 包,非基站节点根据自身信息新建Hello 包,广播。 recvHello函数recvHello(P
18、acket*p)基站接收到Hello 包,丢弃;节点接收到自身广播的Hello 包,丢弃;节点接收到有效Hello 包,更新本节点的跳步数,将上一跳节点信息加入邻居表,并广播自身;丢弃重复邻居Hello 包和非邻居包。 HelloTimer定时器运行一段时间的网络会不稳定(包括网络中有新结点加入,节点寿命结束,能量用尽等),用HelloTimer 定时器定时发送Hello 包,更新邻居信息,建立新的树状网络结构。sdrad.h 中HelloTimer 的定义:class SDRAD_HelloTimer : public Handler SDRAD_HelloTimer(SDRAD* a) :
19、 agent(a) void handle(Event*);SDRAD *agent;Event intr;重写handle 函数,使基站发送Hello 包,建立新的网络结构:void SDRAD_HelloTimer:handle(Event*) agent-nb_purge(); /清楚邻居表sendHello(true); /基站发送Hello 包/该定时器每个50s 调度一次Scheduler:instance().schedule(this, &intr, 50);6 Resolve函数resolve(Packet *p) 节点通过第一节点建立好网络结构后,就进入数据收集阶段,此协议
20、通过将有用数据处理成Collect 包在网络之间传送。在recv函数中节点在接收到有用数据后,通过resolve 函数将其处理成collect 包后转发给邻居节点。7 下一跳函数u_int32_t SDRAD:nexthop_random() 随机选择邻居表中节点编号8 转发函数forwardforward(u_int32_t seqno,Packet *p, double delay) 9 发送collect包函数sendCollect(u_int32_t ipdst) 节点根据参数ipdst 确定下一跳目的地,发送collect包。10 接收collect包函数recvCollect(Pa
21、cket *p) 节点随机选择下一跳,发送collect 包。 基站处理数据,丢弃废包。3.5 将SDRAD整合到NS-2.35中3.5.1 建立协议文件本协议程序共五个文件,分别是: sdrad_packet.h、sdrad_nbtable.h、sdrad.h 和sdrad.cc。在目录下建立sdrad 文件夹,将上述这5 个文件放进去。3.5.2 修改NS-2.35源码 需要改五个文件:ns-2.35/common/packet.hns-2.35/tcl/lib/ns-lib.tcl ns-2.35/tcl/lib/ns-packet.tcl ns-2.35/Makefile ns-2.3
22、5/common/packet.h文件中找到如下位置,添加红色标记的一行。static const packet_t PT_PROTONAME = 73; / insert new packet types herestatic packet_t PT_NTYPE = 75; / This MUST be the LAST one 找到如下位置,添加红色标记的一行。name_PT_DCCP_RESET=DCCP_Reset; name_PT_PROTONAME= protonamename_PT_SDRAD=SDRADname_PT_NTYPE= undefined 在ns-2.35/tcl/
23、lib/ns-lib.tcl文件中找到如下位置,添加红色标记的一段代码。 AODV set ragent $self create-aodv-agent $nodeSDRAD set ragent $self create-sdrad-agent $nodeAOMDV set ragent $self create-aomdv-agent $node在合适的位置加入如下代码: 在ns-2.35/tcl/lib/ns-packet.tcl 文件中找到如下位置,添加红色标记部分。 MDART # routing protocol for ad-hoc networks # AOMDV patch AOMDV Protoname SDRAD# 在ns-2.35/Makefile文件中找到如下位置,添加红色标记部分wpan/p802_15_4trace.o wpan/p802_15_4transac.o apps/pbc.o protoname/protoname.o protoname/protoname_rtable.o sdrad/sdrad.o $(OBJ_STL)3.5.3 编译NS-2.35源文件 在cygwin中运行如下命令完成源文件的编译。hugerhuger-PC /ns-allinone-2.35$ cd n
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1