8、ns-3可視化工具


v Pyiz

在ns-3中集合到Visualizer。只要在程序中加入:

CommandLine cmd;

cmd.Parse (argc,argv);

並且在運行是加入參數-vis。它不需要trace文件

運行第三個示例./waf --run third --vis

clip_image002

紅色為無線網絡,綠色為通信狀態。

clip_image004

v NetAnim

NetAnim是基於Qt4的離線動畫演示工具。,主要是利用XML格式的trace文件,仿真后NetAnim讀取該文件顯示網絡拓撲和節點數據分組等動畫過程。Ns-3中的ns3::AnimationInterface類負責生存XML跟蹤文件。在仿真開始前,AnimationInterface注冊為tx和rx(發送數據和接受數據)事件的追蹤hook,當發送和接受數據分組是,在AnimationInterface能感知到正在流動的數據流的2個端點,然后添加該信息到XML格式的追蹤文件。

使用NetAnim時分兩步:

第一步、生成XML記錄文件。

① 確保程序的wscipt文件包含netanim模塊,src/netanim/examples/wsctipt是關於wscript文件的例子。

② 包含頭文件:#include”ns3/netanim-module.h”

③ 添加語句

AnimationInterface::SetConstantPosition (p2pNodes.Get (1), 10, 30); //位置

AnimationInterface::SetNodeDescription (wifiApNode, "AP"); // Optional名字

AnimationInterface::SetNodeColor (csmaNodes, 0, 0, 255); // Optional節點顏色

AnimationInterface::SetBoundary (0, 0, 35, 35); // Optional范圍

AnimationInterface anim ("wireless-animation.xml"); // Mandatory名字

anim.EnablePacketMetadata (true); // Optional

anim.EnableIpv4RouteTracking ("routingtable-wireless.xml", Seconds (0), Seconds (5), Seconds (0.25)); //Optional

具體例子可以看自帶的/ns-allinone-3.19/ns-3.19/src/netanim/examples/wireless-animation.cc

第二步、使用NetAnim裝載XML記錄文件

在終端./NetAnim,然后左上角File open按鈕,選擇XML文件,單擊播放按鈕開始動畫。

具體截圖如下:

clip_image006

clip_image008

clip_image010

clip_image012

XML文件有:

a. <anim> XML根元素

b. <topology>畫布坐標X、Y的最大和最小值

c. <node>描述每個節點的ID、x、y坐標位置及顏色

d. <link>描述節點間的鏈路

e. <packet>描述包在無線網絡中傳輸。

f. <rx>節點收到的數據包

g. <wpacket>無線數據分組

v Tcpump

tcpdump [ -AdDeflLnNOpqRStuUvxX ] [ -c count ]

[ -C file_size ] [ -F file ]

[ -i interface ] [ -m module ] [ -M secret ]

[ -r file ] [ -s snaplen ] [ -T type ] [ -w file ]

[ -W filecount ]

[ -E spi@ipaddr algo:secret,... ]

[ -y datalinktype ] [ -Z user ]

[ expression ]

-A 以ASCII碼方式顯示每一個數據包(不會顯示數據包中鏈路層頭部信息). 在抓取包含網頁數據的數據包時, 可方便查看數據(nt: 即Handy for capturing web pages).

-c count

tcpdump將在接受到count個數據包后退出.

-C file-size (nt: 此選項用於配合-w file 選項使用)

該選項使得tcpdump 在把原始數據包直接保存到文件中之前, 檢查此文件大小是否超過file-size. 如果超過了, 將關閉此文件,另創一個文件繼續用於原始數據包的記錄. 新創建的文件名與-w 選項指定的文件名一致, 但文件名后多了一個數字.該數字會從1開始隨着新創建文件的增多而增加. file-size的單位是百萬字節(nt: 這里指1,000,000個字節,並非1,048,576個字節, 后者是以1024字節為1k, 1024k字節為1M計算所得, 即1M=1024 * 1024 = 1,048,576)

-d 以容易閱讀的形式,在標准輸出上打印出編排過的包匹配碼, 隨后tcpdump停止.(nt | rt: human readable, 容易閱讀的,通常是指以ascii碼來打印一些信息. compiled, 編排過的. packet-matching code, 包匹配碼,含義未知, 需補充)

-dd 以C語言的形式打印出包匹配碼.

-ddd 以十進制數的形式打印出包匹配碼(會在包匹配碼之前有一個附加的'count'前綴).

-D 打印系統中所有tcpdump可以在其上進行抓包的網絡接口. 每一個接口會打印出數字編號, 相應的接口名字, 以及可能的一個網絡接口描述. 其中網絡接口名字和數字編號可以用在tcpdump 的-i flag 選項(nt: 把名字或數字代替flag), 來指定要在其上抓包的網絡接口.

