550 likes | 773 Views
Ns2 一個常用的網路模擬器. 洪振洲. 台灣科技大學資管系資料庫實驗室. Ns2 一個常用的網路模擬器. 基本介紹與安裝. 認識 NS2. The NS-2 is a powerful tool for network simulation. There are many researchers use ns-2 to validate their algorithms and protocols for their network researches.
E N D
Ns2 一個常用的網路模擬器 洪振洲 台灣科技大學資管系資料庫實驗室
Ns2 一個常用的網路模擬器 基本介紹與安裝
認識NS2 • The NS-2 is a powerful tool for network simulation. • There are many researchers use ns-2 to validate their algorithms and protocols for their network researches. • NS-2 provides many supports for simulation of TCP, routing, and multicast protocol over wired and wireless network. • It also provide topology generator to create topology from a number of nodes to thousand of nodes.
NS2 資源 • 官方網站 • http://www.isi.edu/nsnam/ns/ • 下載NS2 source, 最完整NS2手冊 • 中文網頁 • http://netlab.cse.yzu.edu.tw/ns2/ • 詳細Windows安裝 • 資源整理 • http://140.116.72.80/~smallko/ns2/ns2.htm • NS2 詳細的資源
安裝需求 • 作業系統: • Linux • Windows + cygwin (在windows 下模擬的Linux 環境) • 檔案空間需求 約 1GB
下載NS2 • 由official site 下載 all-in-one 的版本 • 這是最簡單的方式,可以得到一個可用的NS2 • 目前最新版本 2.29 • 由於Ns2 為網路社群共享,所以有各式各樣的修改版本. 我使用的是 2.1b8: 是為了實現AdHoc下面的Multi-cast 所改編的版本.
簡要安裝步驟 (I) Linux 下的安裝(可以參考 install_on_Suse.txt) • 先create 安裝目錄,並給予適當權限 • 以下假設安裝在 /opt/ns2 • 必先安裝4個重要的library • Tcl 8.3.2 • Tk 8.3.2 • Otcl 1.0a7 • Tclcl 1.0b11
簡要安裝步驟 (II) • 將library copy 到 /opt/ns2 之下 • 利用指令 “tar –zxvf 檔名” 解開 • 進入每一個子目錄中,依序執行 ./configure 與 make 兩個指令. • 將ns2 的主檔copy 到 /opt/ns2之下, 並用 “tar –zxvf 檔名” 的指令解開 • 進入解開後的子目錄,打入 ./configure 的指令 • 先別執行 make, 我們要修改Makefile
簡要安裝步驟 (III) • 利用文字編輯器修改ns2 解開後目錄中的 “Makefile”, 找到一行叫 “all :$(NS) all-recursive”把其中的 all-recursive 拿掉 • 執行 make • 如果沒有錯誤訊息,就是安裝成功了
Ns2 一個常用的網路模擬器 Overview of NS2
C++ 與 TCL • NS2 中的元件是由C++ 撰寫而成 • 劇本檔語言是 TCL • 為了讓模擬實驗撰寫者能簡單操作物件,ns2 中劇本 • 對於研究新protocol 的研究者,著重於如何用C++撰寫元件(agent) • 對於研究複雜系統效能者,著重於如何用TCL描述系統
Ns2 一個常用的網路模擬器 Use C++ to write your first NS2 agent.
AgentEcho • 簡單的模擬 adhoc network 下面的echo 功能. • 所有echo 的邏輯都將寫在 名為”AdhocEcho” 的Agent 之中 • 我們預計在”AdhocEcho”中實現的功能 • 創造並列印節點基本資料 • 可以送出/回應 自訂的echo packet • 利用時鐘來建立"Time-out” 機制
在開始之前 • 建立專案子目錄: • 在NS2 主目錄之下的“AdHocEcho”子目錄 • 步驟一覽 • STEP 1. 建立 C++ 中AdHocEcho所需的 Head • STEP 2. 建立 AdhocEcho Agent 所需的基本架構 • STEP 3. 建立 Tcl srcipt來測試初步結果. • STEP 4. 修改C++ 檔案,使有 request/response 的能力 • STEP 5. 修改C++ 檔案,使其有偵測Time-out 的能力
Echo Protocol 簡述 若A 在 T 時間 執行Echo 封包內容: A
Echo Protocol 簡述 若B 在 T2 時間 收到來自A 的Echo_request B B 將只回應 A 封包內容: A
Ns2 一個常用的網路模擬器 Step 1-Step 3 建立最簡單的echo agent,並加以測試
STEP 1. 建立 C++ 中Agent所需的 HeadAdhocEcho.h (I) // 講義第二頁,程式一自訂的packet 表頭 structhdr_ahe { // 表頭結構的定義 int FromNode; double FromTime; int ReplyNode; double ReplyTime; int Type; // Type=0: request, Type=1: reply int size_; int& size() { return size_; } staticint offset_; inlinestaticint& offset() { return offset_; } inlinestatichdr_ahe* access(const Packet* p) { return(hdr_ahe*) p->access(offset_); } }; 自訂表頭
STEP 1. 建立 C++ 中Agent所需的 HeadAdhocEcho.h (II) // 講義第二頁,程式二自訂的agent class 的定義 classAgentECHO : public Agent { public: AgentECHO(); // 建構子 virtual void recv(Packet *, Handler *); // 封包入口 protected: virtual int command(int argc, const char*const* argv); // 與TCL 溝通的界面 private: int my_addr; //用來儲存自己的 address, 與溝通用的port. int data_port; };
STEP 2. 以 C++程式碼實現 AgentEcho.cc 的細節(I) • 建立的檔案是AgentEcho.cc (講義第三頁) #include "AdhocEcho.h“ #include “ip.h“ // 用來處理ip 表頭的訊息 #include “packet.h“// 處理封包必備標頭檔 inthdr_ahe::offset_; // 為了正確處理自訂packet 標頭而宣告 // 自訂標頭檔的 wrapper class, 宣告十分制式,目的是為了讓使用者能在TCL中存取自訂packet 標頭, 用處很少 static classAHEHeaderClass : public PacketHeaderClass { public: AHEHeaderClass() :PacketHeaderClass("PacketHeader/AHECHOHEAD",sizeof(hdr_ahe)) { bind_offset( &hdr_ahe::offset_ ); } } class_ahe_hdr;
STEP 2. 以 C++程式碼實現 AgentEcho.cc 的細節(II) // 十分重要的 Wrapper class for our agent.講義第三頁 – 程式五 static classAHEClass : public TclClass { public: // Agent/ADECHO 是在TCL 中 create 這個 agent 時所需要的名字 AHEClass() : TclClass("Agent/ADECHO") {} // 這個class 實際上僅是創造一個agent class 並回傳. TclObject* create(int, const char*const*) { return ( new AgentECHO() ); } } class_ahe_agent;
STEP 2. 以 C++程式碼實現 AgentEcho.cc 的細節(III) AgentECHO::AgentECHO() : Agent(PT_AECHO) { } • 1. 目前沒有需要初始化的部份,因此建構子沒有內容 • 2. “PT_AECHO” 表示AgentECHO agent 所使用的packet類別設為”PT_AECHO”. • 利用此packet 類別,Agent可以決定對應的處理. • 並且系統trace 輸出也將跟據此類別決定輸出的方式. • packet類別可以為任意值,但必須在”../packet.h” 中稍加修改. • (可參考講義第4頁)
STEP 2. 以 C++程式碼實現 AgentEcho.cc 的細節(IV) • AgentECHO預設必須要實現的函式: command • command是由tcl 對此agent class 下指令時,與c++程式溝通的介面. • 目前我們讓使用者在劇本中可以對此agent 下三種指令, 分別為: • AgentName myaddr Int1 • AgentName myport Int2 • AgentName ShowName • 指令(1)與(2)是用來告知c++程式中,agnet的addr與溝通用的port. • 指令(3) 則是要求該agent 列印出addr 與port, 可以當作debug 訊息.
STEP 2. 以 C++程式碼實現 AgentEcho.cc 的細節(V) • command 副函式接收到的訊息使用argc 表示參數個數, argv陣列實際紀錄所收到的字串內容.我們可以把上列指令(1)想像成 • AgentName myaddr Int1 • argc=3 : argv[0] argv[1] argv[2] • 判斷所輸入的指令的方式 • 1. 比對argc 數目 • 2. 比對 argv[1] 的值
STEP 2. 以 C++程式碼實現 AgentEcho.cc 的細節(VI) int AgentECHO::command(int argc, const char*const* argv) { if (argc == 2) { //AgentName ShowName if (strcmp(argv[1], "ShowName") == 0) { printf(" Hello World -- I am %d port=%d!!\n" ,my_addr,data_port); return (TCL_OK); } } else if(argc==3){ // AgentName myaddr Int1 if (strcasecmp(argv[1], "myaddr") == 0) { my_addr= atoi(argv[2]); return (TCL_OK); } if (strcasecmp(argv[1], "myport") == 0) {// AgentName myport Int2 data_port= atoi(argv[2]); return (TCL_OK); } } return Agent::command(argc, argv); }
STEP 2. 以 C++程式碼實現 AgentEcho.cc 的細節(VII) • 編輯Ns2目錄下的 Makefile, 將AdhocEcho/AdhocEcho.o 加到適當位置去. OBJ_CC = \ …… aodv/aodv_logs.o aodv/aodv.o \ AdhocEcho/AdhocEcho.o \ …… simulator.o \ • 完成後,執行make depend, make. • 若無錯誤,就完成了
STEP 3. 建立簡單TCL script 來測試AgentEcho • 我們要執行實驗的指令: • ./ns scripts/run.tcl -x 1200 -y 800 -stop 20 -tr TRACES/out.tr -mg AdhocEcho/sna_1 -sc movement_scenarios/scen-1200x800-30-500-10-1 -nn 30 -rp AdhocEcho • 使用ns 主程式執行 scripts/run.tcl 的設定檔file. • -x, -y 用來描述實驗範圍的大小為 1200x800 m2. • -stop 設定此實驗模擬20 secs, • -tr 則是指定log 檔的位址.
STEP 3. 建立簡單TCL script 來測試AgentEcho (I) • ./ns scripts/run.tcl -x 1200 -y 800 -stop 20 -tr TRACES/out.tr -mg AdhocEcho/sna_1 -sc movement_scenarios/scen-1200x800-30-500-10-1 -nn 30 -rp AdhocEcho • -mg 指定了本程式的劇本為AdhocEcho/sna_1, • -sc 指定了節點的移動路徑設定檔file 為movement_scenarios/scen-1200x800-30-500-10-1。 • -nn 指定了模擬實驗中的節點總數為50, • -rp 則指定模擬的protocol 為adhocEcho(根據這個敘述,ns2將尋找並載入adhocEcho/adhocEcho.tcl .
STEP 3. 建立簡單TCL script 來測試AgentEcho (II) – 4個重要的scripts • 1: srcipts/run.tcl: 用來建立adhoc nodes的設定檔, • 此設定檔將自動建立 -nn 個節點. • 此檔案無須修改,並在 srcipts 子目錄下面可以找到. • 2: AdHocEcho.tcl: 用來描述建立一個adhoc node較底層的設定, • 此檔案較為難懂,建議copy我的file,並稍加修改其內容即可(下面介紹要修改的部份), • 注意此file名稱必須與資料夾名稱相同.
STEP 3. 建立簡單TCL script 來測試AgentEcho (III) – 4個重要的script • 3: scen-1200x800-30-500-10-1: adhoc nodes 移動的路徑設定, • 用setdest的程式來產生 • 4: sna_1: 實驗的劇本設定.用來指定實驗節點的互動方式. • 由於大部分的運作邏輯利用c++ 實現在 AdEchoAgent的邏輯之中,所以此劇本大致上只是進行簡單的設定,起動與結束的動作.
STEP 3. 建立簡單TCL script 來測試AgentEcho (IV) • 在AdHocEcho.tcl中,所需修改的程式部份為 create-client的副程式 ODMRPNode instproc create-client{}{ $self instvar dmux_ mcast_dmux_ global RouterTrace AgentTrace opt #set s_agent [new Agent/IRODV1] set s_agent [new Agent/ADECHO] // 只需改這裡,改成我們的agent set id_ [$selfid] set port $opt(uni_data_port) $s_agent myaddr $id_ $s_agent myport $port … return$s_agent }
STEP 3. 建立簡單TCL script 來測試AgentEcho (V) • sna_1 的內容: 節點之間的互動 for {set i 0} {$i < $opt(nn)} {incr i} { set ag_($i) [$node_($i) create-client] // 呼叫我們剛剛修改的副程式,將agent 架構在node 上 $ns_ at 2.000 "$ag_($i) ShowName" // 要求 ns 在 2 sec 時,對每一個agent 下 ShowName的指令 } 試試看. 看一下效果如何.
補充: setdest 的用法 • 用 setdest 產生random walk 的移動 • 在compile 時,會自動compile 出setdest 這個utility • Setdest 的參數 • usage: ./setdest • -n <nodes> : 要移動的節點數 • -p <pause time> : 移動間的休息時間 • -s <max speed> : 移動速度 m/s • -t <simulation time> : 模擬時間 • -x <max X> -y <max Y> : 模擬範圍 X, Y
Ns2 一個常用的網路模擬器 Step4. 加入傳送與接收封包的功能
STEP 4. request/response 的能力 • 目標新功能 • EchoAgent 可以接受來自ns 的 send指令. • 在收到send 指令之後, Echo Agent 將廣播一個Echo封包給其鄰居, • 所有收到Echo封包的人將回送一個reply 封包.
目標分析 • 上面的需求可以分成: • 在command 副函式中加入send指令的描述, 當Ns2 執行 send 指令時, echo_send 的副函式將被執行. • 實現echo_send 的副函式,其內容為廣播一個echo-request 封包 • 改寫 recv 函式, 當確認收到echo 封包時, 呼叫 echo_recv 函式來回應 • 實現echo_recv 的副函式,其內容為當收到echo-request 時, 送出一個echo-reply 封包, 當收到echo-reply時,列印相關訊息
傳送Request (Send 的能力) • 我們在command 副函式中,加入send 指令的描述 • AgentECHO::command 副函式的內容將改成: int AgentECHO::command(int argc, const char*const* argv) // 程式九 { Tcl& tcl = Tcl::instance(); if (argc == 2) { if (strcmp(argv[1], "send") == 0) { echo_send(); return (TCL_OK); } ….. } }
傳送Request (Send 的能力) (II) • 當echo_send 被呼叫時,agent 將準備一個echo-request 的封包,廣播給所有的鄰居。 void AgentECHO::echo_send() // 程式十 Packet *pkt = allocpkt(); // Create New Packet hdr_cmn *ch = hdr_cmn::access(pkt); hdr_ip *iph=hdr_ip::access(pkt); hdr_ahe *aheh=hdr_ahe::access(pkt); iph->saddr()=my_addr; iph->sport()=data_port; iph->daddr()=IP_BROADCAST; iph->dport()=data_port; ch->ptype()=PT_AECHO; aheh->Type=0; // Request Packet aheh->FromNode=my_addr; aheh->FromTime=Scheduler::instance().clock(); target_->recv(pkt, (Handler*)0); } IP Information Fill AdHocEcho’s Header Send Packet.
接收封包 (Recv 的能力) (II) • 當一個agent收到封包時,該封包將會被送到recv副函式 。 • 為了簡化recv的內容,我們多半只在recv中作分類的動作,然後就將不同的封包交給不同的副函式去處理。 void AgentECHO::recv(Packet* pkt, Handler *){// 程式 11 hdr_cmn *ch = hdr_cmn::access(pkt); if(ch->ptype()==PT_AECHO){ // 如果是AdHocEcho 封包,就交給echo_recv() echo_recv(pkt); } Packet::free(pkt); }
void AgentECHO::echo_recv(Packet* pkt) // 程式 12 { hdr_ip *iph=hdr_ip::access(pkt); hdr_ahe *aheh=hdr_ahe::access(pkt); if(!aheh->Type){ // Recv Request Packet Packet *npkt = allocpkt(); // 產生Reply用的封包 hdr_ip *niph=hdr_ip::access(npkt); hdr_ahe *naheh=hdr_ahe::access(npkt); hdr_cmn *nch = hdr_cmn::access(npkt); niph->saddr()=my_addr; niph->sport()=data_port; niph->daddr()=iph->saddr(); niph->dport()=data_port; naheh->Type=1; // 設定為Reply用的封包 naheh->FromNode=aheh->FromNode; // 填入訊息 naheh->FromTime=aheh->FromTime; naheh->ReplyNode=my_addr; naheh->ReplyTime=Scheduler::instance().clock(); target_->recv(npkt, (Handler*)0); }else{ // 列印訊息 } } echo_recv詳細內容
試試看: Send/Request 的功能 • 我們重新make程式,並在sna_1 的最後加入: • $ns_ at 12.0001 "$ag_(20) send" • 執行實驗指令
Ns2 一個常用的網路模擬器 偵測 Time-out 的能力
STEP 5. 處理Time-out的能力 • 所謂的Timeout,就是說在一定的時間之內,某一個agent沒有收到該有的回應,因此該agent必須作一些動作來彌補這個意外。 • 如何知道,已經timeout ? • 透過”鬧鐘”class 來達成
想像的劇本 • 我們要模擬的狀況: • A送出一個requeste給B,而期望在1 sec 內收到B的回應,若無回應,則認為已經time-out。 • 則我們在NS2中要作的是,就是當A送出一個封包時,順便啟動一個會在1sec之後觸發的鬧鐘, • 若在1sec內收到回應,則在收到的瞬間,關掉鬧鐘。 • 否則在1sec 結束後,鬧鐘將會觸發,A也將認為本次的連線是以timeout的情形結束。
目標分析 • 上面的需求可以分成: • 創造一個”鬧鐘”的物件。 • 當agent 送出request封包時,也馬上設定/啟動鬧鐘 • 當收到回應封包時,便嘗試著關鬧鐘 • 一但鬧鐘響,便表示timeout已經發生
創造一個”鬧鐘”的物件 • 我們必須修改AdhocEcho.h,不僅是定義”鬧鐘”的class,並且要建立鬧鐘與我們的agent的互動。我們將我們鬧鐘物件稱為Echo_Timeout,
創造一個”鬧鐘”的物件(I) • AdhocEcho.h,定義”鬧鐘”class -- Echo_Timeout • 並且要建立鬧鐘與我們的agent的互動。 // 程式13 的上半部 class Echo_Timeout; // ”鬧鐘”class 的宣告 class AgentECHO : public Agent { friend class Echo_Timeout; // 設為friend class 可呼叫private method public: AgentECHO(); virtual void recv(Packet *, Handler *); void Recv_callback(Event* e); protected: virtual int command(int argc, const char*const* argv); ….. }
創造一個”鬧鐘”的物件(II) // 程式13 的下半部 private: int my_addr; int data_port; …… Echo_Timeout* EchoT; // agent 內部宣告一個時鐘 void echo_p2p_send(int dest); // 測試 time-out 的函式 Event *p2pSendEvent; // 為了取消鬧鐘設定的變數 void Recv_callback(Event *); // 與鬧鐘互動的函式 }; class Echo_Timeout : public Handler { // 鬧鐘class 的完整內容 public: Echo_Timeout(AgentECHO *a_) { a = a_; } // 鬧鐘觸發時會執行 handle 副函式 // handle 副函式會執行agent中的Recv_callback副函式 virtual void handle(Event *e) { a->Recv_callback(e); } private: AgentECHO *a; }; #endif // ns_ns_irreq_h
AdHocEcho Agent 的Time-out處理 • 為了創造EchoT的object(鬧鐘),我們在AgentEcho 的建構子中,加入了兩行敘述 AgentECHO::AgentECHO() : Agent(PT_AECHO) // 程式 14 { EchoT= new Echo_Timeout(this); p2pSendEvent=0; }