v Pyiz
在ns-3中集合到Visualizer。只要在程序中加入:
CommandLine cmd;
cmd.Parse (argc,argv);
並且在運行是加入參數-vis。它不需要trace文件
運行第三個示例./waf --run third --vis
紅色為無線網絡,綠色為通信狀態。
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文件,單擊播放按鈕開始動畫。
具體截圖如下:
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"
運行結果:
運行后可以看出多了一些分析數據文件
v Gnuplot繪圖工具
具體類的繼承:
在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;
}
運行之后的文件:
可以分析
gnuplot plot-2d.pl,生成圖片