此選項在不支持接口列表命令的系統上很有用(nt: 比如, Windows 系統, 或缺乏 ifconfig -a 的UNIX系統); 接口的數字編號在windows 2000 或其后的系統中很有用, 因為這些系統上的接口名字比較復雜, 而不易使用.

如果tcpdump編譯時所依賴的libpcap庫太老,-D 選項不會被支持, 因為其中缺乏 pcap_findalldevs()函數.

-e 每行的打印輸出中將包括數據包的數據鏈路層頭部信息

-E spi@ipaddr algo:secret,...

可通過spi@ipaddr algo:secret 來解密IPsec ESP包(nt | rt:IPsec Encapsulating Security Payload,IPsec 封裝安全負載, IPsec可理解為, 一整套對ip數據包的加密協議, ESP 為整個IP 數據包或其中上層協議部分被加密后的數據,前者的工作模式稱為隧道模式; 后者的工作模式稱為傳輸模式 . 工作原理, 另需補充).

需要注意的是, 在終端啟動tcpdump 時, 可以為IPv4 ESP packets 設置密鑰(secret).

可用於加密的算法包括des-cbc, 3des-cbc, blowfish-cbc, rc3-cbc, cast128-cbc, 或者沒有(none).默認的是des-cbc(nt: des, Data Encryption Standard, 數據加密標准, 加密算法未知, 另需補充).secret 為用於ESP 的密鑰, 使用ASCII 字符串方式表達. 如果以 0x 開頭, 該密鑰將以16進制方式讀入.

該選項中ESP 的定義遵循RFC2406, 而不是 RFC1827. 並且, 此選項只是用來調試的, 不推薦以真實密鑰(secret)來使用該選項, 因為這樣不安全: 在命令行中輸入的secret 可以被其他人通過ps 等命令查看到.

除了以上的語法格式(nt: 指spi@ipaddr algo:secret), 還可以在后面添加一個語法輸入文件名字供tcpdump 使用(nt:即把spi@ipaddr algo:secret,... 中...換成一個語法文件名). 此文件在接受到第一個ESP 包時會打開此文件, 所以最好此時把賦予tcpdump 的一些特權取消(nt: 可理解為, 這樣防范之后, 當該文件為惡意編寫時,不至於造成過大損害).

-f 顯示外部的IPv4 地址時(nt: foreign IPv4 addresses, 可理解為, 非本機ip地址), 采用數字方式而不是名字.(此選項是用來對付Sun公司的NIS服務器的缺陷(nt: NIS, 網絡信息服務, tcpdump 顯示外部地址的名字時會用到她提供的名稱服務): 此NIS服務器在查詢非本地地址名字時,常常會陷入無盡的查詢循環).

由於對外部(foreign)IPv4地址的測試需要用到本地網絡接口(nt: tcpdump 抓包時用到的接口)及其IPv4 地址和網絡掩碼. 如果此地址或網絡掩碼不可用, 或者此接口根本就沒有設置相應網絡地址和網絡掩碼(nt: linux 下的 'any' 網絡接口就不需要設置地址和掩碼, 不過此'any'接口可以收到系統中所有接口的數據包), 該選項不能正常工作.

-F file

使用file 文件作為過濾條件表達式的輸入, 此時命令行上的輸入將被忽略.

-i interface

指定tcpdump 需要監聽的接口. 如果沒有指定, tcpdump 會從系統接口列表中搜尋編號最小的已配置好的接口(不包括 loopback 接口).一但找到第一個符合條件的接口, 搜尋馬上結束.

在采用2.2版本或之后版本內核的Linux 操作系統上, 'any' 這個虛擬網絡接口可被用來接收所有網絡接口上的數據包(nt: 這會包括目的是該網絡接口的, 也包括目的不是該網絡接口的). 需要注意的是如果真實網絡接口不能工作在'混雜'模式(promiscuous)下,則無法在'any'這個虛擬的網絡接口上抓取其數據包.

如果 -D 標志被指定, tcpdump會打印系統中的接口編號,而該編號就可用於此處的interface 參數.

-l 對標准輸出進行行緩沖(nt: 使標准輸出設備遇到一個換行符就馬上把這行的內容打印出來).在需要同時觀察抓包打印以及保存抓包記錄的時候很有用. 比如, 可通過以下命令組合來達到此目的:

``tcpdump -l | tee dat'' 或者 ``tcpdump -l > dat & tail -f dat''.(nt: 前者使用tee來把tcpdump 的輸出同時放到文件dat和標准輸出中, 而后者通過重定向操作'>', 把tcpdump的輸出放到dat 文件中, 同時通過tail把dat文件中的內容放到標准輸出中)

-L 列出指定網絡接口所支持的數據鏈路層的類型后退出.(nt: 指定接口通過-i 來指定)

-m module

通過module 指定的file 裝載SMI MIB 模塊(nt: SMI,Structure of Management Information, 管理信息結構MIB, Management Information Base, 管理信息庫. 可理解為, 這兩者用於SNMP(Simple Network Management Protoco)協議數據包的抓取. 具體SNMP 的工作原理未知, 另需補充).

