The-ONE 是一个机会网络模拟仿真系统,使用该模拟可以方便地测试DTNs网络中各种不同的路由的效果.

背景知识

什么是DTN

DTN(Delay-Tolerant Network)是容滞网络.

现在的网络环境依托于高效的硬件设施,一个消息需要在短时间内得到回执,从而确保信息的正确传输.
而显然,当网络的现实条件无法达到要求时,信息将完全无法正常传输.

而容滞网络就是为了解决这种问题而诞生的一种新的网络.
它允许信息在发出的一天甚至更长时间后才到达,并且信息在网络中的失效时间更长.

举例而言,容滞网络就像在一个荒岛上,零零散散地居住着一些居民.居民们过着通信基本靠吼的生活.今天,岛东的A想要告诉岛西的B一件事.A把这个消息告诉了经常与自己见面的邻居岛民CDE,让他们帮自己传达.
而CDE的活动范围也是有限的,他们把消息又传达给自己经常见到的人……
就这样,消息最终传达到了B的耳朵里(当然,也有可能传达不到,或者消息已经没有意义的很久以后才传达到)

其中,又需要考虑如果一个人需要传达的消息太多,他可能会忘掉最早要传达的信息;信息如果弄得人尽皆知太兴师动众,希望尽可能少的人知道(每个人只告诉一个人)等具体要求.这就牵扯到了不同的路由.

在一种特定的情况下,如何制定一个满足以下要求的传递消息的协议(路由),就是我们应该研究的.

  • 尽可能保证信息能够传达到(递交率高)
  • 尽可能让最少人知道(开效率低)
  • 尽可能早点传递成功(延时率低)

容滞网络本身是架构于当前网络协议之上的,称之为聚束层.
比如将上面的例子中的村民变为小岛,荒岛变为大海.岛A的居民a想把消息传达给岛B的居民b
岛内的网络可能是我们当前使用的普通网络,而岛与岛之间信息的传递使用容滞网络.

在信息的传递过程中,有以下可能会涉及到的名词:
信源:消息的产生者
信束:消息的接受者
副本:消息实体在传递过程中产生的复制版本

什么是The-ONE

The-ONE是一个使用Java写的DTN网络仿真软件.
通过不同配置文件,可以设定结点的数目、移动方式、路由传递协议等各种信息
其有GUI模式和终端模式,GUI模式更为直观,而终端模式则能更快得到仿真结果.

写出自己的The-ONE路由协议

模拟环境

在一个战场上,存在指挥、士官、士兵三种级别的军人.他们在战场区域内随机移动(检查战场区域).
而每一个人都有可能会发现不同的情报.情报分为三个等级:紧急,重要,一般
显然,指挥官的发出的紧急情报最为重要,这可能会影响全局布防,而士官的紧急情报可能只会影响局部的胜负.
因此需要给不同的情报设定不同的优先程度
使用HighMiddleLow表示发出情报的人员的优先度,HML代表情报的优先度.如:士官发出的紧急情报为MiddleH

很显然,优先度越高的情报应该更快送达目的地,如何实现更快呢?
计算机中最常见的加快速度的方法就是:空间换时间
也即放弃一部分开销率来换取更高的递交率和更小的延时率

我们选择使用**二分散发等待路由(Spary and Wait)**来实现消息的传递.
二分散发等待路由类似发传单.信源把需要传递的信息印成特定份数的传单(当然,发出去前事实上并没有占用空间,也即发出去后才印制传单).传递消息的时候会把一半的传单给遇到的人,让它帮自己发……
这样,对于每个有传单的结点,都会把一半的传单发给遇到的人,让他们帮自己发.直到自己只剩下一张传单,这张就留着,等到遇到信束后直接给它.

同时,考虑到每名军人的存储装置的容量有限.因此消息是有可能被移除掉的.有两种针对缓存区的删除方式:

  • 删除最早的消息
  • 根据优先级按概率删除

分析The-ONE的相关代码

The-ONE里本身就有一个散发等待的路由协议,我们可以直接从这里看起.

src/routing/SprayAndWaitRouter.java

根据代码可以大概分析出以下内容:

  • 该类继承与ActiveRouter
  • 该类的成员函数只有简单的实现部分操作
  • 所有使用散发等待模型的初始副本数是确定的

