天天看點

NS-3入門

什麼是NS-3?

離散事件驅動網絡模拟器。看看官方的定義:(from http://www.nsnam.org/)

ns-3 is a discrete-event network simulator for Internet systems, targeted primarily for research and educational use. ns-3 is free software, licensed under the GNU GPLv2 license, and is publicly available for research, development, and use.

ns-3 is intended as an eventual replacement for the popular ns-2 simulator. The project acronym “nsnam” derives historically from the concatenation of ns (network simulator) and nam (network animator).

NS-3 vs NS-2

NS-3雖然冠以一個“3”,但事實上跟它廣泛流行的前任NS-2并非一脈相承,或者從使用角度上說,僅僅繼承了一個名稱而已。NS-3基本上是一個新的模拟器,不支援NS-2的API。NS-3是完全用C++編寫的(也有可選的Python接口),而NS-2一部分子產品使用C++而另一部分使用OTcl。因而NS-3最大的特點就是腳本可以C++或Python語言,而在NS-2中,我們使用的是OTcl。

NS-3的功能仍舊在開發中,是以它遠沒有NS-2完善(當然NS-2的維護也在進行中)。NS-3并不包含目前所有NS-2的功能,但它具有某些新的特性:正确的多網卡處理、IP尋址政策的使用、更詳細的802.11子產品等等。

(出于最後的這句話,我們這次作業大膽地采用了NS-3進行仿真——此是後話。)

Latest stable release: ns-3.2.1 (November 20, 2008)

結構:

據說NS-3的架構看起來比NS-2清晰得多,從NS-3 Tutorial看起來确實是這樣。NS-3中把網絡構件分為四類:

  ·Node:終端節點,能夠添加應用、協定、外部接口等。

  ·NetDevice:網卡及其驅動,有各種不同類型的網卡:CsmaNetDevice、PointToPointNetDevice、WifiNetDevice。

  ·Channel:通道,有各種不同類型的媒體通道:CsmaChannel、PointToPointChannel、WifiChannel。

  ·Application:應用程式,包括UdpEchoClientApplication、UdpServerApplication等。

此外,NS-3中提供了一類稱為Topology Helper的子產品,對應每種拓撲連接配接有不同的Helper(例如CsmaNetHelper等),使用這些類來模拟現實中的安裝網卡、連接配接、配置鍊路等過程,來簡化工作。

NS-3對我來說也是一個小火星環境,是以也有許多火星文需要學習:

【名詞解釋】

POSIX:Portable Operating System Interface

一組作業系統API的協定/标準族,最開始為了Unix系統上的可移植性而開發的,也适用于其他作業系統。

Doxygen:Documentation Generator

支援C++、C、Java、Objective-C、Python、IDL、Fortran、VHDL、PHP、C#等各種語言的文檔生成器,用于從源代碼中生成說明文檔。(類似于我之前使用過的Sandcastle,貌似更加強大些,有必要得學習一下。)

nam:Network Animator

基于Tcl/TK的網絡動畫示範工具,能提供拓撲和包級别的動畫以及資料流觀察。(參考http://www.isi.edu/nsnam/nam/)

Mercurial

NS-3代碼維護使用的源碼版本控制管理系統

Waf

NS-3項目使用的新一代的基于Python的建構系統(Build System)

WireShark

一種GUI包嗅探器。由于NS-3能生成.pcap檔案,是以可以使用類似于WireShark的軟體對資料進行分析

tcpdump

另一種包嗅探器。在Linux下使用CLI進行資料分析

╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬

一、環境支援

如上文(NS-3入門[1]概念引入)所述,編譯/運作NS-3腳本需要保證Linux環境的設定(gcc、waf、tcpdump等),詳細的必要軟體包安裝過程參見http://www.nsnam.org/wiki/index.php/Installation

二、NS-3C++腳本的編寫

如前所述,NS-3的腳本使用C++語言(也支援python),使用四種類型的網絡構件(Node、NetDevice、Channel、Application)。一個簡單的腳本一般有以下步驟:

1、建立節點Node(使用類NodeContainer::Create()方法)

2、使用鍊路Helper類來幫助設定鍊路(包括PointToPointHelper、CsmaHelper、WifiHelper等類型)。Helper類雖然不屬于上述四類的網絡構件,但它卻極大地友善了拓撲的搭建,它可以幫助我們處理實際中諸如在兩個終端安裝網卡、連網線、Modern、配置上網方式、鍊路屬性等底層工作,簡化了仿真過程,使我們可以更專注于仿真的目的

3、安裝IP協定棧(使用類InternetStackHelper::Install()方法)

4、設定IP位址(使用類Ipv4AddressHelper::SetBase()/Assign()方法)

5、在節點Node上安裝應用程式(目前支援UdpServerServer、UdpEchoClient、PacketSink等)

6、設定仿真時間、啟動仿真

===================================

一個簡單的腳本(來自NS-3 Tutorial)及其解釋

=========================================================================

#include "ns3/core-module.h"

#include "ns3/simulator-module.h

#include "ns3/node-module.h"

#include "ns3/helper-module.h"

using namespace ns3;

NS_LOG_COMPONENT_DEFINE ("Example");   //定義名稱為“Example”的日志子產品

int

main (int argc, char *argv[])

{

   //以下兩個語句啟用UdpEcho應用程式的日志記錄,其級别為LOG_LEVEL_INFO。關于NS-3的日志系統将在後續篇章進行介紹。

  LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);

  LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO);

  NodeContainer nodes;   //1、建立兩個節點

  nodes.Create (2);  

  PointToPointHelper pointToPoint;  //2、建立P2P類型的Helper

  pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));   //使用Helper設定鍊路屬性

  pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));

  NetDeviceContainer devices;

  devices = pointToPoint.Install (nodes);  //使用Helper将網卡安裝到節點

  InternetStackHelper stack;  //3、安裝IP協定棧

  stack.Install (nodes);

  Ipv4AddressHelper address;  //4、配置設定IP位址

  address.SetBase ("10.1.1.0", "255.255.255.0");

  Ipv4InterfaceContainer interfaces = address.Assign (devices);  //配置設定到網卡

  UdpEchoServerHelper echoServer (9);   //5.1、安裝UdpServer應用服務,9表示服務端口

  ApplicationContainer serverApps = echoServer.Install (nodes.Get (1));

  serverApps.Start (Seconds (1.0));

  serverApps.Stop (Seconds (10.0));

  serverApps.Start (Seconds (1.0));   //6.1、Server啟動時間

  serverApps.Stop (Seconds (10.0));

  UdpEchoClientHelper echoClient (interfaces.GetAddress (1), 9);   //5.2、安裝UdpClient應用服務,需要指明伺服器IP以及服務端口

  echoClient.SetAttribute ("MaxPackets", UintegerValue (1));

  echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.)));

  echoClient.SetAttribute ("PacketSize", UintegerValue (1024));

  ApplicationContainer clientApps = echoClient.Install (nodes.Get (0));

  clientApps.Start (Seconds (2.0));   //6.2、Client啟動時間

  clientApps.Stop (Seconds (10.0));

  Simulator::Run ();   //6.3、啟動仿真

  Simulator::Destroy ();

  return 0;

}

