在omnet++上仿真无线传感网络4

上一节,大体了解了一下网络协议中最上层--应用层的仿真。这一节将进行网络层(networklayer)。

无线传感器网络中的路由协议和算法都是在网络层中实现的,所以对这一层的理解的好坏对协议和算法的设计与仿真这关重要。

在omnet++IDE中,双击我用红色矩形标记的图标(网络层模块),打开网络层NED文件,默认进入design模式。

在omnet++上仿真无线传感网络4_第1张图片

我们发现,这里仅仅给了一个网络层的接口。具体使用那个模块需要我们自己指定。host802154_2400MHz的祖先结点wirelessnode指定了默认的networkType = default("BaseNetwLayer"),也就是说使用basenetwlayer模块。networkType 这个参数指定了host802154_2400MHz结点网络层使用的模块。

好吧,下面查看BaseNetwLayer模块的源码。

simple BaseNetwLayer extends BaseLayer like IBaseNetwLayer
{
    parameters:
        @class(BaseNetwLayer);

        bool coreDebug = default(false); // debug switch for core framework
        bool stats = default(false); // stats switch
        int headerLength @unit(bit); // length of the network packet header (in bits)
}

basenetwlayer的NED文件很简单。这个模块是基模块,是用来继承的。当我们实现自己的网络层协议和算法时,自己的网络层模块去继承basenetwlayer,这样,网络层的大部分功能就已经实现了,剩下的是添加自己的算法代码。下面是basenetwlayer.h中定义的成员变量和成员方法,通过查看这些成员方法就可以看出这个模块的大致功能了。basenetwlayer这个模块大致功能包括:初始化,对上下层数据进行封包或解包....。代码中我一一注明功能。

class MIXIM_API BaseNetwLayer : public BaseLayer
{
private:
	BaseNetwLayer(const BaseNetwLayer&);//拷贝构造函数,这里写出原型,意味着默认拷贝构造函数不可用
	BaseNetwLayer& operator=(const BaseNetwLayer&);//<span style="font-family: Arial, Helvetica, sans-serif;">拷贝构造函数,这里写出原型,意味着默认拷贝构造函数不可用</span>

public:
	typedef NetwPkt* netwpkt_ptr_t;//网络层数据包
	enum BaseNetwMessageKinds {
		/** @brief Stores the id on which classes extending BaseNetw should
		 * continue their own message kinds.*/
		LAST_BASE_NETW_MESSAGE_KIND = 24000,
	};
	/** @brief Control message kinds used by this layer.*/
	enum BaseNetwControlKinds {
		/** @brief Stores the id on which classes extending BaseNetw should
		 * continue their own control kinds.*/
		LAST_BASE_NETW_CONTROL_KIND = 24500,
	};

protected:
<span style="white-space:pre">	</span>/*下面变量从<span style="font-family: Arial, Helvetica, sans-serif;">omnetpp.ini中读取*/</span>
    int headerLength;//数据包大小

    /** @brief Pointer to the arp module*/
    ArpInterface* arp;

    LAddress::L3Type myNetwAddr;//网络层地址,<span style="font-family: Arial, Helvetica, sans-serif;">LAddress::L3Type代表网络层,</span><span style="font-family: Arial, Helvetica, sans-serif;">LAddress::L2Type代表mac层地址</span>
    bool coreDebug;

public:
    BaseNetwLayer() 
      : BaseLayer()
      , headerLength(0)
      , arp(NULL)
      , myNetwAddr()
      , coreDebug(false)
    {}

    BaseNetwLayer(unsigned stacksize) 
      : BaseLayer(stacksize)
      , headerLength(0)
      , arp(NULL)
      , myNetwAddr()
      , coreDebug(false)
    {}

    /** @brief Initialization of the module and some variables*/
    virtual void initialize(int);

  protected:
    virtual void handleUpperMsg(cMessage* msg);// 处理上层来的数据
    virtual void handleLowerMsg(cMessage* msg);// 处理下层来的数据

    virtual void handleSelfMsg(cMessage* /*msg*/){
	error("BaseNetwLayer does not handle self messages");
    }
    virtual void handleLowerControl(cMessage* msg);

    virtual void handleUpperControl(cMessage* /*msg*/){
        error("BaseNetwLayer does not handle control messages");
    }

    virtual cMessage*     decapsMsg(netwpkt_ptr_t); //对数据解包以备发送到上层

    virtual netwpkt_ptr_t encapsMsg(cPacket*); // 对数据封包以备发送到下层
    
    virtual cObject* setDownControlInfo(cMessage *const pMsg, const LAddress::L2Type& pDestAddr);
    
    virtual cObject* setUpControlInfo(cMessage *const pMsg, const LAddress::L3Type& pSrcAddr);
};


在仿真中不用这个模块,我们使用它的子模块wiseroute。下面是WiseRoute的NED定义:

simple WiseRoute extends BaseNetwLayer
{
    parameters:
        // debug switch
        bool debug = default(false);
        bool trace = default(false);
        bool useSimTracer = default(false);

        // sink node address (integer)
        int sinkAddress = default(0);
        // the sink directs the tree building procedure with periodic floods.
        // iterationDelay is the period between two floods.


        // RSSI threshold for route selection
        double rssiThreshold @unit(dBm) = default(-50 dBm);

        // If set to zero, this node does not initiates route tree building.
        // If set to a value larger than zero, this nodes periodically initiates route tree building.
        double routeFloodsInterval @unit(s) = default(0 s);// 默认是0即不更新路由表,但是在omnetpp.ini中设置其1200s,表示20分钟广播更新一次路由。
        @display("i=block/fork");
        @class(WiseRoute);

}

wiseroute在网络层中的功能大致是:建立路由表,并且周期性的维护路由表。根据路由表选择下一跳结点,将数据包发送到下一跳结点上。

从WiseRoute模块的c++头文件开始看起。找到路由表中的一个表项(entry)的定义:

	typedef struct tRouteTableEntry {
		LAddress::L3Type nextHop;
		double           rssi;
	} tRouteTableEntry;
nexthop下一跳结点地址,很明显是网络层地址。rssi信号强度,根据信号强度来决定路由表的更新。

下面是路由表的定义:

	typedef std::map<LAddress::L3Type, tRouteTableEntry>        tRouteTable;
<span style="white-space:pre">	</span>tRouteTable routeTable;
路由表数据类型troutetable定义成一个map的数据结构。定义路由表 routeTable。

下面看看WiseRoute模块的c++源文件中的关键函数:

void WiseRoute::handleSelfMsg(cMessage* msg)
{
	if (msg->getKind() == SEND_ROUTE_FLOOD_TIMER) {
		// Send route flood packet and restart the timer
		WiseRoutePkt* pkt = new WiseRoutePkt("route-flood", ROUTE_FLOOD);
		pkt->setByteLength(headerLength);
		pkt->setInitialSrcAddr(myNetwAddr);
		pkt->setFinalDestAddr(LAddress::L3BROADCAST);
		pkt->setSrcAddr(myNetwAddr);
		pkt->setDestAddr(LAddress::L3BROADCAST);
		pkt->setNbHops(0);
		floodTable.insert(make_pair(myNetwAddr, floodSeqNumber));
		pkt->setSeqNum(floodSeqNumber);
		floodSeqNumber++;
		pkt->setIsFlood(1);
		setDownControlInfo(pkt, LAddress::L2BROADCAST);
		sendDown(pkt);
		nbFloodsSent++;
		nbRouteFloodsSent++;
		scheduleAt(simTime() + routeFloodsInterval + uniform(0, 1), routeFloodTimer);
	}
	else {
		EV << "WiseRoute - handleSelfMessage: got unexpected message of kind " << msg->getKind() << endl;
		delete msg;
	}
}

这个函数的功能相当于一个定时器,在指定时间向全网泛洪数据包用于建立路由表。当函数判定接收到的数据是routeFloodTimer就开始广播,并重新开始计时器。那么什么时候开始第一次的广播呢?当然是在初始化的时候指定的:

void WiseRoute::initialize(int stage)
{
	...........
		
		// only schedule a flood of the node is a sink!!
		if (routeFloodsInterval > 0 && myNetwAddr==sinkAddress)
			scheduleAt(simTime() + uniform(0.5, 1.5), routeFloodTimer);
从上面代码中可以看出,仿真开始后0.5s~1.5s之间的某个时刻开始广播建立路由。

void WiseRoute::updateRouteTable(const LAddress::L3Type& origin, const LAddress::L3Type& lastHop, double rssi, double ber)
{
	tRouteTable::iterator pos;

	pos = routeTable.find(origin);
	if(trace) {
	  receivedRSSI.record(rssi);
	  receivedBER.record(ber);
	}
	if (pos == routeTable.end()) {
		// A route towards origin does not exist yet. Insert the currently discovered one
		// only if the received RSSI is above the threshold.
		if (rssi > rssiThreshold) {
			tRouteTableEntry newEntry;

			// last hop from origin means next hop towards origin.
			newEntry.nextHop = lastHop;
			newEntry.rssi = rssi;
			if(trace) {
			  routeRSSI.record(rssi);
			  routeBER.record(ber);
			}
			routeTable.insert(make_pair(origin, newEntry));
			if(useSimTracer) {
			  tracer->logLink(myNetwAddr, lastHop);
			}
			nbRoutesRecorded++;
			if (origin == LAddress::L3NULL && trace) {
				nextHopSelectionForSink.record(static_cast<double>(lastHop));
			}
		}
	}
	else {

	}
}

这个函数功能是更新路由。更新的条件是1.在当前路由中没有发现到origin结点的路由。2.信号强度要比设置的阈值大。


WiseRoute::tFloodTable::key_type WiseRoute::getRoute(const tFloodTable::key_type& destAddr, bool /*iAmOrigin*/) const
{
	// Find a route to dest address. As in the embedded code, if no route exists, indicate
	// final destination as next hop. If we'are lucky, final destination is one hop away...
	// If I am the origin of the packet and no route exists, use flood, hence return broadcast
	// address for next hop.
	tRouteTable::const_iterator pos = routeTable.find(destAddr);
	if (pos != routeTable.end())
		return pos->second.nextHop;
	else
		return LAddress::L3BROADCAST;
}
找到去destAddr结点的下一跳结点。

你可能感兴趣的:(在omnet++上仿真无线传感网络4)