Dtnsim2学习笔记

1、DTN MED平均等待时间计算公式

下面这段代码是在dtnsim2中的packageprotocolStack.globalKnowledge;下的contactschedule中,有一个计算MED时间的函数

/** Computes the MED metric assuming that time begins at startTime. */
	public double getMEDWeight(double simTime)
	{
		if (nextUpTime != null)
		{
			throw new RuntimeException("ContactSchedule is not closed");
		}

		double downSquaredSum = 0;
		double lastTime = 0;

		for (UpTime up : times)
		{
			if (up.getTimeUp() != 0)
			{
				assert up.getTimeUp() > lastTime;
				double downTime = up.getTimeUp() - lastTime;
				assert downTime > 0;

				downSquaredSum += downTime * downTime;
			}

			lastTime = up.getTimeDown();//仅仅统计down的时间长度
		}

		// Add the very last down time
		double downTime = simTime - lastTime;

		if (downTime > 0)
		{
			downSquaredSum += downTime * downTime;
		}

		double ret = (double) (downSquaredSum / (2 * simTime)) + contact.getLatency();

		return ret;
	}

在example-simple-readme中有下面情景

This scenario has four nodes: A, B, C, D. Band C are permanently connected to

D. A <-> B has a down interval of 40,and an up interval of 20 (MED = 13.3).

A <-> C has adown interval of 20, and an up interval of 5 (MED = 8).

对于AB之间的链路调度如下:

0      40  60     100 120

start  up  down   up  down

 

通过手动计算可以知道0-40期间平均等待时间为40/2=20,而40-60期间平均等待时间是0,所以整个60s的周期中平均等待时间为:20*(40/60)+0*(20/60)=13.3

上面函数中downSquaredSum统计了链路中断持续时间的平方,最后又除以2倍的simTime,让人有点摸不着头脑,其实是这样的:(downtime/2) * (downtime/simtime)

即在中断时间的平均等待时间乘以中断时间占整个时间的百分比。在MEED的硕士论文中提到了如何计算。

2、如何运行dtnsim2

在console界面下进入到E:\Network\ONE\Eclipseprj\dtnsim2的examples/simple目录下,运行如下命令行:

java -ea -cp ../../bin/lib simulator.Main-verbose 1 simple_MED

verbose冗长的、啰嗦的,Setthe amount of logging output that should be generated


其中ea不知道什么意思,cp表示查找类的路径,后面的-verbose设置输出调试信息的数量,最后的simple_MED表示要读取的配置文件,如下所示:

Dtnsim2学习笔记_第1张图片

上述文件设定了带宽、延迟,什么时刻做什么工作,设置node类型、schedule文件、运行文件,最后设置了输出统计数据

 

其中的simple_Times文件如下:


运行完后,即可在该目录下生成simple_stats统计输出文件:

Algo;  Buffer_Size;  Message_Size; Bandwidth; Latency;   Total_Msgs;   Delivered_Msgs;    Deliv_Ratio;  Avg_Time

MED;   2000;  50; 10; 2;  2;  2;  100.00%;   26.50


如果是在Eclipse下运行的话,当前的路径是如下目录

E:\Network\ONE\Eclipseprj\dtnsim2

在设置argument参数时应该设置为:-verbose 1 examples/simple/simple_MED

3、程序解读

程序运行流程,simulator包下有一个Main,会读取运行参数:

if (args[i].charAt(0) != '-')
              {
                  // Until first linewith specified time, all lines in input
                  // will beinterpreted immediately.
                  (new InputReader(net, args[i])).runInput(-1);
              }


上面这个把simple_MED文件中@0之前的配置读取完毕

 

runInput函数会对simple_MED文件进行解析,一句话一句话进行解析,语句分为注释#时间@和命令

publicvoid runInput(double curTime)

比如default_contactbandwidth = 10 latency = 2

这句话是对contact进行参数配置,是一个命令

会一步一步的测试各种命令:

l  测试是否是本地命令,看是否有interpreter,下是否有run_file
cs = checkLocalCmds(line,curTime);

l  下一步测试cs =line.execCommand();在InputLine类中

 

1) 测试网络层的命令,network.parseLocalCommand();有network_element,traffic,stats,simulator,network_graph等

2) 测试节点层的命令,parseNodeCommand();有default_node等

3) 测试contact连接的命令,parseContactCommand();,在findContactsForCommand()下有default_contact

 

在contact,stat类下都有commandparser方法,用于解析配置文件中的命令

 

 

运行到如下函数fire处时,将开始执行网络仿真,其实是开始执行@0后的语句命令或配置。

需要执行receiver.receiveEvent(this);,其中receiver定义为EventReceiver,而EventReceiver为一个接口类,找不到其接口实现函数?

public class Event
{
    protected long seq = 0;
 
    protected double time = 0;
 
    protectedEventReceiver receiver = null;
public void fire(Simulator net)
        {
            if (receiver == null)
               return;
 
            receiver.receiveEvent(this);
        }

 

经过调试发现执行的是publicclass InputReaderimplements EventReceiver

public void receiveEvent(Eventevent)
    {
       runInput(event.getTime());
    }


在runInput中会simple_MED文件内容,并按照其内容进一步读取其它文件,或执行相关命令。

  

消息发送

在ProtocolStackNode类下有sendNewMessage方法

4、路径计算相关

路由模块的routeForMsg(ProtocolStackMessage msg)方法会调用topology.getRoute(msg);

接着,会调用GKnowledgeTopologyHandler类下的getRoute(msg);

接着,会调用此函数进行计算的初始化lastRouting = new NetworkDijkstra(networkGraph(), parent,network.getCurrentTime(), forMsg);

接着,会调用lastRouting.routeTo((ProtocolStackNode)forMsg.getDestNode());进行真正的路由计算

 

NetworkGraph,一个抽象类,定义了一些Dijkstra可能会用到的方法:获取邻节点、得到代价

DijkstraGraph,一个接口类,与NetworkGraph差不多

NetworkDijkstra,直接调用的父类Dijkstra的构造函数,这个主要是对Dijkstra计算进行一下初始化