三、編譯與運作

當我們裝好NS-3的運作環境之後,在NS-3的程式目錄下會有一個scratch目錄,其性質類似于VC/VC++環境下的Debug目錄。

将上述腳本檔案儲存為example.cc,複制到scratch下面,然後在NS-3目錄下使用指令waf完成編譯,然後運作。例如:

      $~/NS-3.2.1 > ./waf

      $~/NS-3.2.1 > ./waf --run scratch/example

可以看到程式輸出:

    Entering directory ‘~/NS-3.2.1/build’

    Compilation finished successfully

    Sent 1024 bytes to 10.1.1.2

    Received 1024 bytes from 10.1.1.1

    Received 1024 bytes from 10.1.1.2

╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬═╬

NS-3日志子系統的提供了各種檢視仿真結果的管道:

一、使用Logging Module

0、【預備知識】日志級别及其對應的宏

NS-3提供了若幹個日志級别來滿足不同的Debug需求,每一級的日志内容都涵蓋了低一級的内容。這些級别對應的宏從低到高排列為:

  *NS_LOG_ERROR — Log error messages;

  *NS_LOG_WARN — Log warning messages;

  *NS_LOG_DEBUG — Log relatively rare, ad-hoc debugging messages;

  *NS_LOG_INFO — Log informational messages about program progress;

  *NS_LOG_FUNCTION — Log a message describing each function called;

  *NS_LOG_LOGIC — Log messages describing logical flow within a function;

  *NS_LOG_ALL — Log everything.

  *NS_LOG_UNCOND — 無條件輸出

