The ONE使用笔记:消息发送队列(随机和先进先出)

The ONE目前支持两种消息队列:先进先出FIFO和随机。本文介绍与之相关的技术细节,以及介绍如何添加新的消息模式。

1. 消息发送队列模式

The ONE目前支持两种消息发送队列:先进先出FIFO和随机。

//MessageRouter.java
public static final int Q_MODE_RANDOM = 1;
public static final int Q_MODE_FIFO = 2;

可以在设置文件设置消息队列模式,若不设置,则默认为随机。

Group.sendQueue = 1  # 随机,默认
Group.sendQueue = 2  # 先来先到FIFO

值得注意的是,The ONE使用HashMap组织消息,HashMap是无序的,所以getMessageCollection()取得的消息是无序的。如果消息要按某种排序(FIFO),需先换成实现List接口的类存储,再调用sortByQueueMode排序队列。使用方法如下:

//ActiveRouter.java的tryAllMessagesToAllConnections()
List<Message> messages = new ArrayList<Message>(this.getMessageCollection());
this.sortByQueueMode(messages);

getMessageCollection()源代码如下:

//MessageRouter.java
private HashMap<String, Message> messages;
public Collection<Message> getMessageCollection() {
    return this.messages.values();
}

2. 随机模式

随机器取决于当前仿真时钟,如果一个节点在update interval被更新多次,那么消息的顺序是一样的。相关源代码如下:

//MessageRouter.java
protected List sortByQueueMode(List list) {
    switch (sendQueueMode) {
    case Q_MODE_RANDOM:
        Collections.shuffle(list, new Random(SimClock.getIntTime()));
        break;
    }
}

3. 先进先出

先接收到的消息在队头,后接收到的消息在队尾。支持两种List:MessageTuple<Message, Connection>,源代码如下:

//MessageRouter.java
protected List sortByQueueMode(List list) {
    switch (sendQueueMode) {
    case Q_MODE_FIFO:
        Collections.sort(list, new Comparator() {
            public int compare(Object o1, Object o2) {
                double diff;
                Message m1, m2;
                //Tuple<Message, Connection>
                if (o1 instanceof Tuple) { 
                    m1 = ((Tuple<Message, Connection>)o1).getKey();
                    m2 = ((Tuple<Message, Connection>)o2).getKey();
                } else if (o1 instanceof Message) {
                    m1 = (Message)o1;
                    m2 = (Message)o2;
                } else {
                    throw new SimError("Invalid type of objects in " + "the list");
                }

                diff = m1.getReceiveTime() - m2.getReceiveTime();
                if (diff == 0) {
                    return 0;
                }
                return (diff < 0 ? -1 : 1);
            }
        });
        break;
    }
}

4. 新消息在队尾

对于FIFO,新产生的消息是在队头还是队尾?要回答这个问题,只需看新创建消息的成员变量timeReceived被设成了什么,代码如下:

//Message.java
publi Message(DTNHost from, DTNHost to, String id, int size) {
    ...
    this.timeCreated = SimClock.getTime();
    this.timeReceived = this.timeCreated;
    ...
}

可见,新创建消息的timeReceived被初始化成当前仿真时钟,所以新创建的消息被放在队尾。顺便提一下,判断一个消息是否新创建的方法如下:

if (m.getCreationTime() == m.getReceiveTime())

5. 添加新模式

理解了上面的内容,添加新的消息模式就很简单了,最主要是修改sortByQueueModecompareByQueueModesortByQueueMode对buffer的消息排序;compareByQueueMode(m1, m2)比较两个消息谁在前面,返回-1m1在前面;返回1m2在前面;返回0,则表示不确定。在MaxPropProphet都用到了这个函数。完整步骤如下:

//MessageRouter.java
//步骤1:添加静态变量
public static final int Q_MODE_FIFO_EXTEND = 3;

//步骤2:修改构造函数,sendQueueMode > 2更为3
public MessageRouter(Settings s) {
    if (s.contains(SEND_QUEUE_MODE_S)) {
        this.sendQueueMode = s.getInt(SEND_QUEUE_MODE_S);
        if (sendQueueMode < 1 || sendQueueMode > 2) { //sendQueueMode > 3
            throw new SettingsError("Invalid value for " + s.getFullPropertyName(SEND_QUEUE_MODE_S));
        }
    }
}

//步骤3:修改sortedQueueMode
protected List sortByQueueMode(List list) {
    switch (sendQueueMode) {
    case Q_MODE_FIFO_EXTEND:
        ...
        break;
    }
}

//步骤4:修改compareByQueueMode
protected int compareByQueueMode(Message m1, Message m2) {
    switch (sendQueueMode) {
    case Q_MODE_FIFO_EXTEND:
        ...
        return ...;
    }
}

//步骤5:在设置文件设置
Group.sendQueue = 3

发表评论

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