消息监听器MessageListener
是一个接口,与消息有关的Report实现了该接口。当消息被创建、开始传输、转发、传输中止、删除时,会调用已实现MessageListener
相应的类的相应函数,更新统计信息(如MessageStatsReport
)或者输出日志信息(如EventLogReport
)。本文深入源码介绍The ONE消息监听器MessageListenner
的技术细节。理解了MessageListener
,其他Listener
也就不难了。
目录
1. MessageListener接口
消息监听器MessageListener
,类似于钩子函数,hook到消息相关的事件中,换句话说,当消息被创建、开始传输、转发、传输中止、删除时,会调用相应的钩子函数更新reports
统计信息。MessageListener
源代码如下:
public interface MessageListener { public void newMessage(Message m); public void messageTransferStarted(Message m, DTNHost from, DTNHost to); public void messageTransferAborted(Message m, DTNHost from, DTNHost to); public void messageTransferred(Message m, DTNHost from, DTNHost to, boolean firstDelivery); public void messageDeleted(Message m, DTNHost where, boolean dropped); //包含drop和remove }
MessageListener
是一个接口,有很多类(主要是Report,用于输出仿真过程的一些信息)实现了该接口,这些类只实现了MessageListener
接口的一个或多个函数,其他留空,如:CreatedMessageReport.java
只实现了MessageListener
接口的newMessage()
。实现MessageListener
接口的类,如下:
2. 创建MessageListener
The ONE维持一个全局的MessageListener
链表,初始化时,将那些实现了MessageListener
接口的report接加入到MessageListener
链表。当消息被创建、开始传输、转发、传输中止、删除时,遍历MessageListener
链表并调用相应函数,更新仿真结果。
private List<MessageListener> messageListeners; //SimScenario.java 全局MessageListener链表
2.1 设置文件
在设置文件my_settings.txt
增加需要产生的Reports
,举例如下:
Report.nrofReports = 10 Report.reportDir = nc/reports/ Report.report1 = MessageStatsReport Report.report2 = MessageDelayReport Report.report3 = MovementNs2Report Report.report4 = TotalContactTimeReport Report.report5 = MessageReport Report.report6 = DistanceDelayReport Report.report7 = EventLogReport Report.report8 = MessageGraphvizReport Report.report9 = AdjacencyGraphvizReport Report.report10 = MessageLocationReport
2.2 创建MessageListener链表
The ONE初始化,在main(DTNSim) —> DTNSimTextUI().start() –> DTNSimUI.initModel()
中,根据2.1的设置文件,将report添加到相应的监听器Listener
。相关源代码如下:
//DTNSimUI.java private void initModel() { for (int i=1, n = settings.getInt(NROF_REPORT_S); i<=n; i++) { //NROF_REPORT_S = "Report.nrofReports"; String reportClass = settings.getSetting(REPORT_S + i); //REPORT_S = "Report.report", 形如Report.report1,2,3, ... addReport((Report)settings.createObject(REPORT_PAC + reportClass)); //REPORT_PAC = "report.", 形如MessageStatsReport } } protected void addReport(Report r) { if (r instanceof MessageListener) { scen.addMessageListener((MessageListener)r); //增加MessageListener } if (r instanceof ConnectionListener) { scen.addConnectionListener((ConnectionListener)r); } if (r instanceof MovementListener) { scen.addMovementListener((MovementListener)r); } if (r instanceof UpdateListener) { scen.addUpdateListener((UpdateListener)r); } if (r instanceof ApplicationListener) { scen.addApplicationListener((ApplicationListener)r); } this.reports.add(r); //protected Vector<Report> reports; } //SimScenario.java private List<MessageListener> messageListeners; //Global message event listeners public void addMessageListener(MessageListener ml) { this.messageListeners.add(ml); }
这样,MessageListener
全局链表就创建好了,随后的初始化,将messageListeners
赋值给每个DTNHost
以及对应的MessageRouter
。相关源代码如下:
//SimScenario.java 创建所有DTNHost private List<MessageListener> messageListeners; //Global message event listeners protected SimScenario() { this.messageListeners = new ArrayList<MessageListener>(); //创建全局MessageListener createHosts(); } protected void createHosts() { this.hosts = new ArrayList<DTNHost>(); for (int i=1; i<=nrofGroups; i++) { for (int j=0; j<nrofHosts; j++) { DTNHost host = new DTNHost(this.messageListeners, this.movementListeners, gid, interfaces, comBus, mmProto, mRouterProto ); hosts.add(host); } } } //DTNHost.java Create a DTNHost,messageListeners赋值给DTNHost private List<MessageListener> msgListeners; public DTNHost(List<MessageListener> msgLs, List<MovementListener> movLs, String groupId, List<NetworkInterface> interf, ModuleCommunicationBus comBus, MovementModel mmProto, MessageRouter mRouterProto) { this.msgListeners = msgLs; setRouter(mRouterProto.replicate()); //新建MessageRouter,并初始化 } private void setRouter(MessageRouter router) { router.init(this, msgListeners); this.router = router; } //MessageRouter.java, messageListeners赋值给MessageRouter public void init(DTNHost host, List<MessageListener> mListeners) { this.incomingMessages = new HashMap<String, Message>(); this.messages = new HashMap<String, Message>(); this.deliveredMessages = new HashMap<String, Message>(); this.blacklistedMessages = new HashMap<String, Object>(); this.mListeners = mListeners; this.host = host; } /******************************************************************************/ //MessageRouter.java抽象函数replicate(), 由具体路由实现, 以ProphetRouter为例 public MessageRouter replicate() { ProphetRouter r = new ProphetRouter(this); return r; } //ProphetRouter.java构造函数ProphetRouter(ProphetRouter r), 会调用父类的构造函数ActiveRouter(ActiveRouter r), MessageRouter(MessageRouter r) protected ProphetRouter(ProphetRouter r) { super(r); //--> ActiveRouter(ActiveRouter r) --> MessageRouter(MessageRouter r) }
3. MessageListener实例
以创建消息为例。每隔updateInterval
,World.update()
依次取得外部事件,若是消息创建事件,则调用其事件处理函数processEvent
创建消息,相关源代码如下:
//MessageCreateEvent.processEvent --> DTNHost.createNewMessage --> MessageRouter.createNewMessage --> MessageRouter.addToMessages protected void addToMessages(Message m, boolean newMessage) { this.messages.put(m.getId(), m); if (newMessage) { for (MessageListener ml : this.mListeners) { //触发消息监听器 ml.newMessage(m); } } }
由上可见,消息创建好,放入messages
(理解成buffer
),触发所有消息监听器。假设设置文件包含CreatedMessagesReport
,此时会调用CreatedMessagesReport.java
实现的MessageListener
接口的newMessage
函数(只实现了MessageListener
接口的newMessage
,其他接口函数留空),向文件写入日志信息。newMessage
源代码如下:
public void newMessage(Message m) { if (isWarmup()) { return; } int ttl = m.getTtl(); write(format(getSimTime()) + " " + m.getId() + " " + m.getSize() + " " + m.getFrom() + " " + m.getTo() + " " + (ttl != Integer.MAX_VALUE ? ttl : "n/a") + (m.isResponse() ? " Y " : " N ")); }
将日志信息输出到*_CreatedMessagesReport.txt
文件,取部分结果如下:
32.0000 M1 8834 p0 p34 1440 N 58.0000 M2 7273 p43 p4 1440 N 84.0000 M3 8122 p5 p65 1440 N 112.0000 M4 8257 p61 p67 1440 N 144.0000 M5 9671 p36 p11 1440 N 170.0000 M6 6032 p71 p35 1440 N 203.0000 M7 7010 p3 p69 1440 N
4. 其他Listener
理解了MessageListener
,其他Listener
也就不难了。
//SimScenario.java private List<ConnectionListener> connectionListeners; private List<MessageListener> messageListeners; private List<MovementListener> movementListeners; private List<UpdateListener> updateListeners; private List<ApplicationListener> appListeners;赞赏
微信赞赏
支付宝赞赏
Pingback: The ONE使用笔记:DTNHost包含些什么 | Spark & Shine
Pingback: The ONE使用笔记:深入源码理解消息创建过程 | Spark & Shine
Pingback: The ONE使用笔记:目录 | Spark & Shine