方式1、通過設定shell環境變量NS_LOG使用日志系統

 1.1)首先,定義好一個日志子產品:

  可以在腳本中使用宏NS_LOG_COMPONENT_DEFINE(name)定義一個日志子產品。(注意,為了使用宏NS_LOG(name, level)來輸出這個子產品所定義的内容,這個定義語句必須寫在每個腳本檔案的開始。宏NS_LOG将在方式2中進行介紹。)

  也有一些日志子產品是内置的,比如上文的名為“UdpEchoClientApplication”“UdpEchoServerApplication”的子產品就是UdpEcho應用程式内置的日志子產品,隻要使用了相應的類,就可以啟用相應的日志子產品。

 1.2)在shell中通過設定環境變量NS_LOG,來控制仿真輸出級别:

  $~/ns-3.2.1 > export NS_LOG = '<日志子產品名稱> =level_all | prefix_func | prefix_time'

   *level_all表示啟用所有級别(=error | warn | debug | info | function | logic)

   *prefix_func表示記錄輸出該消息的函數

   *prefix_time表示加上時間字首

  $~/ns-3.2.1 > export NS_LOG = '<日志子產品名稱1>=level_all : <日志子產品名稱2>=info'

   *符号:隔開兩個不同的日志子產品

  $~/ns-3.2.1 > export NS_LOG = * = level_all

   *符号*作為通配符。上行指令表示啟用所有可用子產品的所有日志級别。

   *這一般會形成大量的資料,此時可以使用shell的輸出重定向儲存日志到檔案裡面:

    $~/ns-3.2.1 > ./waf --run scratch/example >& log.out

方式2、通過在腳本裡使用宏NS_LOG調用日志子產品

 2.0)宏NS_LOG(level, msg)用于定義對應level的輸出内容;為了友善使用,系統預定義了各個級别的NS_LOG宏NS_LOG_ERROR等(參見【預備知識】):

  #define NS_LOG_ERROR(msg)   NS_LOG(ns3::LOG_ERROR, msg)

 2.1)如上文,在腳本裡使用宏NS_LOG_COMPONENT_DEFINE(name)定義一個日志子產品;

 2.2)使用宏LogComponentEnable(name, level)啟用日志(對應地,有宏LogComponentDisable(name, level)用于禁用日志);                                                                                                                                                 

 2.3)使用【預備知識】裡定義的各種級别的宏輸出内容,注意程式隻會輸出低于等于已經啟用的level的宏内容。

  NS_LOG_COMPONENT_DEFINE("Example");

  LogComponentEnable("Example", LOG_LEVEL_INFO);   //等價于shell中:export NS_LOG = 'Example=info'

  NS_LOG_WARN("Message:level_warn");

  NS_LOG_INFO("Message:level_info");

  NS_LOG_LOGIC("Message:level_logic");

   //由于我們啟用的日志level是INFO,是以編譯運作後,程式會輸出低于和等于INFO級别的内容,而高于INFO級别的宏内容不會被輸出

   //即,Message:level_warn和Message:level_info會被輸出,而Message:level_logic不會被輸出

===============================================================================================================

二、使用Command Line參數

仿真一般是為了收集各種不同條件下的資料,常常需要改變一些變量。NS-3提供了Command Line參數接口,可以在運作時對腳本中的變量進行設定,免去了每次更改變量後要重新編譯的麻煩。(相當于在運作前進行變量的scanf/cin操作,但因為有預設值,CLI更靈活一些。)

1、在腳本中添加語句

int main (int argc, char *argv[])