此選項可多次使用, 從而為tcpdump 裝載不同的MIB 模塊.

-M secret 如果TCP 數據包(TCP segments)有TCP-MD5選項(在RFC 2385有相關描述), 則為其摘要的驗證指定一個公共的密鑰secret.

-n 不對地址(比如, 主機地址, 端口號)進行數字表示到名字表示的轉換.

-N 不打印出host 的域名部分. 比如, 如果設置了此選現, tcpdump 將會打印'nic' 而不是 'nic.ddn.mil'.

-O 不啟用進行包匹配時所用的優化代碼. 當懷疑某些bug是由優化代碼引起的, 此選項將很有用.

-p 一般情況下, 把網絡接口設置為非'混雜'模式. 但必須注意 , 在特殊情況下此網絡接口還是會以'混雜'模式來工作; 從而, '-p' 的設與不設, 不能當做以下選現的代名詞:'ether host {local-hw-add}' 或 'ether broadcast'(nt: 前者表示只匹配以太網地址為host 的包, 后者表示匹配以太網地址為廣播地址的數據包).

-q 快速(也許用'安靜'更好?)打印輸出. 即打印很少的協議相關信息, 從而輸出行都比較簡短.

-R 設定tcpdump 對 ESP/AH 數據包的解析按照 RFC1825而不是RFC1829(nt: AH, 認證頭, ESP, 安全負載封裝, 這兩者會用在IP包的安全傳輸機制中). 如果此選項被設置, tcpdump 將不會打印出'禁止中繼'域(nt: relay prevention field). 另外,由於ESP/AH規范中沒有規定ESP/AH數據包必須擁有協議版本號域,所以tcpdump不能從收到的ESP/AH數據包中推導出協議版本號.

-r file

從文件file 中讀取包數據. 如果file 字段為 '-' 符號, 則tcpdump 會從標准輸入中讀取包數據.

-S 打印TCP 數據包的順序號時, 使用絕對的順序號, 而不是相對的順序號.(nt: 相對順序號可理解為, 相對第一個TCP 包順序號的差距,比如, 接受方收到第一個數據包的絕對順序號為232323, 對於后來接收到的第2個,第3個數據包, tcpdump會打印其序列號為1, 2分別表示與第一個數據包的差距為1 和 2. 而如果此時-S 選項被設置, 對於后來接收到的第2個, 第3個數據包會打印出其絕對順序號:232324, 232325).

-s snaplen

設置tcpdump的數據包抓取長度為snaplen, 如果不設置默認將會是68字節(而支持網絡接口分接頭(nt: NIT, 上文已有描述,可搜索'網絡接口分接頭'關鍵字找到那里)的SunOS系列操作系統中默認的也是最小值是96).68字節對於IP, ICMP(nt: Internet Control Message Protocol,因特網控制報文協議), TCP 以及 UDP 協議的報文已足夠, 但對於名稱服務(nt: 可理解為dns, nis等服務), NFS服務相關的數據包會產生包截短. 如果產生包截短這種情況, tcpdump的相應打印輸出行中會出現''[|proto]''的標志(proto 實際會顯示為被截短的數據包的相關協議層次). 需要注意的是, 采用長的抓取長度(nt: snaplen比較大), 會增加包的處理時間, 並且會減少tcpdump 可緩存的數據包的數量, 從而會導致數據包的丟失. 所以, 在能抓取我們想要的包的前提下, 抓取長度越小越好.把snaplen 設置為0 意味着讓tcpdump自動選擇合適的長度來抓取數據包.

-T type

強制tcpdump按type指定的協議所描述的包結構來分析收到的數據包. 目前已知的type 可取的協議為:

aodv (Ad-hoc On-demand Distance Vector protocol, 按需距離向量路由協議, 在Ad hoc(點對點模式)網絡中使用),

cnfp (Cisco NetFlow protocol), rpc(Remote Procedure Call), rtp (Real-Time Applications protocol),

rtcp (Real-Time Applications con-trol protocol), snmp (Simple Network Management Protocol),

tftp (Trivial File Transfer Protocol, 碎文件協議), vat (Visual Audio Tool, 可用於在internet 上進行電

視電話會議的應用層協議), 以及wb (distributed White Board, 可用於網絡會議的應用層協議).

-t 在每行輸出中不打印時間戳

-tt 不對每行輸出的時間進行格式處理(nt: 這種格式一眼可能看不出其含義, 如時間戳打印成1261798315)

-ttt tcpdump 輸出時, 每兩行打印之間會延遲一個段時間(以毫秒為單位)

-tttt 在每行打印的時間戳之前添加日期的打印

-u 打印出未加密的NFS 句柄(nt: handle可理解為NFS 中使用的文件句柄, 這將包括文件夾和文件夾中的文件)

