本文从宏观角度讲解The ONE事件是如何组织的,即由EventQueueHandle
类处理所有事件,将所有事件组织成一个队列,每个update internal
处理队列的所有事件。
1. The ONE事件
1.1 事件组织
最开始以为The ONE会为每个DTNHost
设置一个事件队列,但实际不是,而是全局维持一个事件队列链表(仿真与现实的差距!),由EventQueueHandle
类处理所有事件。
EventQueueHandle
类成员变量queues
维护着整个仿真的所有事件,事件可以是:消息事件产生器MessageEventGenerator
、连接事件ConnectionEvent
、消息事件MessageEvent
(包含消息创建、转发、删除)。The ONE所有事件(消息产生器事件、外部消息事件、连接事件)是这样组织的(队列嵌套队列):
图1 The ONE事件组织(visio源文件:EventQueueHandle.vsdx)
1.2 事件
EventQueueHandler
类维持着一个EventQueue
接口类的列表,用具体实现抽象方法的类实例化接口类,实现多态,如下:
private List<EventQueue> queues;
目前只有外部事件队列ExternalEventsQueue
和消息事件队列MessageEventGenerator
实现了EventQueue
接口,所以EventQueueHandler
只能处理这两种事件队列。ExternalEventsQueue
类成员变量queue
将外部事件(ExternalEvent
)组织成一个队列,如下:
private List<ExternalEvent> queue;
该队列包含ConnectionEvent
和MessageEvent
(包含消息创建、转发、删除)。The ONE所有事件的类图关系如下:
图2 The ONE事件类图
2. 事件处理
2.1 EventQueueHandler
事件队列处理EventQueueHandler
在仿真初始化时创建,调用路径:**main(DTNSim)—> DTNSimTextUI().start() –> initModel(DTNSimUI) –> SimScenario.getInstance –> SimScenario**
构造函数,相关的源代码如下:
/*** 创建EventQueueHandler ***/
private EventQueueHandler eqHandler; //SimScenario.java 私有成员变量
//在SimScenario()构造函数中
this.eqHandler = new EventQueueHandler(); //创建EventQueueHandler
this.world = new World(hosts, worldSizeX, worldSizeY, updateInterval,
updateListeners, simulateConnections,
eqHandler.getEventQueues()); //eqHandler.getEventQueues()
//SimScenario.java
public List<EventQueue> getExternalEvents() {
return this.eqHandler.getEventQueues(); //返回EventQueue接口类型的列表
}
//World.java 包含所有节点,更新节点的位置和连接状态
this.eventQueues = eventQueues; //World构造函数中
private EventQueue nextEventQueue; //World.java 私有成员变量
2.2 EventQueueHandler构造函数
The ONE初始化时,创建场景SimScenario()
会创建EventQueueHandler
一个实例。EventQueueHandler
构造函数读取创建外部事件和消息产生器事件(如果有的话),其源代码如下:
public EventQueueHandler() {
Settings settings = new Settings(SETTINGS_NAMESPACE); //SETTINGS_NAMESPACE = "Events";
int nrof = settings.getInt(NROF_SETTING);
this.queues = new ArrayList<EventQueue>();
for (int i=1; i <= nrof; i++) {
Settings s = new Settings(SETTINGS_NAMESPACE + i);
/*********** 外部事件 ***********/
if (s.contains(PATH_SETTING)) {
int preload = 0;
String path = "";
if (s.contains(PRELOAD_SETTING)) {
preload = s.getInt(PRELOAD_SETTING);
}
path = s.getSetting(PATH_SETTING);
queues.add(new ExternalEventsQueue(path, preload)); //创建外部事件,并加入到queues
}
/*********** 消息产生器事件 ***********/
else if (s.contains(CLASS_SETTING)) {
String className = CLASS_PACKAGE + "." + s.getSetting(CLASS_SETTING);
EventQueue eq = (EventQueue)s.createIntializedObject(className);
queues.add(eq);
}
}
}
2.3 事件处理
各种类型事件都有相应的事件处理函数processEvent
,当事件被触发时,就调用相应的该事件的processEvent
(这点类似于钩子函数)。以MessageCreateEvent
为例,其processEvent
函数源码如下:
public void processEvent(World world) {
DTNHost to = world.getNodeByAddress(this.toAddr);
DTNHost from = world.getNodeByAddress(this.fromAddr);
Message m = new Message(from, to, this.id, this.size);
m.setResponseSize(this.responseSize);
from.createNewMessage(m); //创建消息
}
关于事件被触发的过程,请移步博文《连接事件ConnectionEvent读取与处理》。