1 ns-3初識
資料:
- ns-3官網:http://www.nsnam.org/
- ns-3官方開發文檔:https://www.nsnam.org/releases/ns-3-34/documentation/
- ns-3維基百科(文檔中沒有的内容)、FAQ問題解答:https://www.nsnam.org/support/
- ns-3相關文獻:https://www.nsnam.org/education/
2 ns-3快速上手
使用waf配置編譯ns-3系統:
./waf clean #清除先前的配置編譯
./waf -d optimized --enable-examples --enable-tests configure #重新配置ns-3,優化編譯包括例子和測試(優化模式下禁止輸出)
./waf -d --enable-examples --enable-tests configure #重新配置ns-3,優化編譯包括例子和測試(這樣就有輸出了)
./waf #正式編譯
測試安裝
./test.py -c core # 測試ns-3發行版是否編譯正确
./waf --run scratch-simulator# 運作腳本測試
3 ns-3基礎
3.1 關鍵概念
-
節點
Node類描述節點,提供添加外設卡、驅動程式、協定棧、應用程式等功能。
NodeContainer類,拓撲生成器,用于建立、管理
使用節點,儲存一組節點指針。
NodeContainer nodes;//聲明一個名為nodes的NodeContainer
node.Create (2);//調用nodes對象的Create()方法建立2個節點對象,并把2個節點對象的指針存儲在系統中
-
應用
Application類描述。
UdpEchoServerHelper和UdpEchoClientHelper為Application類執行個體。(動物類->執行個體:熊貓類)
-
信道
Channel類,執行個體包括:CsmaChannel(模拟了載波偵聽多路通路通信子網中的媒介,有以太網的功能)、PointToPointChannel(最多2個點到點連接配接的網絡裝置)、WifiChannel(無線信道)
-
網絡裝置(網卡)
NetDevice類,提供連接配接節點和信道對象的各種方法。執行個體有:CsmaNetDevice、PointToPointNetDevice、Wi-FiNetDevice。
NetDeviceContainer類存放(類似NodeContainer類)。
-
拓撲幫助
Helper類,用于網絡裝置配置到節點、連接配接信道、配置IP位址等。
例如TopologyReaderHelper類可以配置和使用TopologyReader;InternetStackHelper安裝PointToPointHelper對象和網絡協定棧。
3.2 優化技術
3.2.1 Logging系統
将執行結果輸出指令行中(類似cout、printf)。
LogComponentEnable ("UdpEchoClientApplication",LOG_LEVEL_INFO); //LogComponentEnable()使記錄子產品有效,參數1是類元件的字元串,參數2是顯示的等級(例如改為下列其他值)
LogComponentEnable ("UdpEchoServerApplication", LOG_LEVEL_INFO);
通過環境變量修改記錄系統等級
export 'NS_LOG=UdpEchoClientApplication=level_all:UdpEchoServerApplication=level_all' #export為指令,level_all等級表示顯示全部的調試資訊
./waf --run scratch/first
添加附加字首
自定義Logging代碼(輸出自定義資訊)
NS_LOG_COMPONENT_DEFINE("FirstScriptExample");//向ns-3系統注冊一個名為"FirstScriptExample"的記錄元件,之後才能在Logging系統中自定義輸出語句。
NS_LOG_INFO("Creating Topology")//在first.cc中添加
3.2.2 指令行參數
作用:不修改腳本,用指令行傳遞參數來修改腳本中的變量。
CommandLine cmd;
cmd.Parse(argc,argv);//之後使用者可以用指令行通路代碼中的全局變量和屬性系統
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
挂鈎自定義變量
int main(int argc,char *argv[]){
uint32_t nPackets = 1;
CommandLine cmd;
cmd.AddValue("nPackets","Number of packets to echo",nPackets);//使得變量nPackets可以在指令行中修改
cmd.Parse(argc, argv);
//echoClient.SetAttribute("MaxPackets",UintegerValue(1));
echoClient.SetAttribute("MaxPackets",UintegerValue(nPackets));
}
# 運作
./waf --run "scratch/first --PrintHelp"
./waf --run "scratch/first --nPackets=2"
3.2.3 Tracing系統
- 作用:将執行結果輸出一個檔案中。
- 3個基本概念:Tracing Sources、Tracing Sink、連接配接的統一機制。
- Helper類:AsciiTraceHelper生成文檔
- ASCII Tracing:以ASCII格式的資訊輸出
//在Simulator::Run();前寫入
AsciiTraceHelper ascii;//聲明一個AsciiTraceHelper對象,為調用其成員函數做準備
pointToPoint.EnableAsciiAll (ascii.CreateFileStream ("myfirst.tr"));//CreateFileStream()建立一個名為myfirst.tr流檔案。EnableAsciiAll()通知helper将所有關于pointToPoint裝置的仿真資訊列印為ASCII Tracing格式。
# 運作後在ns-3.xx中多一個檔案myfirst.tr
./waf --run scratch/first
-
PCAP Tracing
生成.pacp格式檔案,可用于Wireshark工具打開分析。
4 ns-3仿真結果統計分析
4.1 ns-3仿真可視化工具
4.1.1 PyViz 可視化子產品
# 運作
./waf --run example/tutorial/third --vis
其他資訊:http://www/nsnam.org/wiki/index.php/PyViz
4.1.2 NetAnim 動畫示範工具
在腳本檔案中寫入代碼,以生成XML記錄檔案。
//確定程式的wscript檔案包含netanim子產品(關于wscript檔案的例子在src/netanim/examples/wscript中)
# include "ns3/netanim-module.h"
AnimationInterface anim ("first.xml");// 設定XML檔案。生成檔案名為animation.xml的xml格式的追蹤檔案
// AnimationInterface anim ("animation.xml",50000); // 確定每個動畫XML檔案僅包含50000個資料分組,多了分為幾個XML檔案
// 以下為可選語句
anim.SetMobilityPollInterval (Seconds (1)); //設定記錄節點位置的周期,預設為250ms
anim.SetConstantPosition (Ptr<Node> n, double x, double y); //設定節點的位置,ConstantPosition為移動模型中節點靜态位置的x、y坐标。
anim.SetStartTime (Seconds (150)); //動畫接口可以隻記錄仿真過程中一部分。設定動畫記錄的開始和結束時間
anim.SetStopTime (Seconds (200));
anim.EnablePacketMetadata (true); // 設定XML檔案記錄包括中繼資料(如TCP序号、源節點目的節點的IP位址)。啟用此特性會導緻xml記錄檔案增大,在WIMAX仿真中不建議使用
//AnimationInterface的其他方法可以看ns-3/src/netanim/examples/wireless-anemation.cc目錄下的檔案例子
運作:
# 在NetAnim目錄下
./NetAnim
# 在ns-3.xx目錄下
./waf --run first
在netanim界面中點選open->first.xml->play
詳細資訊:http://www.nsnam.org/wiki/index.php/NetAnim
4.2 分析追蹤記錄檔案資料
第三方網絡資料分組顯示和統計分析工具,讀取ns-3的trace檔案,并進行統計和分析。
4.2.1 TcpDump
TcpDump (dump the traffic on a network),讀取pcap檔案,截獲分組,分析頭部,輸出
系統時間來源主機.端口 > 目标主機.端口資料分組參數
使用方法:
在腳本first.cc中加入代碼
在指令行中使用TcpDump
# 格式
# tcpdump [-adeflnOpqStvx][-c 數量][-F 檔案名][-i 網絡接口][-r 檔案名][-s snaplen][-T 類型][-w 檔案名][表達式]
tcpdump -nn -tt -r first-0-0.pcap
# 輸出
reading from file first-1-0.pcap, link-type PPP (PPP) # 鍊路類型為PPP
2.003686 IP 10.1.1.1.49153 > 10.1.1.2.9: UDP, length 1024 # 資料分組從節點0(IP:10.1.1.1, port:49153)發出,到達節點4(IP:10.1.2.4, port:9)
2.003686 IP 10.1.1.2.9 > 10.1.1.1.49153: UDP, length 1024
4.2.2 Wireshark
在Wireshark界面中打開first-0-0.pace,可以看到通信過程、資料分組格式、二進制流。
工作區上部分為資料分組的簡單資訊,中間為詳細資訊(各個協定的頭格式),下面為二進制顯示。
詳細資訊:http://www.wireshark.org/
4.3 統計子產品status
使用方法
-
寫腳本
例子: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 <[email protected]>
*
* 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/internet-module.h"
#include "ns3/stats-module.h"
#include "ns3/yans-wifi-helper.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 ();
}
// 1. Set up command line parameters used to control the experiment.聲明參數和使用ns3::CommandLine解析指令
CommandLine cmd (__FILE__);
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 ();
}
//------------------------------------------------------------
//-- 2. Create nodes and network stacks建立節點和網絡堆棧
//--------------------------------------------
NS_LOG_INFO ("Creating nodes.");
NodeContainer nodes;//NodeContainer
nodes.Create (2);
NS_LOG_INFO ("Installing WiFi and Internet stack.");
WifiHelper wifi;//WifiHelper
WifiMacHelper wifiMac;
wifiMac.SetType ("ns3::AdhocWifiMac");
YansWifiPhyHelper wifiPhy;
YansWifiChannelHelper wifiChannel = YansWifiChannelHelper::Default ();
wifiPhy.SetChannel (wifiChannel.Create ());
NetDeviceContainer nodeDevices = wifi.Install (wifiPhy, wifiMac, nodes);
InternetStackHelper internet; // InternetStackHelper
internet.Install (nodes);
Ipv4AddressHelper ipAddrs;
ipAddrs.SetBase ("192.168.0.0", "255.255.255.0");
ipAddrs.Assign (nodeDevices);
//------------------------------------------------------------
//-- 3. Setup physical layout
//--------------------------------------------
NS_LOG_INFO ("Installing static mobility; distance " << distance << " .");
MobilityHelper mobility;//使用MobilityHelper定位節點。預設節點有靜态流動性且不能移動
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);
//------------------------------------------------------------
//-- 4. 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,//“實驗”資訊标簽,辨別研究對象,Wi-Fi性能和距離
strategy,//政策:實驗中被檢測的參數,e.g. Wi-Fi比特率
input,//輸入,2個節點之間的距離
runID);//運作ID,實驗的唯一辨別符。運作資訊
// Add any information we wish to record about this run.
data.AddMetadata ("author", "tjkopena");
// 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
}
4.4 繪圖工具Gnuplot
第三方作圖工具,有gnuplot類,可産生gnuplot資料,最後由gnuplot讀取資料生成圖表,進而進行仿真資料統計分析。
# 安裝
apt-get install Gnuplot
# 進入Gnuplot互動界面
gnuplot>
# 得到正弦曲線
plot[-3.14:3.14]sin(x)
詳細資訊:http://www.gnuplot.info/
ns-3提供了Gnuplot類和GnuplotDataset類
ns-3中使用方法:(例子ns-3.xx/src/tools/examples/gnuplot-example.cc)
# 運作例子
./waf --run src/tools/examples/gnuplot-example
# 結果:生成Gnuplot控制檔案 plot-2d.plt plot-2d-with-error-bars.plt plot-3d.plt
# 使用gnuplot處理gnuplot控制檔案
gnuplot plot-2d.plt
gnuplot plot-2d-with-error-bars.plt
gnuplot plot-3d.plt
# 處理後生成圖檔檔案:plot-2d.png plot-2d-with-error-bars.png plot-3d.png
# 圖檔可以用浏覽器等工具打開(e.g. gimp, Image Viewer, Shotwell)
5 ns-3核心
5.1 ns-3的組織結構
- 組織結構在src目錄中實作。下層為上層服務。
- 核心子產品,在src/core中實作。包括了ns-3基本機制,例如随機變量、回調、屬性系統、Tracing系統等。
- 網絡子產品,分組在src/network中實作,讨論網絡資料分組的相關問題。
- Internet子產品:介紹Internet網絡基本協定,包括路由、傳輸層。
- 移動子產品:提供一些移動模型。
- 應用層子產品:提供一些應用程式。
- 能量子產品:關于節點能量消耗。
5.2 随機變量Random Variables
-
随機數生成器(RNG)
随機變量通過調用類ns3::RandomVariableStream提供。這個類封裝了随機數生成器并提供接口。子類:UniformVariableStream和ExponetialVariableStram。
- 仿真程式中,不改變種子或運作辨別的前提下,仿真程式産生的結果的一定的。想要結果不一樣,ns3::RngSeedManager::SetSeed()設定種子,或ns3::RngSeedManager::SetRun()設定運作辨別。
- ns-3所有的随機變量使用一個基于全局固定的或随機的種子。
- 固定的種子和辨別存儲在類GlobalValue的g_rngSeed和g_rngRun成員中。
- 同一仿真程式多次實驗,若要實作每次實驗都具有獨立性,有兩種方法:
方法一:每次獨立重複實驗時,調用函數RngSeedManager::SetSeed()設定不同的全局種子。
//在scratch檔案夾下,建立檔案sample-random-variable-stream.cc
# include "ns3/simulator.h"
# include "ns3/nstime.h"
# include "ns3/command-line.h"
# include "ns3/rng-seed-manager.h"
# include "ns3/random-variable-stream.h"
# include <iostream>
using namespace ns3;
int main(int argc,char *argv[])
{
CommandLine cmd;
cmd.Parse(argc, argv);
RngSeedManager::SetSeed(1);//改為SetSeed(2)結果也會變化
Ptr<UniformRandomVariable> uv=CreateObject<UniformRandomVariable>();//建立一個指向随機變量類的指針uv
std::cout << uv->GetValue() << std::endl;
return 0;
}
# 運作
./waf --run scratch/sample-random-variable-stream
# 不改代碼的話,每次運作輸出同樣的數字[0,1),例如0.816532
方法二:每次獨立重複實驗時,全局種子不變,每次設定不同的辨別。改變辨別有幾種方式:
a. 調用函數RngSeedManager::SetRun(3)設定不同的運作辨別。
// 修改檔案代碼
RngSeedManager::SetRun(3);//這一句代替RngSeedManager::SetSeed(1);
b. 修改全局變量NS_GLOBAL_VALUE值來修改運作辨別。
# 運作
# ./waf --run scratch/sample-random-variable-stream
NS_GLOBAL_VALUE="RngRun=3" ./waf --run scratch/sample-random-variable-stream # RngRun=可以取不同的值
c(推薦). 使用指令行傳遞參數修改運作辨別
# 運作
./waf --run "scratch/sample-random-variable-stream --RngRun=3"
d. 使用build
# 運作
./build/optimized/scratch/sample-random-variable-stream --RngRun=3
随機變量
ns-3中用來聲明随機變量的類,都有一個基類RandomVariableStream。其基類有:
- UniformRandomVariable: 最基本的類。給定一個最大值和最小值,按均勻分布方式傳回一個随機數。
# include "ns3/double.h"
# include "ns3/simulator.h"
# include "ns3/nstime.h"
# include "ns3/command-line.h"
# include "ns3/rng-seed-manager.h"
# include "ns3/random-variable-stream.h"
# include <iostream>
using namespace ns3;
int main(int argc,char *argv[])
{
CommandLine cmd;
cmd.Parse(argc,argv);
RngSeedManager::SetSeed(3);
double min = 0.0;
double max = 10.0;
Ptr<UniformRandomVariable> uv = CreateObject<UniformRandomVariable> ();
//改變傳回随機變量的區間為[0,10),預設為[0,1)
uv->SetAttribute("Min",DoubleValue(min));
uv->SetAttribute("Max",DoubleValue(max));
std::cout << uv->GetValue() << std::endl;
return 0;
}
- ConstantRandomVariable: 傳回一個固定的數,預設為0
...
// Ptr<UniformRandomVariable> uv = CreateObject<UniformRandomVariable> ();
//改變傳回随機變量為10,預設為0
double dValue = 10.0;
Ptr<UniformRandomVariable> uv = CreateObject<ConstantRandomVariable> ();
uv->SetAttribute("Constant",DoubleValue(dValue))
...
}
- SequentialRandomVariable: 傳回一串等差數列,超過最大上限重新從開始再次循環。
- ExponentialRandomVariable: 根據指數機率分布傳回随機數。
- NormalRandomVariable: 根據正态分布傳回随機數
5.3 回調Callbacks
-
為什麼用回調機制?why
實作讓A子產品調用B子產品的函數,并且兩個子產品沒有任何依賴。
先看C語言中的回調機制:
//想調用另一個子產品的函數,先把被調用函數的位址作為一個變量,這個變量為函數指針變量。
int (*pfi)(int arg) = 0;//聲明一個帶整型參數(int arg)的函數指針pfi,初始值為0,前面int表示指向函數的傳回值為整型,函數參數和指針參數也一緻。
int MyFunction(int arg){}//pfi對應函數可以聲明為這樣
pfi = MyFuction;//用函數初始化函數指針
int result = (*pfi)(1234);//通過函數指針調用函數
在C++中還要為成員函數建立成員函數指針、區分成員函數指針和函數指針:
int (MyClass::*pmi)(int arg) = 0;//聲明類的成員函數指針,MyClass類名
class MyClass
{
public:
int MyMethod (int arg);//函數聲明
};
pmi = &MyClass::MyMethod;//pmi類函數指針變量的指派和調用
MyClass myclass;
myclass.*pmi(1234);
-
什麼是回調機制?what
例如調用快排函數,函數參數中有回調函數位址,可以傳遞自己的比較函數。這種被調用者(快排函數)調用調用者的排序函數(cmp),稱為回調。
-
怎麼用回調機制?how
ns-3提供了Callback類的API接口:
- 靜态函數
// 對于靜态函數,聲明和執行個體化Callback類型
static double CbOne (double a, double b)
{
std::cout<<"invoke cbOne a="<<a<<",b="<<b<<std::endl;
return a;
}
int main(int argc,char *argv[])
{
Callback<double, double, double> one;//執行個體化回調類。<傳回類型,第一個參數,第二個參數>
one = MakeCallback(&CbOne);//将回調one與簽名比對的函數進行綁定
//使用回調
NS_ASSERT(!one.IsNull());//檢查回調one是否為空
Double retOne;
retOne = one(10.0, 20.0);
}
- 類成員函數回調
class MyCb{
public:
int CbTwo (double a){
std::cout<<"invoke cbTwo a="<<a<<std::endl;
return -5;
}
}
int main(int argc,char *argv[])
{
Callback<int, double> two;
MyCb cb;
two = MakeCallback (&MyCb::CbTwo,&cb);//建立一個回調變量并指向MyCb::CbTwo
//若建構空回調:two = MakeCallback<int,double>();int retTwoNull = two(20.0);
//使用回調
NS_ASSERT(!two.IsNull());
int retTwo;
retTwo = two(10.0);
NS_ASSERT(retTwo == -5);
two = MakeNullCallback<int, double>();//傳遞一個額外指針給函數MakeNullCallback<>(),當函數two()被調用時,調用的是&cb指向的對象函數CbTwo。
NS_ASSERT(two.IsNull());
return 0;
}
5.4 對象模型
- 面向對象設計
-
對象基類
ns-3提供了3個對象基類:Object、ObjectBase、SimpleRefCount。若每個類繼承這種類,就可以包含ns-3提供的特有特性:
基類 | 屬性 |
---|---|
Object | 屬性系統、對象聚合系統、智能指針和引用計數系統 |
ObjectBase | 屬性系統、對象聚合系統 |
SimpleRefCount | 智能指針和引用計數系統 |
-
記憶體管理與引用計數指針(Ptr類)
ns-3使用引用計數來管理記憶體 。
//在ns-3中使用CreateObject()來建立對象,而不是使用C++的new操作符。這是對new操作的封裝,自動處理智能指針的引用次數。
Ptr<WifiNetDevice> device = CreateObject<WifiNetDevice>();
- 聚合
-
why?
例如ns-3中,Node類在任何網絡終端中都使用,但不同網絡終端的建構和協定不同,為了建立滿足不同網絡節點需求,就要使用聚合,将不同構件聚合到節點中。
- what?
-
how?
例如,将IPv4協定加入節點中:
static void
AddIpv4Stack(Ptr<Node> node)
{
Ptr<IPv4L3Protocol> ipv4 = CreateObject<IPv4L3Protocol> ();//建立一個IPv4協定的指針對象ipv4
ipv4->SetNode (node);//把IPv4協定聚合到節點中。這樣Node就不需要被單獨編輯。
node->AggregateObject (ipv4);
Ptr<IPv4Impl> ipv4Impl = CreateObject<IPv4Impl> ();
ipv4Impl->SetIPv4 (ipv4);
node->AggregateObject (ipv4Impl);
}
5.5 屬性系統
- 對象模型:設定執行個體化模型的參數。
- Object類:多數ns-3類都是繼承Object類。所有繼承Object的類都可以包含一個叫TypeId的中繼資料類,用于記錄類的元資訊(包括唯一辨別字元串、子類的基類、子類的構造函數)。
- 例子:Node類,靜态成員函數GetTypeId
// 頭檔案node.h中
Class Node : public Object
{
public:Static TypeId GetTypeId(void):...
}
//node.cc檔案中
TypeId
Node::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::Node")
.SetParent<Object> ()//聲明此類的基類,友善在用GetObject()時進行向上或向下類型轉化
.AddConstryctor<Node> ()//建構對象
.AddAttribute ("DeviceList","The list of devices associated to this Node.",ObjectVectorValue (), MakeObjectVectorAccessor (&Node::m_devices), MakeObjectVectorChecker<NetDevice> ())//把字元串與類的成員變量關聯。參數1:要綁定的字元串,參數2:解釋說明,參數3:成員變量必須轉化的類型,參數4:将成員變量強制轉化為參數3的類型,參數5:對成員變量是否合法的檢查
.AddAttribute ("ApplicationList","The list of application associated to this Node.",ObjectVectorValue (), MakeObjectVectorAccessor (&Node::m_applications), MakeObjectVectorChecker<Application> ())
.AddAttribute ("Id","The id(unique integer)of this Node.",TypeId::ATTR_GET, UintegerValue (0), MakeUintegerAccessor (&Node::m_id), MakeUintegerChecker<uint32_t> ());
return tid;
}
//使用CreateObject(),建立節點:
Ptr<Node> n = CreateObject<Node>();
//使用對象工程機制,建立節點:
ObjectFactory factory;
const st::string typeId = "ns3::Node";
factory.SetTypeId (typeId);
Ptr(Object) node = factory.Create<Object> ();
- 屬性系統:管理群組織仿真中内部對象(友善使用者通路模拟中内部變量,e.g. cwnd)
- 例如:DropTailQueue類,無符号整型成員變量m_maxPackets(用來控制隊列的大小)
// drop-tail-queue.h
class DropTailQueue : public Queue
{
public:
static typeId GetTypeId (void);
...
private:
std::queue<Ptr<Packet>> m_packets;
uint32_t m_maxPackets;
};
// drop-tail-queue.cc
// 用TypeId類實作建立類時,成員變量被初始化為預設值
NS_OBJECT_ENSURE_REGISTERED (DropTailQueue);//自定義類必須有,使屬性系統涉及的屬性可以正常初始化。
TypeId DropTailQueue::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::DropTailQueue")
.SetParent<Queue> ()
.AddConstructor<DropTailQueue> ()
.AddAttribute ("MaxPackets","The maximum number of packets accepted by this DropTailQueue.", UintegerValue (100), MakeUintegerAccessor (&DropTailQueue::m_maxPackets), MakeUintegerChecker<uint32_t> ());//使用AddAttribute()方法處理變量m_maxPackets:将m_maxPackets綁定到字元串“MaxPackets”中,預設值為100,Checker可用來設定允許的範圍
return tid;
}
在腳本中操縱屬性系統中的資料(src/point-to-point/examples/main-attribute-value.cc)
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2008 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: Tom Henderson <[email protected]>
*/
#include "ns3/log.h"
#include "ns3/command-line.h"
#include "ns3/ptr.h"
#include "ns3/config.h"
#include "ns3/uinteger.h"
#include "ns3/string.h"
#include "ns3/pointer.h"
#include "ns3/simulator.h"
#include "ns3/node.h"
#include "ns3/queue.h"
#include "ns3/drop-tail-queue.h"
#include "ns3/point-to-point-net-device.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE ("AttributeValueSample");
//
// This is a basic example of how to use the attribute system to
// set and get a value in the underlying system; namely, the maximum
// size of the FIFO queue in the PointToPointNetDevice
//
int
main (int argc, char *argv[])
{
LogComponentEnable ("AttributeValueSample", LOG_LEVEL_INFO);
// Queues in ns-3 are objects that hold items (other objects) in
// a queue structure. The C++ implementation uses templates to
// allow queues to hold various types of items, but the most
// common is a pointer to a packet (Ptr<Packet>).
//
// The maximum queue size can either be enforced in bytes ('b') or
// packets ('p'). A special type called the ns3::QueueSize can
// hold queue size values in either unit (bytes or packets). The
// queue base class ns3::QueueBase has a MaxSize attribute that can
// be set to a QueueSize.
// By default, the MaxSize attribute has a value of 100 packets ('100p')
// (this default can be observed in the function QueueBase::GetTypeId)
//
// Here, we set it to 80 packets. We could use one of two value types:
// a string-based value or a QueueSizeValue value
Config::SetDefault ("ns3::QueueBase::MaxSize", StringValue ("80p"));
// The below function call is redundant
Config::SetDefault ("ns3::QueueBase::MaxSize", QueueSizeValue (QueueSize (QueueSizeUnit::PACKETS, 80)));
// Allow the user to override any of the defaults and the above
// SetDefaults() at run-time, via command-line arguments
// For example, via "--ns3::QueueBase::MaxSize=80p"
CommandLine cmd;
// This provides yet another way to set the value from the command line:
cmd.AddValue ("maxSize", "ns3::QueueBase::MaxSize");
cmd.Parse (argc, argv);
// Now, we will create a few objects using the low-level API
Ptr<Node> n0 = CreateObject<Node> ();
Ptr<PointToPointNetDevice> net0 = CreateObject<PointToPointNetDevice> ();
n0->AddDevice (net0);
Ptr<Queue<Packet> > q = CreateObject<DropTailQueue<Packet> > ();
net0->SetQueue (q);
// At this point, we have created a single node (Node 0) and a
// single PointToPointNetDevice (NetDevice 0) and added a
// DropTailQueue to it.
// Now, we can manipulate the MaxSize value of the already
// instantiated DropTailQueue. Here are various ways to do that.
// We assume that a smart pointer (Ptr) to a relevant network device
// is in hand; here, it is the net0 pointer.
// 1. Pointer-based access 通過指針通路屬性值
//
// One way to change the value is to access a pointer to the
// underlying queue and modify its attribute.
//
// First, we observe that we can get a pointer to the (base class)
// queue via the PointToPointNetDevice attributes, where it is called
// TxQueue
PointerValue ptr;// 建立一個指針變量
net0->GetAttribute ("TxQueue", ptr);// 為變量指派
Ptr<Queue<Packet> > txQueue = ptr.Get<Queue<Packet> > ();// 擷取隊列
// Using the GetObject function, we can perform a safe downcast。通過GetObject函數安全地把txQueue向下類型轉化(Queue->DropTailQueue)
// to a DropTailQueue
Ptr<DropTailQueue<Packet> > dtq = txQueue->GetObject <DropTailQueue<Packet> > ();
NS_ASSERT (dtq);
// Next, we can get the value of an attribute on this queue
// We have introduced wrapper "Value" classes for the underlying
// data types, similar to Java wrappers around these types, since
// the attribute system stores values and not disparate types.
// Here, the attribute value is assigned to a QueueSizeValue, and
// the Get() method on this value produces the (unwrapped) QueueSize.
// 通過輸出資料驗證程式是否将預設值100改成了80:
QueueSizeValue limit;
dtq->GetAttribute ("MaxSize", limit);
NS_LOG_INFO ("1. dtq limit: " << limit.Get ());
// Note that the above downcast is not really needed; we could have
// done the same using the Ptr<Queue> even though the attribute
// is a member of the subclass
// 實際上,不向下轉化,也可以得到MaxSize值:80
txQueue->GetAttribute ("MaxSize", limit);
NS_LOG_INFO ("2. txQueue limit: " << limit.Get ());
// Now, let's set it to another value (60 packets). Let's also make
// use of the StringValue shorthand notation to set the size by
// passing in a string (the string must be a positive integer suffixed
// by either the 'p' or 'b' character).
// 在建立對象後再改變MaxSize值:
txQueue->SetAttribute ("MaxSize", StringValue ("60p"));
txQueue->GetAttribute ("MaxSize", limit);
NS_LOG_INFO ("3. txQueue limit changed: " << limit.Get ());
// 2. Namespace-based access
// 通路屬性值的第二種方法:通過命名空間方式
// An alternative way to get at the attribute is to use the configuration
// namespace. Here, this attribute resides on a known path in this
// namespace; this approach is useful if one doesn't have access to
// the underlying pointers and would like to configure a specific
// attribute with a single statement.
// 修改了第一個節點的第一個網絡裝置屬性值
Config::Set ("/NodeList/0/DeviceList/0/TxQueue/MaxSize", StringValue ("25p"));
txQueue->GetAttribute ("MaxSize", limit);
NS_LOG_INFO ("4. txQueue limit changed through namespace: " <<
limit.Get ());
// we could have also used wildcards to set this value for all nodes
// and all net devices (which in this simple example has the same
// effect as the previous Set())
// 修改了所有節點的所有網絡裝置屬性值
Config::Set ("/NodeList/*/DeviceList/*/TxQueue/MaxSize", StringValue ("15p"));
txQueue->GetAttribute ("MaxSize", limit);
NS_LOG_INFO ("5. txQueue limit changed through wildcarded namespace: " <<
limit.Get ());
Simulator::Destroy ();
}
# 運作
./waf --run scratch/main-attribute-value
寫自己的網絡子產品:
-
添加現有類的成員變量到中繼資料系統中
例如TcpSocket類的成員變量:uint32_tm_cWnd。使用TCP子產品時想用中繼資料獲得、設定變量的值,而ns-3沒有提供這個變量,使用者可以在中繼資料系統中添加聲明:
./AddAttribute ("Congestion window","Tcp congestion window (bytes)",
UintergerValue(1),
MakeUintergerAccessor(&TcpSocket::m_cWnd),
MakeUintergerChecker<uint16_t>())
進而可以用指向TcpSocket類的指針執行設定和擷取操作。
-
向屬性系統中添加自定義類
例如:把自定義的類A加入到系統屬性中
//在a.h中聲明類A
class A:public Object{
public:
...
static TypeId GetTypeId(void);
...
private:
int16_t m_int16;
};
NS_OBJECT_ENSURE_REGISTERED(A);
//在a.cc中定義類函數GetTypeId
static TypeId GetTypeId(void){
static TypeId tid = TypeId("ns3::A")
.SetParent<Object>()
.addAttribute("TestInt16","help text",IntgerValue(-2),MakeIntegerAccessor(&A::m_int16),MakeInterChecker<int16_t>());
return tid;
}
5.6 Tracing系統
作用:追蹤某仿真資料。
Tracing系統由三部分構成:Tracing Sources, Tracing Sinks, 連接配接前兩者的方法。
- Tracing Sources提供資訊(生産者)。
- Tracing Sinks使用資訊做相關事務(消費者)。
- 二者關聯。使用到回調。
(1)使用函數TraceConnectWithoutContext将二者關聯。
例子:(examples/tutorial/fourth.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
*/
# include "ns3/object.h" //定義自己的類,父類為Object
# include "ns3/uinteger.h"//要用到自定義的無符号整型
# include "ns3/traced-value.h"//此頭檔案中引入了要跟蹤的資料的類型,即TracedValue
# include "ns3/traced-source-accessor.h"//使用把自定義資料轉換為traced-source的函數
# include <iostream>
using namespace ns3;
class MyObject : public Object
{//追蹤系統與屬性系統關聯緊密,是以追蹤的資料必須屬于一個類
public:
/**
* Register this type.
* \return The TypeId.
*/
static TypeId GetTypeId (void)
{
static TypeId tid = TypeId ("MyObject")
.SetParent<Object> ()
.SetGroupName ("Tutorial")
.AddConstructor<MyObject> ()
.AddTraceSource ("MyInteger",
"An integer value to trace.",
MakeTraceSourceAccessor (&MyObject::m_myInt),
"ns3::TracedValueCallback::Int32")//AddTraceSorce()使得m_myInt成為一個Trace Source
;
return tid;
}
MyObject () {}
TracedValue<int32_t> m_myInt;
};
// 此函數為定義Trace Sink
void
IntTrace (int32_t oldValue, int32_t newValue)
{
std::cout << "Traced " << oldValue << " to " << newValue << std::endl;
}
int
main (int argc, char *argv[])
{//定義一個對象執行個體,執行個體中包含一個TraceSource,m_myInt
Ptr<MyObject> myObject = CreateObject<MyObject> ();
myObject->TraceConnectWithoutContext ("MyInteger", MakeCallback (&IntTrace));//TraceConnectWithoutContext()将Trace Source和Trace Sink關聯。當Trace Source資料m_myInt變化時,IntTrace函數會被調用。
myObject->m_myInt = 1234;//m_myInt變化了,系統将m_myInt指派前和指派後的兩個值作為形參傳遞給Trace Sink的回調函數IntTrace
}
# 運作
./waf --run example/tutorial/fourth
# outpuy
Traced 0 to 1234
(2)使用“配置路徑”将Trace Sources和Trace Sink關聯起來。
例子:third.cc改寫,通過定義一個Trace Sink輸出移動節點的位置變化資訊。
#include "ns3/core-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/network-module.h"
#include "ns3/applications-module.h"
#include "ns3/mobility-module.h"
#include "ns3/csma-module.h"
#include "ns3/internet-module.h"
#include "ns3/yans-wifi-helper.h"
#include "ns3/ssid.h"
// Default Network Topology
//
// Wifi 10.1.3.0
// AP
// * * * *
// | | | | 10.1.1.0
// n5 n6 n7 n0 -------------- n1 n2 n3 n4
// point-to-point | | | |
// ================
// LAN 10.1.2.0
//2.命名空間
using namespace ns3;
using namespace std;// 加一行代碼
//3.定義一個LOG子產品
NS_LOG_COMPONENT_DEFINE ("ThirdScriptExample");
// 加一個函數,定義Trace Sink。
void CourseChange (string context, Ptr<const MobilityModel> model)
{
Vector position = model->GetPosition();// 獲得模型的位置
NS_LOG_UNCOND(context << " x = " << position.x << "y = " << position.y);// 輸出模型的x,y坐标
}
//4.主函數
int
main (int argc, char *argv[])
{
bool verbose = true;
uint32_t nCsma = 3;
uint32_t nWifi = 3;
bool tracing = false;
CommandLine cmd;
cmd.AddValue ("nCsma", "Number of \"extra\" CSMA nodes/devices", nCsma);
cmd.AddValue ("nWifi", "Number of wifi STA devices", nWifi);
cmd.AddValue ("verbose", "Tell echo applications to log if true", verbose);
cmd.AddValue ("tracing", "Enable pcap tracing", tracing);
cmd.Parse (argc,argv);
// The underlying restriction of 18 is due to the grid position
// allocator's configuration; the grid layout will exceed the
// bounding box if more than 18 nodes are provided.
if (nWifi > 18)
{
std::cout << "nWifi should be 18 or less; otherwise grid layout exceeds the bounding box" << std::endl;
return 1;
}
if (verbose)
{//列印指定LOG元件資訊
LogComponentEnable ("UdpEchoClientApplication", LOG_LEVEL_INFO);
LogComponentEnable ("UdpEchoServerApplication", LOG_LEVEL_INFO);
}
//5.建立網絡拓撲
NodeContainer p2pNodes;
p2pNodes.Create (2);//建立兩個p2p節點
PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
NetDeviceContainer p2pDevices;
p2pDevices = pointToPoint.Install (p2pNodes);
NodeContainer csmaNodes;
csmaNodes.Add (p2pNodes.Get (1));
csmaNodes.Create (nCsma);
CsmaHelper csma;
csma.SetChannelAttribute ("DataRate", StringValue ("100Mbps"));
csma.SetChannelAttribute ("Delay", TimeValue (NanoSeconds (6560)));
NetDeviceContainer csmaDevices;
csmaDevices = csma.Install (csmaNodes);
NodeContainer wifiStaNodes;
wifiStaNodes.Create (nWifi);
NodeContainer wifiApNode = p2pNodes.Get (0);
YansWifiChannelHelper channel = YansWifiChannelHelper::Default ();//預設傳播延遲模型,預設損耗模型
YansWifiPhyHelper phy = YansWifiPhyHelper::Default ();//預設誤碼率模型
phy.SetChannel (channel.Create ());
WifiHelper wifi;
wifi.SetRemoteStationManager ("ns3::AarfWifiManager");// wifiRemoteStationManager主要用于wifi的速率控制(rate control)
WifiMacHelper mac;
Ssid = Ssid ("ns-3-ssid");
mac.SetType ("ns3::StaWifiMac",//移動節點
"Ssid", SsidValue (ssid),
"ActiveProbing", BooleanValue (false));
NetDeviceContainer staDevices;//安裝移動節點
staDevices = wifi.Install (phy, mac, wifiStaNodes);
mac.SetType ("ns3::ApWifiMac",//AP節點
"Ssid", SsidValue (ssid));
NetDeviceContainer apDevices;//為AP節點安裝應用
apDevices = wifi.Install (phy, mac, wifiApNode);
MobilityHelper mobility;//移動模型助手類
mobility.SetPositionAllocator ("ns3::GridPositionAllocator",
"MinX", DoubleValue (0.0),//起點坐标(0.0,0.0)
"MinY", DoubleValue (0.0),
"DeltaX", DoubleValue (5.0),//x軸節點間距:5m
"DeltaY", DoubleValue (10.0), //y軸節點間距:10m
"GridWidth", UintegerValue (3),//每行最大節點數
"LayoutType", StringValue ("RowFirst"));
mobility.SetMobilityModel ("ns3::RandomWalk2dMobilityModel",
"Bounds", RectangleValue (Rectangle (-50, 50, -50, 50)));
mobility.Install (wifiStaNodes);//為AP節點設定移動模型
mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
mobility.Install (wifiApNode);
//6.安裝TCP/IP協定族
InternetStackHelper stack;
stack.Install (csmaNodes);
stack.Install (wifiApNode);
stack.Install (wifiStaNodes);
Ipv4AddressHelper address;
address.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer p2pInterfaces;
p2pInterfaces = address.Assign (p2pDevices);
address.SetBase ("10.1.2.0", "255.255.255.0");
Ipv4InterfaceContainer csmaInterfaces;
csmaInterfaces = address.Assign (csmaDevices);
address.SetBase ("10.1.3.0", "255.255.255.0");
address.Assign (staDevices);
address.Assign (apDevices);
//7.安裝應用程式
UdpEchoServerHelper echoServer (9);
ApplicationContainer serverApps = echoServer.Install (csmaNodes.Get (nCsma));
serverApps.Start (Seconds (1.0));
serverApps.Stop (Seconds (10.0));
UdpEchoClientHelper echoClient (csmaInterfaces.GetAddress (nCsma), 9);
echoClient.SetAttribute ("MaxPackets", UintegerValue (1));
echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.0)));
echoClient.SetAttribute ("PacketSize", UintegerValue (1024));
ApplicationContainer clientApps =
echoClient.Install (wifiStaNodes.Get (nWifi - 1));
clientApps.Start (Seconds (2.0));
clientApps.Stop (Seconds (10.0));
//8.設定路由
Ipv4GlobalRoutingHelper::PopulateRoutingTables ();
Simulator::Stop (Seconds (10.0));
//9.資料追蹤
if (tracing == true)
{
pointToPoint.EnablePcapAll ("third");
phy.EnablePcap ("third", apDevices.Get (0));
csma.EnablePcap ("third", csmaDevices.Get (0), true);
}
// 附加:使CourseChange (Trace Sink)和CourseChange (Trace Sources)相關聯的代碼(使用config path子系統,從系統中選取使用者所要使用的Trace Sources)
ostringstream oss;
oss << "/NodeList" << wifiStaNodes.Get(nWifi -1) -> GetId() << "/$ns3::MobilityModel/CourseChange";// "/"後面加的表示一個命名空間,這裡用的為NodeList,即一個仿真中使用的節點的清單。後面是清單的索引,通過調用函數Get()擷取節點,再通過GetId()得到節點的索引ID。當程式遇到$符号時,使調用GetObject()傳回一個對象,需要給出傳回對象的類型,這裡為MobilityModel類,CourseChange屬性(即要追蹤的Tracing Source)。(注:如何确定Config Path:進入API文檔->找到需要的類->Config Path标題下) (nWifi -1表示追蹤n7節點的位置)
Config::Connect(oss.str(), MakeCallback(&CourseChange));// 使用類Config的靜态成員函數Connect将二者關聯起來。函數的第二個參數:使函數CourseChange成為一個回調函數。第一個參數是一個由各種字元組成的字元串。
//10.啟動與結束
Simulator::Run ();
Simulator::Destroy ();
return 0;
}
# 運作
./waf --run scratch/mythird
(3)如何确定Trace Sources
ns3官網->API文檔->Modules->C++Constructs Used by All Modules->The list of all trace sources->找到可以直接使用的Trace Sources。
(4)如何确定Trace Sink
Trace Sink是一個函數,是以要确定其傳回值和參數。看例子中已經寫好的回調函數,例如CourseChange回調函數可以在ns-3.xx/examples/wirless/mixed-wireless.cc中找到一個函數CourseChangeCallback()。