-U 使得當tcpdump在使用-w 選項時, 其文件寫入與包的保存同步.(nt: 即, 當每個數據包被保存時, 它將及時被寫入文件中,而不是等文件的輸出緩沖已滿時才真正寫入此文件)

-U 標志在老版本的libcap庫(nt: tcpdump 所依賴的報文捕獲庫)上不起作用, 因為其中缺乏pcap_cump_flush()函數.

-v 當分析和打印的時候, 產生詳細的輸出. 比如, 包的生存時間, 標識, 總長度以及IP包的一些選項. 這也會打開一些附加的包完整性檢測, 比如對IP或ICMP包頭部的校驗和.

-vv 產生比-v更詳細的輸出. 比如, NFS回應包中的附加域將會被打印, SMB數據包也會被完全解碼.

-vvv 產生比-vv更詳細的輸出. 比如, telent 時所使用的SB, SE 選項將會被打印, 如果telnet同時使用的是圖形界面,

其相應的圖形選項將會以16進制的方式打印出來(nt: telnet 的SB,SE選項含義未知, 另需補充).

-w 把包數據直接寫入文件而不進行分析和打印輸出. 這些包數據可在隨后通過-r 選項來重新讀入並進行分析和打印.

-W filecount

此選項與-C 選項配合使用, 這將限制可打開的文件數目, 並且當文件數據超過這里設置的限制時, 依次循環替代之前的文件, 這相當於一個擁有filecount 個文件的文件緩沖池. 同時, 該選項會使得每個文件名的開頭會出現足夠多並用來占位的0, 這可以方便這些文件被正確的排序.

-x 當分析和打印時, tcpdump 會打印每個包的頭部數據, 同時會以16進制打印出每個包的數據(但不包括連接層的頭部).總共打印的數據大小不會超過整個數據包的大小與snaplen 中的最小值. 必須要注意的是, 如果高層協議數據沒有snaplen 這么長,並且數據鏈路層(比如, Ethernet層)有填充數據, 則這些填充數據也會被打印.(nt: so for link layers that pad, 未能銜接理解和翻譯, 需補充 )

-xx tcpdump 會打印每個包的頭部數據, 同時會以16進制打印出每個包的數據, 其中包括數據鏈路層的頭部.

-X 當分析和打印時, tcpdump 會打印每個包的頭部數據, 同時會以16進制和ASCII碼形式打印出每個包的數據(但不包括連接層的頭部).這對於分析一些新協議的數據包很方便.

-XX 當分析和打印時, tcpdump 會打印每個包的頭部數據, 同時會以16進制和ASCII碼形式打印出每個包的數據, 其中包括數據鏈路層的頭部.這對於分析一些新協議的數據包很方便.

-y datalinktype

設置tcpdump 只捕獲數據鏈路層協議類型是datalinktype的數據包

-Z user

使tcpdump 放棄自己的超級權限(如果以root用戶啟動tcpdump, tcpdump將會有超級用戶權限), 並把當前tcpdump的用戶ID設置為user, 組ID設置為user首要所屬組的ID(nt: tcpdump 此處可理解為tcpdump 運行之后對應的進程)

此選項也可在編譯的時候被設置為默認打開.(nt: 此時user 的取值未知, 需補充)

v Wireshark

這個是圖形界面,容易操作

v 統計模塊status

在ns-3 Manual 11.7節中細講

框架核心和2中基本的數據收集器:計數器、最小/最大/平均/總觀察員,純文本輸出為omnetpp格式,數據庫輸出使用sqlite3.

例子在examples/stats/wifi-example-sim.cc中找到。

/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */

/*

* This program is free software; you can redistribute it and/or modify

* it under the terms of the GNU General Public License version 2 as

* published by the Free Software Foundation;

*

* This program is distributed in the hope that it will be useful,

* but WITHOUT ANY WARRANTY; without even the implied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

* GNU General Public License for more details.

*

* You should have received a copy of the GNU General Public License

* along with this program; if not, write to the Free Software

* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

*

* Authors: Joe Kopena <tjkopena@cs.drexel.edu>

*

* This program conducts a simple experiment: It places two nodes at a

* parameterized distance apart. One node generates packets and the

* other node receives. The stat framework collects data on packet

* loss. Outside of this program, a control script uses that data to

* produce graphs presenting performance at the varying distances.

* This isn't a typical simulation but is a common "experiment"

* performed in real life and serves as an accessible exemplar for the

* stat framework. It also gives some intuition on the behavior and

* basic reasonability of the NS-3 WiFi models.

*

* Applications used by this program are in test02-apps.h and

* test02-apps.cc, which should be in the same place as this file.

*

*/

#include <ctime>

#include <sstream>

#include "ns3/core-module.h"

#include "ns3/network-module.h"

#include "ns3/mobility-module.h"

#include "ns3/wifi-module.h"

#include "ns3/internet-module.h"

#include "ns3/stats-module.h"

