The ONE使用笔记:深入源码理解消息创建过程

可以使用The ONE的消息事件产生器MessageEventGenerator自动创建消息,本文深入源码介绍用MessageEventGenerator创建消息的过程。

1. MessageEventGenerator

1.1 设置文件

可以用The ONE的MessageEventGenerator产生消息事件,进而自动创建消息,在my_settings.txt设置如下:

# my_settings.txt
Events2.class = MessageEventGenerator
Events2.interval = 25,35
Events2.size = 5k,10k
Events2.hosts = 0, 79
Events2.tohosts = ...
Events2.prefix = M

值得注意的是,hoststohosts包括下界但不包括上界,即[0, 79)sizeinterval上下界都不包括,即(min, max)详情见MessageEventGenerator.java

1.2 加入事件队列

The ONE初始化时,会创建EventQueueHandler的一个实例,用于管理The ONE所有事件,详情可参考博文《The ONE使用笔记:宏观角度理解事件是如何组织》。MessageEventGenerator事件就是在EventQueueHandler构造函数中被加入到事件队列的。相关源代码如下:

//EventQueueHandler.java
public EventQueueHandler() {
    ...
    //消息产生器事件
    else if (s.contains(CLASS_SETTING)) {
        String className = CLASS_PACKAGE + "." + s.getSetting(CLASS_SETTING); //即input.MessageEventGenerator
        EventQueue eq = (EventQueue)s.createIntializedObject(className);
        queues.add(eq);  //加入到事件队列
    }
    ...
}

1.3 消息Message

描述一个消息Message的属性有:id,从哪里来到哪里去,创建和接收时间,TTL,大小等。Message的主要成员变量如下:

//Message.java
//identify 
private String id;
private int uniqueId;  //Unique ID of this message
private String    appID;  //Application ID of the application that created the message

//about DTNHost
private DTNHost from;
private DTNHost to;
private List<DTNHost> path;  //消息经过的路径

private int size;  //bytes
private int initTtl;
private double timeReceived;
private double timeCreated;

private int responseSize;
private Message requestMsg;

2 消息创建

消息创建分两步:首先,由MessageEventGenerator.nextEvent()产生一个消息创建事件MessageCreateEvent;而后,当轮到处理MessageCreateEvent时,才真正创建一个消息。

2.1 消息创建事件

轮到处理MessageEventGenerator事件时,调用其nextEvent创建一个消息产生事件(只是一个事件,还不是消息)。更确切的说,World.updatethis.nextEventQueue.nextEvent得到一个消息创建的外部事件。相关源代码如下:

//MessageEventGenerator.java
public ExternalEvent nextEvent() {

    /* 从某个范围(在settings文件设置)随机选择消息的source, sink, size, interval */
    from = drawHostAddress(this.hostRange);
    to = drawToAddress(hostRange, from);
    msgSize = drawMessageSize();
    interval = drawNextEventTimeDiff(); //再过interval,再产生一个新的消息

    /* 产生消息创建事件MessageCreateEvent */
    MessageCreateEvent mce = new MessageCreateEvent(from, to, this.getID(), msgSize, responseSize, this.nextEventsTime);
    return mce;
}

//MessageCreateEvent.java
public MessageCreateEvent(int from, int to, String id, int size, int responseSize, double time) {
    super(from,to, id, time);
    this.size = size;
    this.responseSize = responseSize;
}

由此可见,MessageEventGenerator实际上是产生一系列消息创建事件,正如其名。  

2.2 创建消息

首先,需要获取消息创建事件,每隔updateIntervalWorld.java中的update()会逐一处理事件。相关源代码如下:

//World.java中的update()
public void update () {
    ......
    setNextEventQueue();  //找到一个事件队列,该事件队列含有本updateInterval可以处理的事件
    while (this.nextQueueEventTime <= runUntil) {
        simClock.setTime(this.nextQueueEventTime);
        ExternalEvent ee = this.nextEventQueue.nextEvent();  //取得事件
        ee.processEvent(this);  //处理事件
        updateHosts();  //update all hosts after every event
        setNextEventQueue();
    }
    ......
}

从上述代码可见,取得一个事件队列(setNextEventQueue,可能是EventQueue类型的MessageEventGenerator),紧接着处理之processEventprocessEvent()在这里对应于MessageCreateEventprocessEvent函数,旨在创建消息。相关源代码如下:

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

//DTNHost.java
DTNHost.createNewMessage --> MessageRouter.createNewMessage

//MessageRouter.java
public boolean createNewMessage(Message m) {
    m.setTtl(this.msgTtl);
    m.addToMessages( true);     //将消息加入到HashMap<String, Message> messages
    return true;
}

至此,一个消息创建完毕。值得注意的是,当一个新消息被创建时,会触发消息监听器MessageListenerMessageListener是一个接口,实现该接口主要是一些reports。通俗理解就是消息被创建后,通知相关reports更新统计信息(如CreatedMessagesReport, MessageStatsReport)。相关源代码如下:(详情可参考博文《The ONE使用笔记:深入源码理解消息监听器MessageListener》)

//MessageRouter.java
protected void addToMessages(Message m, boolean newMessage) {
    this.messages.put(m.getId(), m);

    if (newMessage) {
        for (MessageListener ml : this.mListeners) {   //触发消息监听器
            ml.newMessage(m);
        }
    }
}

发表评论

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

21 thoughts on “The ONE使用笔记:深入源码理解消息创建过程

  • 2016年06月02日 星期四 at 02:47下午
    Permalink

    Spark您好!您知道为什么我在消息到达目的节点之后,创建反馈消息之后,传递的消息在报告中显示比设定的高了呢?好奇怪啊!

    Reply
  • 2016年05月07日 星期六 at 10:01下午
    Permalink

    您好!能问您一下如果我用Epdemic路由进行消息传输,为什么源节点产生的消息数量越多路由开销却越小呢?

    Reply
    • 2016年05月10日 星期二 at 08:04下午
      Permalink

      As you may already know, the overhead ratio is defined as (#relayed – #delivered) / #delivered. It is true that the more messages created, in general, the more messages relayed. But how does the number of delivered messages vary in your case?

      Reply
  • 2016年05月06日 星期五 at 06:53下午
    Permalink

    你好,你的文章写得很好,非常感谢。我对这个仿真器还不熟悉,我想问下什么时候调用消息转发,另外,您是否研究过one里的POIs设置和修改?

    Reply
  • 2016年04月30日 星期六 at 11:36上午
    Permalink

    Spark 您好!我是想问当目的社区内的节点收到了消息,第一个收到消息的节点将以广播的方式发送一个反馈消息给在通讯范围内的非本社区内节点,我就是搞不懂这个反馈消息应该怎么创建和转发。能像被传递的消息那样创建和转发吗?能不能给我一点提示和思路。谢谢您的多次回复。

    Reply
    • 2016年04月30日 星期六 at 10:34下午
      Permalink

      THE ONE没有现成的反馈消息创建与转发,你得自己实现。在操作上,跟普通消息一样创建与转发。你把消息的接收与转发理解成事件驱动,编程起来就容易了。收到消息后 –> 广播告诉邻居 –> 邻居收到消息 —> 删除掉该消息的副本。

      Reply
      • 2016年05月02日 星期一 at 10:25上午
        Permalink

        谢谢,您帮了我一个大忙。