前两点说明了SprayAndWaitRouter大多数实现继承于父函数,并且路有部分在仿真时是由其它部分调用的
最后一点则说明自带的散发等待不能满足我们的要求(根据不同的优先级产生不同的副本)
其具体实现位于createNewMessage函数中的msg.addProperty(MSG_COUNT_PROPERTY, new Integer(initialNrofCopies));

对于我们而言,路由部分需要实现不同优先级不同初始副本数以及按照优先级概率删除缓存区信息

不同优先级不同初始副本数

实现不同副本数就在我们刚才看到的那段函数中,我们在新建消息的时候,根据不同的消息种类,初始化不同的副本数即可 、
获取消息的名字可以用m.getId(),他返回的id是perfix+number,只需要消去数字部分即可

按照优先级概率删除缓存区信息

这一部分也是路由的一部分,不过定义在src/routing/ActiveRouter.javamakeRoomForMessage函数中
这个函数是结点空间不够的时候,释放原有信息的函数,其中的getNextMessageToRemove返回的就是下一个要删除的信息
我们来看一下它的具体实现
{% fold %}

protected Message getNextMessageToRemove(boolean excludeMsgBeingSent) {
		Collection<Message> messages = this.getMessageCollection();
		Message oldest = null;
		for (Message m : messages) {
			if (excludeMsgBeingSent && isSending(m.getId())) {
				continue; // skip the message(s) that router is sending
			} 
			if (oldest == null ) {
				oldest = m;
			} else if (oldest.getReceiveTime() > m.getReceiveTime()) {
				oldest = m;
			}
		}
		return oldest;
	}

{% endfold %}

很容易看出来,这段代码返回的是buffer里最早的信息,也即按照时间删除
而我们需要修改出另一个buffer管理策略:按照优先级概率删除

由于直接给定百分比删除存在较多的问题,难以计算,可以换一种策略进行随机选择
定义一个值:删除率
加入HighH到LowL的删除率分别为1、2、3、4、5、6、7、8、9,那么如果一个结点中有2个HighL、5个MiddleM、10个LowL
我们将信息复制其删除率份到一个新的链表里,即新的链表里有6个HighL、25个MiddleM、90个LowL,在这121个消息中,随机选择一个消息,返回给上一层函数,实现删除功能,可以近似看做是按照概率删除.
(当然,直接实现我们原本意义上的按照概率删除是其实是非常难的)

实现我们自己的代码

要实现我们自己的代码,需要先知道如何读入配置信息
可以不去看相关的代码实现部分,之间研究其它地方读入的代码

Settings s = new Settings(namespace);
s.getInt(key);
s.getSetting(key);

通过这样的的方法获取指定的设置

因此只需要读入相应的设置,然后更改对应的函数即可

参数的设定

如何设定一组靠谱的数据呢?
首先要明确我们的要求

初步,我们设定为10000×10000的野外,每名军人是随机移动(随机路点模型)
根据人类正常步行速度,将结点移动速度设定为(1,2)
无线电通信范围为100米,传输速度为500k
军人结点共三种,分别为High,Middle,Low分别代表三种优先级的军人
而每种军人又能发出三种不同的消息,共9种,分别是'HighH',HighM,HighL,MiddleH,MiddleM,MiddleL,LowH,LowM,LowL
根据我们设定的路由,这9种消息的最大副本数分别为256,128,64,64,32,16,16,8,4
而他们的删除率分别为2,4,8,3,6,12,4,8,16

这样我们可以通过不同的事件的结果对比得出不同参数的影响

再看消息的产生数量.首先,3种结点数目为5,75,900,体现了不同级别的军人的数量不同
不同优先级的事件的产生时间间隔为480~600min,300~360min,120min~240min

由于the-one的产生频率是根据事件来确定的,与结点无关,因此事件产生需要两个参数结合计算
可以得到

  H M L
High (3600,4320) (2160,2880) (720,1440)
Middle (240,288) (144,192) (48,96)
Low (20,24) (12,16) (4,8)

每种数据的大小为(50k,2M),而每个人能存储的最大信息量为50M,信息失效时间为1800(每次传递后重新计算)