The ONE使用笔记:宏观角度理解事件是如何组织

本文从宏观角度讲解The ONE事件是如何组织的,即由EventQueueHandle类处理所有事件,将所有事件组织成一个队列,每个update internal处理队列的所有事件。

1. The ONE事件

1.1 事件组织

最开始以为The ONE会为每个DTNHost设置一个事件队列,但实际不是,而是全局维持一个事件队列链表(仿真与现实的差距!),由EventQueueHandle类处理所有事件。

EventQueueHandle类成员变量queues维护着整个仿真的所有事件,事件可以是:消息事件产生器MessageEventGenerator、连接事件ConnectionEvent、消息事件MessageEvent(包含消息创建、转发、删除)。The ONE所有事件(消息产生器事件、外部消息事件、连接事件)是这样组织的(队列嵌套队列)

image

图1 The ONE事件组织

1.2 事件

EventQueueHandler类维持着一个EventQueue接口类的列表,用具体实现抽象方法的类实例化接口类,实现多态,如下:

private List<EventQueue> queues;

目前只有外部事件队列ExternalEventsQueue和消息事件队列MessageEventGenerator实现了EventQueue接口,所以EventQueueHandler只能处理这两种事件队列。ExternalEventsQueue类成员变量queue将外部事件(ExternalEvent)组织成一个队列,如下:

private List<ExternalEvent> queue;

该队列包含ConnectionEventMessageEvent(包含消息创建、转发、删除)。The ONE所有事件的类图关系如下:

event_class_diagram

图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);  //创建消息
}

关于事件被触发的过程,请移步博文《The ONE使用笔记:连接事件ConnectionEvent读取与处理》。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

5 thoughts on “The ONE使用笔记:宏观角度理解事件是如何组织