{

  ...

  CommandLine cmd;

  cmd.Parse (argc, argv);  //将指令行輸入的參數作為類CommandLine的參數進行分析

  ...

}

  這樣可以在shell中使用某些附加參數如PrintHelp:

   $~/ns-3.2.1 > ./waf --run "scratch/example --PrintHelp"

  這條指令将會列出example目前可用的指令參數:

   Entering directory '/home/craigdo/repos/ns-3-dev/build'

   Compilation finished successfully

   --PrintHelp: Print this help message.

   --PrintGroups: Print the list of groups.

   --PrintTypeIds: Print all TypeIds.

   --PrintGroup=[group]: Print all TypeIds of group.

   --PrintAttributes=[typeid]: Print all attributes of typeid.

   --PrintGlobals: Print the list of globals.

  從輸出中(倒數第二行)我們知道可以列印某些類的屬性:

   $~/ns-3.2.1 > ./waf --run "scratch/example --PrintAttributes=ns3::PointToPointNetDevice"

  這條指令将會列出類型為PointToPointNetDevice的裝置的屬性:

   --ns3::PointToPointNetDevice::DataRate=[32768bps]:

   The default data rate for point to point links

  知道了屬性名稱,我們也可以使用指令更改這個屬性:

   $~/ns-3.2.1 > ./waf --run "scratch/example --ns3::PointToPointNetDevice::DataRate=5Mbps"

2、使用CommandLine::AddValue添加自己的變量,使之成為CommandLine可以使用的參數

   CommandLine cmd;

   cmd.AddValue("nPackets", "Number of packets to echo", nPackets);   //(屬性名稱,屬性說明,變量)

   cmd.Parse(argc, argv);

  這樣在shell中我們可以在指令中更改這個屬性:

   $~/ns-3.2.1 > ./waf --run "scratch/example --nPackets=2"

===============================================================================================================

三、使用Tracing System

1、啟用ASCII Tracing

  NS-3提供了類似NS-2的日志輸出(*.tr檔案),記錄系統中的動作。在Simulator::Run()之前添加語句:

   #include <fstream>

   ...

   std::ofstream ascii;

   ascii.open ("example.tr");

   PointToPointHelper::EnableAsciiAll (ascii);

  則運作後我們可以在example.tr檔案中看到系統的日志(使用ASCII文本閱讀器即可),其中每一行都是以+/-/d/r開頭的:

   +: An enqueue operation occurred on the device queue;

   -: A dequeue operation occurred on the device queue;

   d: A packet was dropped, typically because the queue was full;

   r: A packet was received by the net device.

  例如我們可以看到檔案中的第一行(為了說明友善,這裡分段編号顯示),顯示了一個入隊操作:

   00 +

   01 2

   02 /NodeList/0/DeviceList/0/$ns3::PointToPointNetDevice/TxQueue/Enqueue

   03 ns3::PppHeader (

   04  Point-to-Point Protocol: IP (0x0021))

   05  ns3::Ipv4Header (

   06   tos 0x0 ttl 64 id 0 offset 0 flags [none]

   07   length: 1052 10.1.1.1 > 10.1.1.2)

   08   ns3::UdpHeader (

   09    length: 1032 49153 > 9)

   10    Payload (size=1024)

  其中編号為02的部分顯示了發生操作的路徑:根/NodeList是NS-3維護的所有節點清單,是以/NodeList/0表示編号為0的節點;随後的/DeviceList/0表示在該節點上的編号為0的NetDivece(比如網卡);接下來的$ns3::PointToPointNetDevice指明了該NetDivece的類型;最後的TxQueue/Enqueue表示在傳送隊列上發生了入隊操作,也就是行開頭的+所表現的意義。

2、啟用PCAP Tracing

  NS-3也可以生成*.pcap檔案,進而可以使用諸如Wireshark、tcpdump(前文NS-3入門[1]概念引入介紹過)等工具進行分析。

 2.1)在腳本Simulator::Run()之前添加語句:

   PointToPointHelper::EnablePcapAll ("example");

  這個語句将會産生若幹*.pcap檔案,命名為example-<Node編号>-<NetDevice編号>.pcap,分别記錄每個裝置的日志。也可以使用語句***Helper::EnablePcap (filename, NodeId, DeviceId)來隻産生特定裝置的pcap檔案:

   PointToPointHelper::EnablePcap ("example", p2pNodes.Get (0)->GetId (), 0);  //隻産生example-0-0.pcap檔案

 2.2)使用tcpdump在指令行閱讀pcap檔案:

   ~/ns-3.2.1 > tcpdump -r example-0-0.pcap -nn -tt

   reading from file second-0-0.pcap, link-type PPP (PPP)

   2.000000 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024

   2.007382 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024

 2.3)使用Wireshark等軟體打開pcap檔案。

=======End===================================================================

轉載連結:http://www.cnblogs.com/dabbei/archive/2013/07/18/3198552.html