The ONE仿真器进行一系列初始化之后,开始仿真,详情可参考博文《main函数剖析》。仿真的核心部分是world.update()函数,world.update负责每隔一段时间,处理所有事件,并且更新所有节点。本文讲解The ONE仿真器每隔一段时间都做些什么。

1. The ONE运行机制

The ONE是基于代理离散事件(agent-based discrete event)仿真器。把节点间连接建立UP或DOWN,消息产生、发送、接收都视为事件,The ONE进行一些初始化工作后,开始仿真。每隔一段间(通过在设置文件Scenario.updateInterval来设置),系统处理每一个到期的事件,并同时更新所有节点。

1.1 main函数

以批处理(batch mode)为例,main函数整个调用过程如下,详情参考博文《main函数剖析》:

main(String[] args)    //DTNSim.java 
    initSettings(confFiles, firstConfIndex);  //初始化设置,读入default_settings.txt
    new DTNSimTextUI().start();
        initModel();         //创建仿真模型
        runSim();            //开始仿真
            world.update();  //在每个updateInterval,处理所有到期事件

1.2 world.update

world.udate,每隔updateInterval处理所有到期事件,并更新所有节点。值得注意的是:每处理一个到期事件,都会更新所有节点。完了之后,处理节点的移动,再次更新所有节点。相关源代码如下:

//World.java
private List<EventQueue> eventQueues;  //事件队列链表,用链表将事件队列组织起来
public void update () {
    double runUntil = SimClock.getTime() + this.updateInterval;  //

    /* process all events that are due until next interval update */
    setNextEventQueue();  //找到一个事件队列,该事件队列含有本updateInterval可以处理的事件
    while (this.nextQueueEventTime <= runUntil) {
        simClock.setTime(this.nextQueueEventTime);
        ExternalEvent ee = this.nextEventQueue.nextEvent();  //取得事件
         ee.processEvent(this); //处理事件,见2
        updateHosts();         //update all hosts after every event,见3
        setNextEventQueue();   
    }

    moveHosts(this.updateInterval);  //Moves all hosts in the world for a given amount of time
    simClock.setTime(runUntil);
    updateHosts();
}

2. 处理事件

消息的创建、转发、接收,连接的建立、撤消都可以视为事件。值得注意的是:使用MessageEventGenerator自动创建消息,只有创建消息事件MessageCreateEventworld.updateprocessEvent被处理,消息转发、接收则是在相关路由器的update被处理。我用MessageEventGenerator产生消息,用静态移动模型(即导入外部数据集,如infocom06)来仿真,以下是world.update处理的部分事件:

CONN up @464.0 43<->8
CONN up @464.0 43<->17
CONN down @464.0 43<->17
CONN up @464.0 43<->23
CONN down @464.0 43<->23
CONN down @464.0 43<->44
CONN up @464.0 43<->53
CONN up @464.0 43<->57
CONN down @464.0 43<->61
MSG @464.0 M16 [8->1] size:1016 CREATE
CONN up @465.0 0<->5
CONN down @465.0 0<->5
CONN down @465.0 0<->6

可见,在我的例子中,world.update只需处理消息创建和连接建立、撤消事件。关于事件处理,可参考博文《消息创建过程》和《连接事件ConnectionEvent读取与处理》。

3. updateHosts

3.1 节点顺序

The ONE仿真器将所有节点组织成一个ArrayList,依次取出节点做更新。这里取出节点的顺序有两种:其一,按网络地址network address排序的;其二,随机顺序。默认是随机顺序,可在设置文件设置,相关源代码如下:

# 可在设置文件设置
Optimization.randomizeUpdateOrder = true

public static final boolean DEF_RANDOMIZE_UPDATES = true; //默认是随机顺序,World.java

随机的顺序取决于当前的仿真时钟,相关源代码如下:

//World.java
private List<DTNHost> hosts;   //indexed by their network address
private ArrayList<DTNHost> updateOrder; //randomized order

//对所有节点进行随机排序,World.java的updateHosts()
Random rng = new Random(SimClock.getIntTime());
Collections.shuffle(this.updateOrder, rng);

3.2 updateHosts

updateHosts根据节点是否随机顺序,依次更新每一个节点,简化后的源代码如下:

//World.java
private void updateHosts() {
    if (this.updateOrder == null) { //indexed by their network address
        for (int i=0, n = hosts.size(); i < n; i++) {
            hosts.get(i).update(simulateConnections);
        }
    } else { //random order
        for (int i=0, n = hosts.size(); i < n; i++) {
            this.updateOrder.get(i).update(simulateConnections);
        }
    }

    if (simulateConOnce && simulateConnections) {
        simulateConnections = false;
    }
}

simulateConnections用于标识网络层network layer是否需要被更新,simulateConOnce标识只更新一次,相关源代码如下:

//World.java
private boolean simulateConnections; //Should network layer be updated too

private boolean simulateConOnce;  //Should the connectivity simulation be stopped after one round
public static final String SIMULATE_CON_ONCE_S = "simulateConnectionsOnce";
simulateConOnce = s.getBoolean(SIMULATE_CON_ONCE_S, false); //默认是false,可以在设置文件更改:Optimization.simulateConnectionsOnce

4. DTNHost.update

节点的更新,先判断节点是否处于活动状态,若不是,断开与该节点建立的所有连接;接着,判断是否需要更新网络层;最后,调用路由协议的update。其源代码如下:

public void update(boolean simulateConnections) {
    if (!isRadioActive()) {  // Make sure inactive nodes don't have connections
        tearDownAllConnections();
        return;
    }

    if (simulateConnections) {
        for (NetworkInterface i : net) {
            i.update();
        }
    }
    this.router.update();
}

关于router.update,可以参考博文《消息转发过程》和《消息接收过程》。

本文系Spark & Shine原创,转载需注明出处本文最近一次修改时间 2022-03-27 15:46

results matching ""

    No results matching ""