#include "wifi-example-apps.h"

using namespace ns3;

using namespace std;

NS_LOG_COMPONENT_DEFINE ("WiFiDistanceExperiment");

void TxCallback (Ptr<CounterCalculator<uint32_t> > datac,

std::string path, Ptr<const Packet> packet) {

NS_LOG_INFO ("Sent frame counted in " <<

datac->GetKey ());

datac->Update ();

// end TxCallback

}

//----------------------------------------------------------------------

//-- main

//----------------------------------------------

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

double distance = 50.0;

string format ("omnet");

string experiment ("wifi-distance-test");

string strategy ("wifi-default");

string input;

string runID;

{

stringstream sstr;

sstr << "run-" << time (NULL);

runID = sstr.str ();

}

// Set up command line parameters used to control the experiment.

CommandLine cmd;

cmd.AddValue ("distance", "Distance apart to place nodes (in meters).",

distance);

cmd.AddValue ("format", "Format to use for data output.",

format);

cmd.AddValue ("experiment", "Identifier for experiment.",

experiment);

cmd.AddValue ("strategy", "Identifier for strategy.",

strategy);

cmd.AddValue ("run", "Identifier for run.",

runID);

cmd.Parse (argc, argv);

if (format != "omnet" && format != "db") {

NS_LOG_ERROR ("Unknown output format '" << format << "'");

return -1;

}

#ifndef STATS_HAS_SQLITE3

if (format == "db") {

NS_LOG_ERROR ("sqlite support not compiled in.");

return -1;

}

#endif

{

stringstream sstr ("");

sstr << distance;

input = sstr.str ();

}

//------------------------------------------------------------

//-- Create nodes and network stacks創建節點和網絡棧

//--------------------------------------------

NS_LOG_INFO ("Creating nodes.");

NodeContainer nodes;

nodes.Create (2);

NS_LOG_INFO ("Installing WiFi and Internet stack.");

WifiHelper wifi = WifiHelper::Default ();

NqosWifiMacHelper wifiMac = NqosWifiMacHelper::Default ();

wifiMac.SetType ("ns3::AdhocWifiMac");

YansWifiPhyHelper wifiPhy = YansWifiPhyHelper::Default ();

YansWifiChannelHelper wifiChannel = YansWifiChannelHelper::Default ();

wifiPhy.SetChannel (wifiChannel.Create ());

NetDeviceContainer nodeDevices = wifi.Install (wifiPhy, wifiMac, nodes);

InternetStackHelper internet;

internet.Install (nodes);

Ipv4AddressHelper ipAddrs;

ipAddrs.SetBase ("192.168.0.0", "255.255.255.0");

ipAddrs.Assign (nodeDevices);

//------------------------------------------------------------

//-- Setup physical layout使用ns3::MobilityHelper定位節點。在默認情況下,節點有靜態流動性並且不能移動,所以給定距離定位有集中方法可以做到這一點,這里利用ns3::ListPositionAllocator

//--------------------------------------------

NS_LOG_INFO ("Installing static mobility; distance " << distance << " .");

MobilityHelper mobility;

Ptr<ListPositionAllocator> positionAlloc =

CreateObject<ListPositionAllocator>();

positionAlloc->Add (Vector (0.0, 0.0, 0.0));

positionAlloc->Add (Vector (0.0, distance, 0.0));

mobility.SetPositionAllocator (positionAlloc);

mobility.Install (nodes);

//------------------------------------------------------------

//-- Create a custom traffic source and sink安裝流量發生器和流量接收器。

//--------------------------------------------

NS_LOG_INFO ("Create traffic source & sink.");

Ptr<Node> appSource = NodeList::GetNode (0);

Ptr<Sender> sender = CreateObject<Sender>();

appSource->AddApplication (sender);

sender->SetStartTime (Seconds (1));

Ptr<Node> appSink = NodeList::GetNode (1);

Ptr<Receiver> receiver = CreateObject<Receiver>();

appSink->AddApplication (receiver);

receiver->SetStartTime (Seconds (0));

Config::Set ("/NodeList/*/ApplicationList/*/$Sender/Destination",

Ipv4AddressValue ("192.168.0.2"));

//------------------------------------------------------------

//-- Setup stats and data collection統計數據,有四個標簽:實驗、戰略、輸入和運行

//--------------------------------------------

// Create a DataCollector object to hold information about this run.

DataCollector data;

data.DescribeRun (experiment,

strategy,

input,

runID);

// Add any information we wish to record about this run.

data.AddMetadata ("author", "tjkopena");

//計算結果是由ns3::DataCalculator對象創建的,它們附在報告或采樣代碼中,然后隨着ns3::DataCollector注冊,它們將查詢其輸出。一個簡單的觀察方式是使用現有的追蹤源。這里一個計數器是直接鏈接到Wi-Fi MAC層目標節點的一個跟蹤信號。

// Create a counter to track how many frames are generated. Updates

