做者:SunSmile 出處:http://www.cnblogs.com/sunsmilecs 歡迎轉載,也請保留這段聲明。node
DTN路由是移動網絡環境中研究最熱門的方向,基於機率的路由、基於效用的路由、基於預測的路由、基於社會網絡的路由甚至是社交網絡中人與人之間聯繫的緊密程度都拿來做爲路由決策的依據。而ONE是專門的DTN路由仿真器,當前網絡上對於ONE仿真器的相關資料較少,特總結其路由模塊的工做原理。
首先須要瞭解core包中類之間的關係,以及分別對應實際DTN網絡中的哪些實體。
a)DTNHost模擬的是DTN網絡中的移動節點,其具體的移動規律或者移動路徑是由MovementModel決定的。
b)NetworkInterface是網絡接口設備,也就是一般說的網卡,因爲節點有可能安裝多個網卡,所以,DTNHost與NetworkInterface之間是一對多的關係
c)Connection就是兩個及以上的DTNHost在移動過程當中進入彼此無線通訊半徑以後,自動創建起無線鏈接,並能夠進行通訊
d)Application是運行在DTNHost之上的應用程序,其主要功能是負責生成消息和接收消息;
e)MessageRouter至關於傳統的網絡路由器,但DTN網絡中,每一個節點有須要具備消息轉發功能,所以,每一個DTNHost都須要包含一個MessageRouter,並將其大部分與消息相關的處理都交給MessageRouter負責。緩存
一個完整的消息傳輸過程是這樣的:DTNHost的某個Application在運行過程當中可能須要與其餘節點的Application進行通訊,從而須要生成消息和接收消息,DTNHost的消息操做經過MessageRouter代爲執行,MessageRouter在消息的傳輸過程當中決定消息轉發給哪個鄰居節點(DTNHost的鄰居節點動態性較高,變化比較頻繁)。而消息的傳輸必須經過鏈接兩個不一樣DTNHost節點上NetworkInterface的Connection進行傳輸,所以,當消息離開上一跳節點但還未到達下一跳節點時,消息是由Connection進行管理的。
節點在移動的過程當中,還須要接收其餘節點發送的消息,並轉發給最可能到達目的節點的下一跳節點,也就是擔當中間節點的角色。所以,MessageRouter在轉發消息的時候首先判斷當前是否存在鄰居節點,若是存在那麼從消息緩存(messages列表)中取出一條消息(具體去哪條消息是路由策略相關,能夠是FIFO,也能夠是基於優先級的),將其發送給下一跳節點。此外,MessageRouter負責管理DTNHost的緩存,在ONE中的實現直接將緩存做爲MessageRouter的屬性,所以消息的刪除一樣是經過MessageRouter完成的。網絡
有一點須要詳細解釋的是,這裏認爲只有消息的發送和接收,是DTNHost中的Application參與,消息中間過程在Application是看不到的。所以當調用DTNHost.sendMessage(msgid,to)時,認爲消息直接就從源節點到目的節點了,一樣接收消息DTNHost.receiveMassage(message,from),也是認爲直接就從源節點接收到目的節點了。所有消息在中間節點的轉發和丟棄都是在MessageRouter中完成的,而MessageRouter進行轉發和丟棄的動做都是在節點運動過程當中是否兩個節點都進入彼此的無線通訊半徑以後且離開通訊半徑以前完成的。換言之,MessageRouter的驅動力來自兩個方面:一是DTNHost上運行的Application;二是DTNHost的不斷運動。函數
前者天然沒必要多說,這裏從ONE的代碼實現角度來理清楚DTNHost的運動是如何致使MessageRouter的相關動做的。首先ONE仿真器的主循環(也就是說主循環的一次循環要完成仿真中全部時間和事件的更新)是在ui.DTNSim.runSim()函數(此函數的具體實現是在其子類ui.DTNSimTextUI.runSim()和gui.DTNSimGUI.runSim()),這個函數反覆調用core.World.update()函數(world類就是仿真環境中的世界,其update()表示更新全部時間和事件)。core.World.update()函數中updateHosts()和moveHosts()兩個函數,而它們正好對應DTNHost的應用更新和位置更新。更進一步,MessageRouter及其子類的主要函數都是經過updateHosts()和moveHosts()間接調用的。ui
public static void main(String[] args) { //省略初始化代碼 if (batchMode) {//批處理模式下,也就是Shell模式下 long startTime = System.currentTimeMillis(); for (int i = nrofRuns[0]; i < nrofRuns[1]; i++) { // print("Run " + (i + 1) + "/" + nrofRuns[1]); Settings.setRunIndex(i); resetForNextRun(); new DTNSimTextUI().start();//仿真器啓動函數 } double duration = (System.currentTimeMillis() - startTime) / 1000.0; print("---\nAll done in " + String.format("%.2f", duration) + "s"); } else {//GUI模式下 Settings.setRunIndex(guiIndex); new DTNSimGUI().start();//仿真器啓動函數 } }
public abstract class DTNSimUI { //省略部分代碼 /** * Runs simulation after the model has been initialized. */ protected abstract void runSim(); //省略部分代碼 }
public class DTNSimTextUI extends DTNSimUI { //省略部分代碼 protected void runSim() { double simTime = SimClock.getTime(); double endTime = scen.getEndTime(); print("Running simulation '" + scen.getName() + "'"); startTime = System.currentTimeMillis(); lastUpdateRt = startTime;
//這裏就是ONE仿真器的主循環 while (simTime < endTime && !simCancelled) { try { world.update(); //看這裏^_^,全部事件的更新 } catch (AssertionError e) { e.printStackTrace(); done(); return; } simTime = SimClock.getTime(); this.update(false);//時間更新 } //省略部分代碼 } //省略部分代碼 }
/** * World contains all the nodes and is responsible for updating their location * and connections. */ public class World { //省略部分代碼 public void update() {/* process all events that are due until next interval update */ while (this.nextQueueEventTime <= runUntil) { simClock.setTime(this.nextQueueEventTime); ExternalEvent ee = this.nextEventQueue.nextEvent(); ee.processEvent(this); updateHosts(); //更新全部DTNHost setNextEventQueue(); } moveHosts(this.updateInterval);////更新全部DTNHost位置 simClock.setTime(runUntil); updateHosts();//更新全部DTNHost } //省略部分代碼 }
最終的結論就是,只要NetworkInterface中存在的Connection都是當前正在鏈接中的,所以能夠直接用來進行消息傳輸。其中,一個DTNHost中存在多個NetworkInterface,而多個NetworkInterface存在多個Connections,所以,MessageRouter某時刻可用的Connection數量可能值爲0,1,2,……this
到這裏,就解決了MessageRouter能夠用來進行傳輸Message的Connection來源問題以及何時調用MessageRouter的問題了。至此,MessageRouter的工做原理也應該算講清楚了。spa