關於NS3的事件調度機制的理解

ns-3是一個離散事件網絡模擬器。各個事件都會有個指定執行的預定模擬時間。從概念上講,模擬器會跟蹤預定好模擬時間待執行的多個事件。模擬器的工作機制是按預定模擬時間順序執行事件,依次調度。一旦事件發生並執行完成,模擬器將移動到下一個事件執行。

要做到上述的一切,模擬器需要有以下一些要素:

(1)模擬器對象,該對象可以訪問事件隊列,並可以管理事件的執行。

(2)調度程序,負責插入和刪除隊列中的事件。

(3)一種表示模擬時間的方式。

(4)事件本身,通常是某個函數。

產生調度事件的方式有兩種,即需要和不需要context,這裏的context包含的是事件對應的節點的信息。如果要調度的事件仍是由該節點執行的,則不需要context。而如果是產生跨節點的調度事件的,則需要給調度器傳遞context即節點的信息。跨節點的調度事件的這種情況通常發生在發送包被傳遞到信道,要使信道中其它節點能接收到該數據包,則在調度接收事件時還要傳遞目標節點的context信息。

這兩種調度方式分別是:

Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj);

Simulator::ScheduleWithContext (uint32_t context, Time const &time, MEM mem_ptr, OBJ obj);

其中參數time是事件的預定執行時間,參數mem_ptr是被調度的事件的指針,參數obj是發起該調度的類對象的指針。

ns3的腳本在設置應用層的時候,實際上就已經產生了一個發包事件。一個應用層的發包事件是一個接一個的,一個發包事件結束後,將根據應用層的實際情況,計算時間間隔,以此時間間隔產生下一次的發包事件。產生的發包事件會被添加到事件隊列。

在仿真腳本的最後,往往會有以下代碼:

Simulator::Stop (Seconds (21.0));
Simulator::Run ();
Simulator::Destroy ();

      第一句是預先設定仿真結束時間,如果沒有這句,仿真運行將會永遠停留在Simulator::Run ()中。

Simulator::Run ()相當於一個循環,該循環會不斷檢測事件隊列的待執行事件,把預定時間最先的(先入列不一定先執行,要看事件的執行時間)的事件出列,執行完畢,再執行下一個。在非realtime仿真模式下,模擬器不關心真正的仿真時間,只會按照事件的發生順序一個個執行,仿真時間被壓縮,仿真過程就很快執行完成。在realtime模式下,事件的執行時間就會嚴格與設定的時間一致,仿真過程就會比較慢。實時化仿真代碼如下:

GlobalValue::Bind ("SimulatorImplementationType",
                     StringValue ("ns3::RealtimeSimulatorImpl"));

Simulator::Run ()會運行到設定的stop時間後退出,由Simulator::Destroy ()釋放相關資源。到此仿真結束。

因此仿真過程都是在Simulator::Run ()這個類似於死循環的函數下完成的,它負責執行各個事件。而事件的產生都是由最初的應用層初始化時候發起的,它產生一個發包事件,發包事件被Simulator::Run ()中執行,然後逐層協議往下傳遞數據包(期間可能還會有中間事件),到最底層會計算信道延時、信噪比、誤碼等參數,然後產生收包事件。由於收包事件是要由別的節點執行,因此會用到上文所描述的context。而發包事件完成前,又會預定下一個發包事件。因此,應用層發包事件會源源不斷的依次產生,而每個發包事件結束前又會產生其它節點的收包事件,其它節點收包事件又接着被執行。該過程會運行,直到應用層stop時間結束。應用層設置啓動和結束時間的代碼的示例如下:

clientApps.Start (Seconds (2.0));
clientApps.Stop (Seconds (19.0));

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章