// are triggered by the trace signal generated by the WiFi MAC model

// object. Here we connect the counter to the signal via the simple

// TxCallback() glue function defined above.

Ptr<CounterCalculator<uint32_t> > totalTx =

CreateObject<CounterCalculator<uint32_t> >();

totalTx->SetKey ("wifi-tx-frames");

totalTx->SetContext ("node[0]");

Config::Connect ("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/Mac/MacTx",

MakeBoundCallback (&TxCallback, totalTx));

data.AddDataCalculator (totalTx);

//簡單的創建計數器,記錄接收到的幀數

// This is similar, but creates a counter to track how many frames

// are received. Instead of our own glue function, this uses a

// method of an adapter class to connect a counter directly to the

// trace signal generated by the WiFi MAC.

Ptr<PacketCounterCalculator> totalRx =

CreateObject<PacketCounterCalculator>();

totalRx->SetKey ("wifi-rx-frames");

totalRx->SetContext ("node[1]");

Config::Connect ("/NodeList/1/DeviceList/*/$ns3::WifiNetDevice/Mac/MacRx",

MakeCallback (&PacketCounterCalculator::PacketUpdate,

totalRx));

data.AddDataCalculator (totalRx);

//發送類產生的包數

// This counter tracks how many packets---as opposed to frames---are

// generated. This is connected directly to a trace signal provided

// by our Sender class.

Ptr<PacketCounterCalculator> appTx =

CreateObject<PacketCounterCalculator>();

appTx->SetKey ("sender-tx-packets");

appTx->SetContext ("node[0]");

Config::Connect ("/NodeList/0/ApplicationList/*/$Sender/Tx",

MakeCallback (&PacketCounterCalculator::PacketUpdate,

appTx));

data.AddDataCalculator (appTx);

//接收的包數

// Here a counter for received packets is directly manipulated by

// one of the custom objects in our simulation, the Receiver

// Application. The Receiver object is given a pointer to the

// counter and calls its Update() method whenever a packet arrives.

Ptr<CounterCalculator<> > appRx =

CreateObject<CounterCalculator<> >();

appRx->SetKey ("receiver-rx-packets");

appRx->SetContext ("node[1]");

receiver->SetCounter (appRx);

data.AddDataCalculator (appRx);

/**

* Just to show this is here...

Ptr<MinMaxAvgTotalCalculator<uint32_t> > test =

CreateObject<MinMaxAvgTotalCalculator<uint32_t> >();

test->SetKey("test-dc");

data.AddDataCalculator(test);

test->Update(4);

test->Update(8);

test->Update(24);

test->Update(12);

**/

//記錄各種場景

// This DataCalculator connects directly to the transmit trace

// provided by our Sender Application. It records some basic

// statistics about the sizes of the packets received (min, max,

// avg, total # bytes), although in this scenaro they're fixed.

Ptr<PacketSizeMinMaxAvgTotalCalculator> appTxPkts =

CreateObject<PacketSizeMinMaxAvgTotalCalculator>();

appTxPkts->SetKey ("tx-pkt-size");

appTxPkts->SetContext ("node[0]");

Config::Connect ("/NodeList/0/ApplicationList/*/$Sender/Tx",

MakeCallback

(&PacketSizeMinMaxAvgTotalCalculator::PacketUpdate,

appTxPkts));

data.AddDataCalculator (appTxPkts);

//記錄最小、最大、平均遷移延遲

// Here we directly manipulate another DataCollector tracking min,

// max, total, and average propagation delays. Check out the Sender

// and Receiver classes to see how packets are tagged with

// timestamps to do this.

Ptr<TimeMinMaxAvgTotalCalculator> delayStat =

CreateObject<TimeMinMaxAvgTotalCalculator>();

delayStat->SetKey ("delay");

delayStat->SetContext (".");

receiver->SetDelayTracker (delayStat);

data.AddDataCalculator (delayStat);

//------------------------------------------------------------

//-- Run the simulation

//--------------------------------------------

NS_LOG_INFO ("Run Simulation.");

Simulator::Run ();

//------------------------------------------------------------

//-- Generate statistics output.

//--------------------------------------------

// Pick an output writer based in the requested format.

Ptr<DataOutputInterface> output = 0;

if (format == "omnet") {

NS_LOG_INFO ("Creating omnet formatted data output.");

output = CreateObject<OmnetDataOutput>();

} else if (format == "db") {

#ifdef STATS_HAS_SQLITE3

NS_LOG_INFO ("Creating sqlite formatted data output.");

output = CreateObject<SqliteDataOutput>();

#endif

} else {

NS_LOG_ERROR ("Unknown output format " << format);

}

// Finally, have that writer interrogate the DataCollector and save

// the results.

if (output != 0)

output->Output (data);

// Free any memory here at the end of this example.

Simulator::Destroy ();

// end main

}