    routeTo(NodeTypeendPoint)该函数负责计算到endPoint的路径

       该函数又调用了computeShortestPath(endPoint);,此函数是Dijkstra计算所在地

 

 

下面的这种HashMap,索引是节点,索引值是源节点到该节点的路径的信息,一种哈希映射

private HashMap<NodeType, RouteInfo>routeInfoMap = new HashMap<NodeType, RouteInfo>();

 

下面这个GKnowledgeTopologyHandler继承了抽象类TopologyHandler

GKnowledgeTopologyHandler extendsTopologyHandler

GKnowledgeTopologyHandler类下有getRoute方法,此方法会新建NetworkDijkstra类,并调用routeTo方法

 

在下面RouteRoutingHandler类下有routeForMsg(ProtocolStackMessage msg)方法,此方法调用了route = topology.getRoute(msg);

 

 

ProtocolStackNode的方法sendNewMessage

    创建一个新的消息:msg = new ProtocolStackMessage(。。destNode, dataLength);

    然后,接收新消息:ret = acceptNewMessage(msg);

    然后进入RouteRoutingHandler类下的acceptNewOwnMessage方法,新消息、自己产生

然后是addMessage(msg),在这里会判断本地节点还有没有足够的buffer,如果有,那么加入buffer,至此,新消息已经产生

 

调用父母parent节点ProtocolStackNode的方法notifyNewMessage,在这里会遍历所有的eventHandlers的新消息到达通知,

通过这些又触发路由模块RouteRoutingHandler的notifyNewMessage,在路由模块的新消息到达函数里会执行routeForMsg(msg);

ProtocolStackNode::notifyNewMessage(ProtocolStackMessage msg)
	{
		for (EventHandler handler : eventHandlers)
		{
			handler.notifyNewMessage(msg);
		}
	}

public boolean addMessage(ProtocolStackMessage msg)
	{

		// We are willing to store any message, as long as we have space in
		// the buffer:
		if (!parent.canAllocateCapacity(msg, this))
		{
			return false;
		}

		parent.allocateCapacity(msg, this);

		if (orderPolicy == ORDER_CREATION_TIME)
		{
		}
		else
		{
			buffer.add(msg);
		}

		msgIDs.put(msg.getId(), msg);
		bufSize += msg.getLength();

		msg.setEventHandlerID(eventHandlerID());

		parent.notifyNewMessage(msg);

		return true;
	}

ContactSchedule类下有getMEDWeight,getEDWeight,getFirstGoodUpTime

 

在BasicContact类下,

    在读取simple_Times文件后,发现有up命令后,会调用parseCommandPart,

接着会在Contact UP后,会调用processEvent(CONTACT_UP, null);

        接着会调用srcNode.contactIdle(this);

public CommandStatus parseCommandPart(ArrayList<String> part, String path)
	{
		String param = part.get(0);
		CommandStatus ok = new CommandStatus(CommandStatus.COMMAND_OK);

		// Parameters without arguments:
		if (param.equals("up"))
		{
			contactUp();
			return ok;
		}

获取第一个合适的连接机会,分两部分,是否合适的标准是能否满足msg的发送时间,为什么不考虑传播时间latency和接收时间呢???发出去了,但对面的节点关闭接收机,消息还是无法收到啊???

1、 当前时间在contact内,判断剩余时间长度是否满足msg的发送时间

2、 当前时间在contact内,但长度不够,或当前时间在contact外,判断时间长度是否满足msg的发送时间

public UpTime getFirstGoodUpTime(double afterTime, Message forMsg)
	{
		// Get the time it will take to send this message over the contact
		double transferTime = 0;

		if (forMsg != null)
			transferTime = contact.getTransferTime(forMsg);

		// Find the first uptime that we care about
		int index = Collections.binarySearch(times, new UpTime(afterTime));

		// If the element wasn't found, switch the index to the positive
		// insertion point
		if (index < 0)
		{
			index = -index - 1;
			assert index >= 0;
		}

		if (index > 0 && times.get(index - 1).getTimeDown() > afterTime)
		{
			// We are in the middle of an interval
			double timeRemaining = times.get(index - 1).getTimeDown() - afterTime;

			// 这里仅仅是看是否有足够时间发送,没有管接收和传播延时
			if (timeRemaining >= transferTime)	
			{
				// There is enough time remaining in this interval: Return
				// an iterator at this point
				return times.get(index - 1);
			}
		}

		if (index == times.size())
		{
			// There are no more times!
			assert afterTime >= times.get(times.size() - 1).getTimeDown() : "AfterTime: " + afterTime + "; lastTime: "
					+ times.get(times.size() - 1).getTimeDown();

			return null;
		}

		assert times.get(index).getTimeUp() >= afterTime;

		while (index < times.size())
		{
			UpTime interval = times.get(index);
			double up = interval.getTimeUp();
			assert up >= afterTime;

			double down = interval.getTimeDown();

			if (down - up >= transferTime)
			{
				return interval;
			}

			// This interval was not long enough for this message
			index += 1;
		}

		return null;
	}

5、总结

Dtnsim2中只有MEEDMEDED的代码,没有EDLQEDAQLP的代码。


你可能感兴趣的:(Dtnsim2学习笔记)