TheONE全称为The OpportunisticNetwork Environmentsimulator,是一款Java平台的容迟网络仿真软件,本文采用一条纵线分析了TheONE中消息转发的流程。
1. 消息转发的入口
跟踪发包流程最主要的是找到入口,ONE与NS2最大的区别在于:NS2是离散事件驱动的,而ONE采用的是周期更新即Update,如果把网络中的事件比喻成出门坐车,那么NS2像是打车,招手即停,而ONE是坐公交,公交车每隔一段时间来一班,这个时间间隔就是Update的周期,在default_setting.txt中定义为0.1秒。于是最先要找到的就是update函数。ONE核心的功能可以看作由两大部分组成,一是移动,二是消息转发,简而言之,前者根据移动模型确定下一时段各节点的位置坐标,后者根据接口和路由来决定节点是否应该收到一个消息。本文讨论的是消息转发流程,因此忽略节点移动部分,直接找到消息转发的入口。
DTNHost是ONE中最基本的类,它定义了一个节点(后文将节点与Host等同)的基本属性和基本功能,在DTNHost.java中的update()函数负责更新网络接口和路由。
public void update(boolean simulateConnections) {
if (!isActive()) {//如果节点处于非激活状态,则不会执行后面的语句
return;//可以将非激活状态想象成一个自私节点或者没电的传感器
}
if (simulateConnections) {
for (NetworkInterface i : net){
i.update();//更新所有的接口
}
}
this.router.update();//更新路由
}
可以看出在update()中先更新了接口,后更新了路由,原因是路由的工作需要建立在接口的基础之上。本文也先说接口,后说路由。
2. 维护有效的连接
首先要解释ONE中的一个最基本的概念——连接(Connection/Connect)。由于ONE并不侧重于底层信道的仿真,因此空中接口的概念已经淡化了,取而代之的是“连接”。简单的理解,当两个节点在彼此通信范围之内,连接就认为是建立的,ONE习惯中用UP表示,反之用DOWN。ONE中提供了一系列函数用于维护所有节点之间的连接。详细情况可以读一下connection.java。一个最基本的连接包括了:
protected DTNHost toNode;//连接的目的节点
protected NetworkInterface toInterface; //连接的目的接口
protected DTNHost fromNode;//链接的源节点
protected NetworkInterface fromInterface;//链接的源接口
protected DTNHost msgFromNode;//消息的源节点
private boolean isUp;//最重要的是连接的当前状态
protectedMessage msgOnFly;//连接正在传输的消息实际上,仿真中通常使用的是CBRConnection类,这个类继承自Connection,扩展了:
private int speed;//CBR流的传输速度
private double transferDoneTime;//传输完成的时间回到update的问题上,更新接口执行的是网络接口的更新函数,在NetworkInterface类中update()是一个空函数,实际上更新的是它子类中的update()函数。在实际仿真中,经常采用SimpleBroadcastInterface作为接口类型(实际上ONE也没给我们太多的选择),因此SimpleBroadcastInterface.java中的更新函数是维护连接的关键。
public void update() {
// First break the old ones
optimizer.updateLocation(this);
for (int i=0;i<</span>this.connections.size(); ) {//遍历所有连接
Connection con = this.connections.get(i);
NetworkInterface anotherInterface =con.getOtherInterface(this);
// all connections should be up at thisstage
assert con.isUp() : "Connection " +con + " wasdown!";
if (!isWithinRange(anotherInterface)){//删除已经断开的连接
disconnect(con,anotherInterface);
connections.remove(i);
}
else {
i++;
}
}
// Then find new possible connections
Collection interfaces =
optimizer.getNearInterfaces(this);
for (NetworkInterface i : interfaces){//建立新的连接
connect(i);
}
}
这个函数的思想很简单,首先检索所有已经建立好的连接,将其中已经断开的连接删除,再找到新的可以建立的连接。这路重点需要看的是两个函数:
isWithinRange()目的是判断两个接口所在的节点是否在彼此的通信范围之内,这个函数是路由与移动模型交互的地方,在仿真脚本中设置的接口传输距离、移动模型都会最这个函数的返回值产生影响。
connect()函数是建立连接的函数,在SimpleBroadcastInterface类中,建立连接并不简单,需要满足一系列条件才能建立,这些条件主要是:确保接口处于扫描状态、确保节点处于活跃状态、确保两接口所在节点彼此能通信、确保两接口不是已经连接的、确保两接口不是同一接口:public void connect(NetworkInterface anotherInterface){
if (isScanning()
&&anotherInterface.getHost().isActive()
&&isWithinRange(anotherInterface)
&&!isConnected(anotherInterface)
&& (this !=anotherInterface)) {满足这些条件的两个接口能够成功建立连接,连接建立的过程包括:将连接con添加到本节点和对方节点的connections中、将本节点和对方节点con的状态设置为UP、通知Listener连接con已经建立。在ONE中,多种Listener用于统计网络性能,生成Reports,刚开始看代码的时候,可以将所有与Listener有关的语句都忽略。
protected void connect(Connection con, NetworkInterface anotherInterface){
this.connections.add(con);
notifyConnectionListeners(CON_UP,anotherInterface.getHost());
// set up bidirectional connection
anotherInterface.getConnections().add(con);
// inform routers about the connection
this.host.connectionUp(con);
anotherInterface.getHost().connectionUp(con);
}
连接维护的实际过程要比上面所说的稍复杂,但核心思想很简单:节点周期检查自己与周围节点的位置,与满足传输条件的节点的对应接口建立连接。需要补充的是,连接的建立实际上是以接口为单位的,不是与节点为单位的,因为一个节点可以有多个接口,而不同种类接口的传输距离不同。