在examples/stats/wifi-example-db.sh腳本中運行用例,執行模擬,通過設置一定距離收集數據到sqlite3數據庫。整個運行要十幾秒。

#!/bin/sh

DISTANCES="25 50 75 100 125 145 147 150 152 155 157 160 162 165 167 170 172 175 177 180"

TRIALS="1 2 3 4 5"

echo WiFi Experiment Example

pCheck=`which sqlite3`

if [ -z "$pCheck" ]

then

echo "ERROR: This script requires sqlite3 (wifi-example-sim does not)."

exit 255

fi

pCheck=`which gnuplot`

if [ -z "$pCheck" ]

then

echo "ERROR: This script requires gnuplot (wifi-example-sim does not)."

exit 255

fi

pCheck=`which sed`

if [ -z "$pCheck" ]

then

echo "ERROR: This script requires sed (wifi-example-sim does not)."

exit 255

fi

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:bin/

if [ -e ../../data.db ]

then

echo "Kill data.db? (y/n)"

read ANS

if [ "$ANS" = "yes" -o "$ANS" = "y" ]

then

echo Deleting database

rm ../../data.db

fi

fi

for trial in $TRIALS

do

for distance in $DISTANCES

do

echo Trial $trial, distance $distance

../../waf --run "wifi-example-sim --format=db --distance=$distance --run=run-$distance-$trial"

done

done

#

#Another SQL command which just collects raw numbers of frames receved.

#

#CMD="select Experiments.input,avg(Singletons.value) \

# from Singletons,Experiments \

# where Singletons.run = Experiments.run AND \

# Singletons.name='wifi-rx-frames' \

# group by Experiments.input \

# order by abs(Experiments.input) ASC;"

mv ../../data.db .

CMD="select exp.input,avg(100-((rx.value*100)/tx.value)) \

from Singletons rx, Singletons tx, Experiments exp \

where rx.run = tx.run AND \

rx.run = exp.run AND \

rx.variable='receiver-rx-packets' AND \

tx.variable='sender-tx-packets' \

group by exp.input \

order by abs(exp.input) ASC;"

sqlite3 -noheader data.db "$CMD" > wifi-default.data

sed -i.bak "s/|/ /" wifi-default.data

rm wifi-default.data.bak

gnuplot wifi-example.gnuplot

echo "Done; data in wifi-default.data, plot in wifi-default.eps"

運行結果:

clip_image014

運行后可以看出多了一些分析數據文件

clip_image016

v Gnuplot繪圖工具

具體類的繼承:

clip_image018

在ns-allinone-3.19/ns-3.19/src/stats/examples/gnuplot-example.cc中有示例。

/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */

/*

* Copyright (c) 2011 University of Washington

*

* This program is free software; you can redistribute it and/or modify

* it under the terms of the GNU General Public License version 2 as

* published by the Free Software Foundation;

*

* This program is distributed in the hope that it will be useful,

* but WITHOUT ANY WARRANTY; without even the implied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

* GNU General Public License for more details.

*

* You should have received a copy of the GNU General Public License

* along with this program; if not, write to the Free Software

* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

*

* Author: Mitch Watrous (watrous@u.washington.edu)

*/

#include <fstream>

#include "ns3/gnuplot.h"

using namespace ns3;

namespace {

//===========================================================================

// Function: Create2DPlotFile

//

//

// This function creates a 2-D plot file.

//===========================================================================

void Create2DPlotFile ()

{

std::string fileNameWithNoExtension = "plot-2d";

std::string graphicsFileName = fileNameWithNoExtension + ".png";

std::string plotFileName = fileNameWithNoExtension + ".plt";

std::string plotTitle = "2-D Plot";

std::string dataTitle = "2-D Data";

// Instantiate the plot and set its title.

Gnuplot plot (graphicsFileName);

plot.SetTitle (plotTitle);

// Make the graphics file, which the plot file will create when it

// is used with Gnuplot, be a PNG file.

plot.SetTerminal ("png");

// Set the labels for each axis.

plot.SetLegend ("X Values", "Y Values");

// Set the range for the x axis.

plot.AppendExtra ("set xrange [-6:+6]");

// Instantiate the dataset, set its title, and make the points be

// plotted along with connecting lines.

Gnuplot2dDataset dataset;

dataset.SetTitle (dataTitle);

dataset.SetStyle (Gnuplot2dDataset::LINES_POINTS);

double x;

double y;

// Create the 2-D dataset.

for (x = -5.0; x <= +5.0; x += 1.0)

{

// Calculate the 2-D curve

//

// 2

// y = x .

//

y = x * x;

// Add this point.

dataset.Add (x, y);

}

// Add the dataset to the plot.

plot.AddDataset (dataset);

// Open the plot file.

std::ofstream plotFile (plotFileName.c_str());

// Write the plot file.

plot.GenerateOutput (plotFile);

// Close the plot file.

plotFile.close ();

}

//===========================================================================

// Function: Create2DPlotWithErrorBarsFile

//

//

// This function creates a 2-D plot with error bars file.

//===========================================================================

void Create2DPlotWithErrorBarsFile ()

{

std::string fileNameWithNoExtension = "plot-2d-with-error-bars";

std::string graphicsFileName = fileNameWithNoExtension + ".png";

std::string plotFileName = fileNameWithNoExtension + ".plt";

std::string plotTitle = "2-D Plot With Error Bars";

std::string dataTitle = "2-D Data With Error Bars";

// Instantiate the plot and set its title.

Gnuplot plot (graphicsFileName);

plot.SetTitle (plotTitle);

// Make the graphics file, which the plot file will create when it

// is used with Gnuplot, be a PNG file.

plot.SetTerminal ("png");

// Set the labels for each axis.

plot.SetLegend ("X Values", "Y Values");

// Set the range for the x axis.

plot.AppendExtra ("set xrange [-6:+6]");

// Instantiate the dataset, set its title, and make the points be

// plotted with no connecting lines.

Gnuplot2dDataset dataset;

dataset.SetTitle (dataTitle);

dataset.SetStyle (Gnuplot2dDataset::POINTS);

// Make the dataset have error bars in both the x and y directions.

dataset.SetErrorBars (Gnuplot2dDataset::XY);

double x;

double xErrorDelta;

double y;

double yErrorDelta;

// Create the 2-D dataset.

for (x = -5.0; x <= +5.0; x += 1.0)

{

// Calculate the 2-D curve

//

// 2

// y = x .

//

y = x * x;

// Make the uncertainty in the x direction be constant and make

// the uncertainty in the y direction be a constant fraction of

// y's value.

xErrorDelta = 0.25;

yErrorDelta = 0.1 * y;

// Add this point with uncertainties in both the x and y

// direction.

dataset.Add (x, y, xErrorDelta, yErrorDelta);

}

// Add the dataset to the plot.

plot.AddDataset (dataset);

// Open the plot file.

std::ofstream plotFile (plotFileName.c_str());

// Write the plot file.

plot.GenerateOutput (plotFile);

// Close the plot file.

plotFile.close ();

}

//===========================================================================

// Function: Create3DPlotFile

//

//

// This function creates a 3-D plot file.

//===========================================================================

void Create3DPlotFile ()

{

std::string fileNameWithNoExtension = "plot-3d";

std::string graphicsFileName = fileNameWithNoExtension + ".png";

std::string plotFileName = fileNameWithNoExtension + ".plt";

std::string plotTitle = "3-D Plot";

std::string dataTitle = "3-D Data";

// Instantiate the plot and set its title.

Gnuplot plot (graphicsFileName);

plot.SetTitle (plotTitle);

// Make the graphics file, which the plot file will create when it

// is used with Gnuplot, be a PNG file.

plot.SetTerminal ("png");

// Rotate the plot 30 degrees around the x axis and then rotate the

// plot 120 degrees around the new z axis.

plot.AppendExtra ("set view 30, 120, 1.0, 1.0");

// Make the zero for the z-axis be in the x-axis and y-axis plane.

plot.AppendExtra ("set ticslevel 0");

// Set the labels for each axis.

plot.AppendExtra ("set xlabel \"X Values\"");

plot.AppendExtra ("set ylabel \"Y Values\"");

plot.AppendExtra ("set zlabel \"Z Values\"");

// Set the ranges for the x and y axis.

plot.AppendExtra ("set xrange [-5:+5]");

plot.AppendExtra ("set yrange [-5:+5]");

// Instantiate the dataset, set its title, and make the points be

// connected by lines.

Gnuplot3dDataset dataset;

dataset.SetTitle (dataTitle);

dataset.SetStyle ("with lines");

double x;

double y;

double z;

// Create the 3-D dataset.

for (x = -5.0; x <= +5.0; x += 1.0)

{

for (y = -5.0; y <= +5.0; y += 1.0)

{

// Calculate the 3-D surface

//

// 2 2

// z = x * y .

//

z = x * x * y * y;

// Add this point.

dataset.Add (x, y, z);

}

// The blank line is necessary at the end of each x value's data

// points for the 3-D surface grid to work.

dataset.AddEmptyLine ();

}

// Add the dataset to the plot.

plot.AddDataset (dataset);

// Open the plot file.

std::ofstream plotFile (plotFileName.c_str());

// Write the plot file.

plot.GenerateOutput (plotFile);

// Close the plot file.

plotFile.close ();

}

} // anonymous namespace

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

{

// Create a 2-D plot file.

Create2DPlotFile();

// Create a 2-D plot with error bars file.

Create2DPlotWithErrorBarsFile();

// Create a 3-D plot file.

Create3DPlotFile();

return 0;

}

運行之后的文件:

clip_image019

可以分析

gnuplot plot-2d.pl,生成圖片

clip_image020

clip_image021

clip_image023

clip_image025


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM