# 10.ns3 路由性能测试实例.md
在本节中,将介绍 ns3
中路由仿真,从路由选择到绘图出结果的一系列流程。
PS:只是本人实验的一系列步骤,不一定是最优做法,但也是一套完整的流程吧,有更好的流程可以互相交流。
# 路由性能好坏的评判标准
通常来说描述一个路由,我们会从 吞吐量,时延,能耗,丢包率,交付率,平均路径长度
等因素来描述路由的好坏。
吞吐量
指的是在单位时间内通过某个网络的实际的数据量。是对实际网络到底有多少数据率在信道上传输。
时延
指的是数据从信源发送到信宿所需的时间。
交付率
指的是发送过程中信宿实际接收的数据包 / 总共发送的数据包。
丢包率
是 1 - 交付率
能耗
指的是一段时间内消耗的能量
路径长度
指的是路由的跳数
# 仿真模拟
为了获取节点收发包的情况,我们需要跟踪设备收发包的情况,这就需要用到 Config
来进行跟踪,
对于 onOffHelper
和 PacketSink
做收发端的情况下,我们可以采用 /NodeList/*/ApplicationList/*/$ns3::PacketSink/Rx
作为 tracking
的地址。
即通过如下方法来绑定 ReceivePacket
作为回调函数
Config::ConnectWithoutContext("/NodeList/*/ApplicationList/*/$ns3::PacketSink/Rx", MakeCallback(&OrrpExample::ReceivePacket, this)); |
而在 ReceivePacket
中,我们又可以通过
类似如下的方法收集已接收的 packet
信息
void OrrpExample::ReceivePacket(Ptr<const Packet> packet, const Address &) | |
{ | |
if ((Simulator::Now() - tmp) < Seconds(1)) | |
{ | |
tmpTotal += packet->GetSize(); | |
} | |
else | |
{ | |
while ((Simulator::Now() - tmp) > Seconds(1)) | |
{ | |
std::cout << tmp.GetSeconds() << "S throughoutput = " << tmpTotal * 8 / (1e6) << "Mbit" << std::endl; | |
std::ostringstream ostrStream; | |
ostrStream << "./result/" << m_protocolName << "Test/" << m_protocolName << "Test-size-" << size << "-seed-" << seed << "-nodesLocationType-" << nodesLocationType << "-nodesMove-" << nodesMove << "-width-" << width << "-step-" << step << "-log"; | |
std::ofstream file(ostrStream.str(), std::ios::app | std::ios::out); | |
file << tmp.GetSeconds() << " " << sendSeq.size() * packet->GetSize() * 8 / (1e6) << " " << bytesTotal * 8 / (1e6) << " " << tmpTotal * 8 / (1e6) << "\n"; | |
file.close(); | |
tmp += Seconds(1); | |
tmpTotal = 0; | |
} | |
tmpTotal += packet->GetSize(); | |
} | |
std::vector<uint32_t>::iterator iter; | |
iter = find(sendSeq.begin(), sendSeq.end(), packet->GetUid()); | |
int index = iter - sendSeq.begin(); | |
bytesTotal += packet->GetSize(); | |
packetsReceived += 1; | |
m_delayEstimation.RecordRx(packet); | |
m_delay += (Simulator::Now() - sendTime[index]).GetSeconds(); | |
m_jitter += m_delayEstimation.GetLastJitter(); | |
if (first_pkt) | |
{ | |
m_firstRx = Simulator::Now(); | |
first_pkt = false; | |
} | |
m_lastRx = Simulator::Now(); | |
} |
并在仿真的最后,调用自定义的 ReportStatistics
进行最后的分析,并存储结果到本地文件
int main(int argc, char **argv) | |
{ | |
OrrpExample test; | |
if (!test.Configure(argc, argv)) | |
{ | |
NS_FATAL_ERROR("Configuration failed. Aborted."); | |
} | |
test.Run(); | |
test.ReportStatistics(); | |
test.Report(std::cout); | |
return 0; | |
} | |
void OrrpExample::ReportStatistics() | |
{ | |
double Dt = m_lastRx.GetSeconds() - m_firstRx.GetSeconds(); | |
double kbs = (bytesTotal * 8.0) / (Dt * 1000); | |
bytesTotal = 0; | |
std::ofstream out(m_CSVfileName.c_str(), std::ios::app); | |
int m_nSinks = 1; | |
out << kbs / m_nSinks << "," | |
<< packetsReceived << "," | |
<< packetsTx << "," | |
<< packetsReceived / (double)packetsTx << "," | |
<< m_delay / packetsReceived << "," | |
<< m_jitter / (packetsReceived * 1000000000.0) << "," | |
// << routingPkts << "," | |
// << m_nSinks << "," | |
// << m_nWifis << "," | |
// << m_protocolName << "," | |
// << m_txrange << "" | |
<< std::endl; | |
std::cout << "吞吐量 " << kbs / m_nSinks << " kbps ," | |
<< "收包数" << packetsReceived << "," | |
<< "发包数" << packetsTx << "," | |
<< "交付率" << packetsReceived / (double)packetsTx << "," | |
<< "时延" << m_delay / packetsReceived << "," | |
<< m_jitter / (packetsReceived * 1000000000.0) << "," | |
<< std::endl; | |
std::ostringstream ostrStream; | |
ostrStream << "./result/" << m_protocolName << "Test/" << m_protocolName << "Test-size-" << size << "-seed-" << seed << "-nodesLocationType-" << nodesLocationType << "-nodesMove-" << nodesMove << "-width-" << width << "-step-" << step << "-delay-log"; | |
std::ofstream file(ostrStream.str(), std::ios::app | std::ios::out); | |
file << packetsReceived / (double)packetsTx << " " << m_delay / packetsReceived << " " << kbs / m_nSinks / 1e3 << "\n"; | |
file.close(); | |
out.close(); | |
packetsReceived = 0; | |
packetsTx = 0; | |
m_delay = 0; | |
m_jitter = 0; | |
// routingPkts = 0; | |
} |
同理我们也可以计算点到点实时的吞吐量
通过添加 Simulator::Schedule (Seconds (6.0), &OrrpExample::CalculateThroughput,this,endTime);
来调用 CalculateThroughput
来计算实时的吞吐量
void OrrpExample::CalculateThroughput(double endTime) | |
{ | |
std::ostringstream ostrStream; | |
ostrStream << "./result/orrpTest/orrpTest-size-" << size << "-seed-" << seed << "-nodesLocationType-" << nodesLocationType << "-nodesMove-" << nodesMove << "-width-" << width << "-step-" << step << "-log"; | |
std::ofstream file; | |
file.open(ostrStream.str(), std::ios_base::app); | |
Time now = Simulator::Now(); | |
double cur = (sink->GetTotalRx() - lastTotalRx) * (double)8 / 1e6; | |
double TotalRx = sink->GetTotalRx() * (double)8 / 1e6; | |
double TotalTx = source->GetTotalTx() * (double)8 / 1e6; | |
file << now.GetSeconds() << " " << TotalTx << " " << TotalRx << " " << cur << "\n"; | |
// std::cout<<now.GetSeconds () << "s 发送数据: \t" <<"send:"<<source->GetTotalTx ()* (double) 8 / 1e6<<"Mbit"<<std::endl; | |
// std::cout<<now.GetSeconds () << "s 接收数据: \t" <<"receive:"<<sink->GetTotalRx ()* (double) 8 / 1e6<<"Mbit"<<std::endl; | |
std::cout << now.GetSeconds() << "s吞吐量: \t" << cur << " Mbit/s" << std::endl; // throughput | |
// std::cout << now.GetSeconds () << cur << std::endl;//throughput | |
lastTotalRx = sink->GetTotalRx(); | |
file.close(); | |
if (now < Seconds(endTime)) | |
// Simulator::Schedule (MilliSeconds (100), &OrrpExample::CalculateThroughput,this,endTime); | |
Simulator::Schedule(Seconds(1), &OrrpExample::CalculateThroughput, this, endTime); | |
} |
详细代码如下所示
#include <vector> | |
#include <iostream> | |
#include <cmath> | |
#include "ns3/aodv-module.h" | |
#include "ns3/orrp-module.h" | |
#include "ns3/orrp2d-helper.h" | |
#include "ns3/core-module.h" | |
#include "ns3/network-module.h" | |
#include "ns3/internet-module.h" | |
#include "ns3/mobility-module.h" | |
#include "ns3/point-to-point-module.h" | |
#include "ns3/v4ping-helper.h" | |
#include "ns3/optical-helper.h" | |
#include "ns3/applications-module.h" | |
// add by yeyu | |
#include "ns3/MyPropagationLossModel.h" | |
#include "ns3/stats-module.h" | |
#include "ns3/netanim-module.h" | |
#include <sstream> | |
#include <string> | |
using namespace ns3; | |
//********************* stats result******************// | |
// 输出结果 | |
// void ReportStatistics (); | |
// send callback | |
void TxPacket(Ptr<const Packet>); | |
// 打印进度 | |
void PrintProgress(double TotalTime); | |
// 接收回调 | |
// void ReceivePacket (Ptr<const Packet> packet, const Address &); | |
uint32_t bytesTotal(0); | |
uint32_t bytesReceivedTotal(0); | |
uint32_t packetsReceived(0); | |
uint32_t packetsTx(0); | |
DelayJitterEstimation m_delayEstimation; | |
double m_delay(0); | |
uint64_t m_jitter(0); | |
bool first_pkt(true); | |
std::string m_CSVfileName("orrpTest-routing-output"); | |
Time m_firstRx; | |
Time m_lastRx; | |
Time tmp; | |
uint32_t tmpTotal(0); | |
std::vector<Time> sendTime; | |
std::vector<uint32_t> sendSeq; | |
//********************* stats result******************// | |
// 接收端应用 | |
Ptr<PacketSink> sink; /* Pointer to the packet sink application */ | |
// 发送端应用 | |
Ptr<OnOffApplication> source; | |
uint64_t lastTotalRx = 0; /* The value of the last total received bytes */ | |
class OrrpExample | |
{ | |
public: | |
OrrpExample(); | |
bool Configure(int argc, char **argv); | |
void Run(); | |
/** | |
* Report results | |
* \param os the output stream | |
*/ | |
void Report(std::ostream &os); | |
void printRoute(double showTime); | |
void CalculateThroughput(double endTime); | |
void PhyRxOkTrace(std::string context, Ptr<const Packet> packet, double snr, WifiMode mode, enum WifiPreamble preamble); | |
void DevTxTrace(std::string context, Ptr<const Packet> packet); | |
void DevRxTrace(std::string context, Ptr<const Packet> packet); | |
void ReceivePacket(Ptr<const Packet> packet, const Address &); | |
void ReportStatistics(); | |
void energyChanged(double oldValue, double newValue); | |
private: | |
// parameters | |
/// 节点数量 | |
uint32_t size; | |
/// 采用网格布局时节点的距离 | |
double step; | |
/// 仿真总时间 (s) | |
double totalTime; | |
/// Write per-device PCAP traces if true | |
bool pcap; | |
/// 是否打印路由表 | |
bool printRoutes; | |
bool nodesMove; | |
double m_energyCost; | |
double m_energyInit; | |
// 节点布局方式 (0: 网格布局;1: 矩形随机布局) | |
int nodesLocationType; | |
// 随机 | |
int seed; | |
int width; | |
// yeyu | |
WifiHelper wifi; | |
std::vector<Ptr<WifiPhy>> m_phyVector; | |
std::string m_protocolName; | |
int m_routingProtocol; | |
NodeContainer nodes; | |
NetDeviceContainer devices; | |
Ipv4InterfaceContainer interfaces; | |
private: | |
void CreateNodes(); | |
void CreateDevices(); | |
void InstallInternetStack(); | |
void InstallApplications(); | |
}; | |
void OrrpExample::ReceivePacket(Ptr<const Packet> packet, const Address &) | |
{ | |
if ((Simulator::Now() - tmp) < Seconds(1)) | |
{ | |
tmpTotal += packet->GetSize(); | |
} | |
else | |
{ | |
while ((Simulator::Now() - tmp) > Seconds(1)) | |
{ | |
std::cout << tmp.GetSeconds() << "S throughoutput = " << tmpTotal * 8 / (1e6) << "Mbit" << std::endl; | |
std::ostringstream ostrStream; | |
ostrStream << "./result/" << m_protocolName << "Test/" << m_protocolName << "Test-size-" << size << "-seed-" << seed << "-nodesLocationType-" << nodesLocationType << "-nodesMove-" << nodesMove << "-width-" << width << "-step-" << step << "-log"; | |
std::ofstream file(ostrStream.str(), std::ios::app | std::ios::out); | |
file << tmp.GetSeconds() << " " << sendSeq.size() * packet->GetSize() * 8 / (1e6) << " " << bytesTotal * 8 / (1e6) << " " << tmpTotal * 8 / (1e6) << "\n"; | |
file.close(); | |
tmp += Seconds(1); | |
tmpTotal = 0; | |
} | |
tmpTotal += packet->GetSize(); | |
} | |
std::vector<uint32_t>::iterator iter; | |
iter = find(sendSeq.begin(), sendSeq.end(), packet->GetUid()); | |
int index = iter - sendSeq.begin(); | |
bytesTotal += packet->GetSize(); | |
packetsReceived += 1; | |
m_delayEstimation.RecordRx(packet); | |
// m_delay += m_delayEstimation.GetLastDelay().GetNanoSeconds(); | |
m_delay += (Simulator::Now() - sendTime[index]).GetSeconds(); | |
m_jitter += m_delayEstimation.GetLastJitter(); | |
// std::cout<<tmp.GetSeconds()<<"s "<<tmpTotal<<"Byte "<<Simulator::Now().GetSeconds()<<"uid:"<<packet->GetUid()<<" received packet delay="<<(Simulator::Now()-sendTime[index]).GetSeconds()<<"s size= "<<packet->GetSize ()<<std::endl; | |
if (first_pkt) | |
{ | |
m_firstRx = Simulator::Now(); | |
first_pkt = false; | |
} | |
m_lastRx = Simulator::Now(); | |
} | |
void TxPacket(Ptr<const Packet> pkt) | |
{ | |
// trace packet | |
packetsTx += 1; | |
m_delayEstimation.PrepareTx(pkt); | |
sendSeq.push_back(pkt->GetUid()); | |
sendTime.push_back(Simulator::Now()); | |
// std::cout<<Simulator::Now().GetSeconds()<<"uid:"<<pkt->GetUid()<<" send"<<std::endl; | |
} | |
void PrintProgress(double TotalTime) | |
{ | |
double now = Simulator::Now().GetSeconds(); | |
NS_LOG_UNCOND("Progress Completed .. " << (now / TotalTime) * 100 << "%"); | |
Simulator::Schedule(Seconds(TotalTime / 100), &PrintProgress, TotalTime); | |
} | |
void OrrpExample::ReportStatistics() | |
{ | |
double Dt = m_lastRx.GetSeconds() - m_firstRx.GetSeconds(); | |
double kbs = (bytesTotal * 8.0) / (Dt * 1000); | |
bytesTotal = 0; | |
std::ofstream out(m_CSVfileName.c_str(), std::ios::app); | |
int m_nSinks = 1; | |
out << kbs / m_nSinks << "," | |
<< packetsReceived << "," | |
<< packetsTx << "," | |
<< packetsReceived / (double)packetsTx << "," | |
<< m_delay / packetsReceived << "," | |
<< m_jitter / (packetsReceived * 1000000000.0) << "," | |
// << routingPkts << "," | |
// << m_nSinks << "," | |
// << m_nWifis << "," | |
// << m_protocolName << "," | |
// << m_txrange << "" | |
<< std::endl; | |
std::cout << "吞吐量 " << kbs / m_nSinks << " kbps ," | |
<< "收包数" << packetsReceived << "," | |
<< "发包数" << packetsTx << "," | |
<< "交付率" << packetsReceived / (double)packetsTx << "," | |
<< "时延" << m_delay / packetsReceived << "," | |
<< m_jitter / (packetsReceived * 1000000000.0) << "," | |
<< std::endl; | |
std::ostringstream ostrStream; | |
ostrStream << "./result/" << m_protocolName << "Test/" << m_protocolName << "Test-size-" << size << "-seed-" << seed << "-nodesLocationType-" << nodesLocationType << "-nodesMove-" << nodesMove << "-width-" << width << "-step-" << step << "-delay-log"; | |
std::ofstream file(ostrStream.str(), std::ios::app | std::ios::out); | |
file << packetsReceived / (double)packetsTx << " " << m_delay / packetsReceived << " " << kbs / m_nSinks / 1e3 << "\n"; | |
file.close(); | |
out.close(); | |
packetsReceived = 0; | |
packetsTx = 0; | |
m_delay = 0; | |
m_jitter = 0; | |
// routingPkts = 0; | |
} | |
int main(int argc, char **argv) | |
{ | |
OrrpExample test; | |
if (!test.Configure(argc, argv)) | |
{ | |
NS_FATAL_ERROR("Configuration failed. Aborted."); | |
} | |
test.Run(); | |
test.ReportStatistics(); | |
test.Report(std::cout); | |
return 0; | |
} | |
//----------------------------------------------------------------------------- | |
OrrpExample::OrrpExample() : size(30), | |
step(40), | |
totalTime(20), | |
pcap(false), | |
printRoutes(true), | |
seed(1), | |
width(size / 5), | |
nodesMove(false), | |
nodesLocationType(0), | |
m_energyInit(1), | |
m_energyCost(0), | |
m_routingProtocol(2), | |
m_protocolName("aodv") | |
{ | |
} | |
bool OrrpExample::Configure(int argc, char **argv) | |
{ | |
// Enable ORRP logs by default. Comment this if too noisy | |
// | |
// LogComponentEnable("OrrpNeighbors", LOG_LEVEL_WARN); | |
// LogComponentEnable("OrrpNeighbors", LOG_LEVEL_WARN); | |
// LogComponentEnable("OrrpRoutingTable", LOG_LEVEL_WARN); | |
LogComponentEnable("Orrp2dRoutingProtocol", LOG_LEVEL_ERROR); | |
LogComponentEnable("Orrp2dNeighbors", LOG_LEVEL_ERROR); | |
// LogComponentEnable("OrrpRoutingProtocol", LOG_LEVEL_ALL); | |
// LogComponentEnable("BasicEnergySource", LOG_LEVEL_ALL); | |
// LogComponentEnable("MyLossModel",LOG_LEVEL_ALL); | |
// LogComponentEnable("YansWifiChannel",LOG_LEVEL_ALL); | |
// LogComponentEnable("MyPacketSink",LOG_LEVEL_ALL); | |
// LogComponentEnable("OrrpRoutingProtocol",LOG_LEVEL_ALL); | |
CommandLine cmd(__FILE__); | |
cmd.AddValue("pcap", "Write PCAP traces.", pcap); | |
cmd.AddValue("printRoutes", "Print routing table dumps.", printRoutes); | |
cmd.AddValue("size", "Number of nodes.", size); | |
cmd.AddValue("time", "Simulation time, s.", totalTime); | |
cmd.AddValue("route", "routing protocol name", m_routingProtocol); | |
cmd.AddValue("step", "Grid step, m", step); | |
cmd.AddValue("seed", "seed", seed); | |
cmd.AddValue("width", "grid width", width); | |
cmd.AddValue("nodesMove", "nodes move?", nodesMove); | |
cmd.AddValue("nodesLocationType", "the type of nodes location", nodesLocationType); | |
cmd.Parse(argc, argv); | |
SeedManager::SetSeed(seed); | |
return true; | |
} | |
void OrrpExample::PhyRxOkTrace(std::string context, Ptr<const Packet> packet, double snr, WifiMode mode, enum WifiPreamble preamble) | |
{ | |
std::cout << "PHYRXOK mode=" << mode << " snr=" << snr << " PacketSize= " << packet->GetSize() << std::endl; | |
} | |
void OrrpExample::DevTxTrace(std::string context, Ptr<const Packet> p) | |
{ | |
std::cout << " TX p size = " << p->GetSize() << std::endl; | |
} | |
void OrrpExample::DevRxTrace(std::string context, Ptr<const Packet> p) | |
{ | |
std::cout << " RX p size = : " << p->GetSize() << std::endl; | |
} | |
void OrrpExample::Run() | |
{ | |
Config::SetDefault("ns3::WifiRemoteStationManager::RtsCtsThreshold", UintegerValue(10)); // enable rts cts all the time. | |
CreateNodes(); | |
CreateDevices(); | |
// Config::Connect ("/NodeList/*/DeviceList/*/Phy/State/RxOk", MakeCallback (&OrrpExample::PhyRxOkTrace,this)); | |
// Config::Connect ("/NodeList/*/DeviceList/*/Mac/MacRx", MakeCallback (&OrrpExample::DevRxTrace,this)); | |
// Config::Connect ("/NodeList/*/DeviceList/*/Mac/MacTx", MakeCallback (&OrrpExample::DevTxTrace,this)); | |
InstallInternetStack(); | |
InstallApplications(); | |
std::cout << "Starting simulation for " << totalTime << " s ...\n"; | |
// 动画显示 | |
AnimationInterface anim("2dTest.xml"); | |
anim.SetMaxPktsPerTraceFile(99999999999999); | |
anim.EnableIpv4RouteTracking("2dTest.route", Seconds(0), Seconds(totalTime), Seconds(1)); | |
Simulator::Stop(Seconds(totalTime)); | |
Simulator::Run(); | |
// Config::Connect ("/NodeList/*/DeviceList/*/Phy/State/RxOk", MakeCallback (&OrrpExample::PhyRxOkTrace2,this)); | |
// Config::Connect ("/NodeList/*/DeviceList/*/Phy/State/RxOk", MakeCallback (&PhyRxOkTrace)); | |
Simulator::Destroy(); | |
} | |
void OrrpExample::Report(std::ostream &) | |
{ | |
} | |
void OrrpExample::CreateNodes() | |
{ | |
std::cout << "Creating " << (unsigned)size << " nodes " << step << " m apart.\n"; | |
nodes.Create(size); | |
// Name nodes | |
for (uint32_t i = 0; i < size; ++i) | |
{ | |
std::ostringstream os; | |
os << "node-" << i; | |
Names::Add(os.str(), nodes.Get(i)); | |
} | |
// Create static grid | |
MobilityHelper mobility; | |
// 节点是否移动 | |
if (nodesMove) | |
{ | |
mobility.SetMobilityModel("ns3::RandomWalk2dMobilityModel", | |
"Mode", StringValue("Time"), | |
"Direction", StringValue("ns3::UniformRandomVariable[Min=0.0|Max=6.283184]"), | |
// "Time", StringValue("0.5s"), | |
"Speed", StringValue("ns3::UniformRandomVariable[Min=0.0|Max=4.0]"), | |
// "Speed", StringValue("ns3::ConstantRandomVariable[Constant=5.0]"), | |
"Bounds", StringValue("0|1000|0|1000")); | |
} | |
// 节点初始部署位置 | |
switch (nodesLocationType) | |
{ | |
case 0: | |
mobility.SetPositionAllocator("ns3::GridPositionAllocator", | |
"MinX", DoubleValue(100.0), | |
"MinY", DoubleValue(100.0), | |
"DeltaX", DoubleValue(step), | |
"DeltaY", DoubleValue(step), | |
"GridWidth", UintegerValue(width), | |
"LayoutType", StringValue("RowFirst")); | |
std::cout << "采用网格布局 width = " << width << std::endl; | |
break; | |
case 1: | |
double tmp = 200; | |
// 设置节点部署在 200*200 米随机位置 | |
mobility.SetPositionAllocator("ns3::RandomBoxPositionAllocator", | |
"X", StringValue("ns3::UniformRandomVariable[Min=0.0|Max=200.0]"), | |
"Y", StringValue("ns3::UniformRandomVariable[Min=0.0|Max=200.0]"), | |
"Z", StringValue("ns3::UniformRandomVariable[Min=0.0|Max=0.0]")); | |
std::cout << "采用200*200随机2维部署" << std::endl; | |
break; | |
} | |
mobility.Install(nodes); | |
} | |
void singleDirectionSend(WifiHelper wifi, double transmitDirectAngel, double theta) | |
{ | |
std::vector<Ptr<WifiPhy>> m_phyVector = wifi.getPhyVector(); | |
for (uint32_t i = 0; i < m_phyVector.size(); i++) | |
{ | |
m_phyVector[i]->setTransmitMode(1); | |
m_phyVector[i]->setTransmitDirectAngel(transmitDirectAngel); | |
m_phyVector[i]->setTheta(theta); | |
} | |
} | |
void fourDirectionSend(WifiHelper wifi, double pianzhuanAngel, double angel) | |
{ | |
std::vector<Ptr<WifiPhy>> m_phyVector = wifi.getPhyVector(); | |
for (uint32_t i = 0; i < m_phyVector.size(); i++) | |
{ | |
m_phyVector[i]->setTransmitDirectAngel(pianzhuanAngel); | |
m_phyVector[i]->setTheta(angel); | |
} | |
} | |
void twoDirectionSend(WifiHelper wifi, double transmitDirectAngel, double angel) | |
{ | |
std::vector<Ptr<WifiPhy>> m_phyVector = wifi.getPhyVector(); | |
for (uint32_t i = 0; i < m_phyVector.size(); i++) | |
{ | |
m_phyVector[i]->setTransmitMode(2); | |
m_phyVector[i]->setTransmitDirectAngel(transmitDirectAngel); | |
m_phyVector[i]->setTheta(angel); | |
} | |
} | |
void OrrpExample::CreateDevices() | |
{ | |
WifiMacHelper wifiMac; | |
wifiMac.SetType("ns3::AdhocWifiMac"); | |
OpticalPhyHelper opticalPhy = OpticalPhyHelper::Default(); | |
OpticalChannelHelper opticalChannel = OpticalChannelHelper::Default(); | |
// add loss | |
// Ptr<MyPropagationLossModel> lossModel=CreateObject<MyPropagationLossModel>(); | |
// lossModel->SetCLamada(0.151); | |
// Ptr<YansWifiChannel> myChannel=wifiChannel.Create(); | |
// myChannel->SetPropagationLossModel(lossModel); | |
opticalPhy.SetChannel(opticalChannel.Create()); | |
opticalPhy.Set("TxPowerStart", DoubleValue(16.0206)); | |
opticalPhy.Set("TxPowerEnd", DoubleValue(16.0206)); | |
opticalPhy.Set("TxPowerLevels", UintegerValue(1)); | |
// opticalPhy.Set("TxGain", DoubleValue(1)); | |
// opticalPhy.Set("RxGain", DoubleValue(1)); | |
// opticalPhy.Set("RxSensitivity", DoubleValue(-96)); | |
// opticalPhy.Set("CcaEdThreshold", DoubleValue(-99)); | |
// wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager", "DataMode", StringValue ("OfdmRate6Mbps"), "RtsCtsThreshold", UintegerValue (0)); | |
// wifi.SetRemoteStationManager ("ns3::MinstrelHtWifiManager"); | |
devices = wifi.Install(opticalPhy, wifiMac, nodes); | |
// create trace file | |
// AsciiTraceHelper ascii; | |
// wifiPhy.EnableAscii(ascii.CreateFileStream ("orrp.tr"),nodes); | |
} | |
void OrrpExample::printRoute(double showTime) | |
{ | |
Ptr<OutputStreamWrapper> routingStream = Create<OutputStreamWrapper>("ArouteTest.routes", std::ios::out); | |
orrp.PrintRoutingTableAllAt(Seconds(showTime), routingStream); | |
} | |
void OrrpExample::InstallInternetStack() | |
{ | |
// you can configure ORRP attributes here using orrp.Set(name, value) | |
InternetStackHelper stack; | |
switch (m_routingProtocol) | |
{ | |
case 2: | |
{ | |
Orrp2dHelper orrp; | |
std::ostringstream os; | |
os << "10.0.0." << size; | |
orrp.m_dst = Ipv4Address(os.str().c_str()); | |
orrp.m_origin = Ipv4Address("10.0.0.1"); | |
stack.SetRoutingHelper(orrp); // has effect on the next Install () | |
m_protocolName = "orrp2d"; | |
std::cout << "used orrp2d routing proto" << std::endl; | |
if (printRoutes) | |
{ | |
Ptr<OutputStreamWrapper> routingStream = Create<OutputStreamWrapper>("2dTest.routes", std::ios::out); | |
orrp.PrintRoutingTableAllAt(Seconds(totalTime - 0.2), routingStream); | |
} | |
} | |
break; | |
case 1: | |
{ | |
OrrpHelper orrp; | |
stack.SetRoutingHelper(orrp); // has effect on the next Install () | |
m_protocolName = "orrp"; | |
std::cout << "used orrp routing proto" << std::endl; | |
if (printRoutes) | |
{ | |
Ptr<OutputStreamWrapper> routingStream = Create<OutputStreamWrapper>("orrpTest.routes", std::ios::out); | |
orrp.PrintRoutingTableAllAt(Seconds(totalTime - 0.2), routingStream); | |
} | |
} | |
break; | |
case 0: | |
{ | |
AodvHelper aodv; | |
stack.SetRoutingHelper(aodv); // has effect on the next Install () | |
m_protocolName = "aodv"; | |
std::cout << "used aodv routing proto" << std::endl; | |
if (printRoutes) | |
{ | |
Ptr<OutputStreamWrapper> routingStream = Create<OutputStreamWrapper>("aodvTest.routes", std::ios::out); | |
aodv.PrintRoutingTableAllAt(Seconds(totalTime - 0.2), routingStream); | |
} | |
} | |
break; | |
} | |
// OrrpHelper orrp; | |
// stack.SetRoutingHelper (orrp); // has effect on the next Install () | |
stack.Install(nodes); | |
Ipv4AddressHelper address; | |
address.SetBase("10.0.0.0", "255.0.0.0"); | |
interfaces = address.Assign(devices); | |
} | |
void OrrpExample::CalculateThroughput(double endTime) | |
{ | |
/* | |
std::ostringstream ostrStream; | |
ostrStream << "./result/orrpTest/orrpTest-size-"<<size<<"-seed-"<<seed<<"-nodesLocationType-"<<nodesLocationType<<"-nodesMove-"<<nodesMove<<"-width-"<<width<<"-step-"<<step<<"-log"; | |
std::ofstream file; | |
file.open (ostrStream.str (),std::ios_base::app); | |
Time now = Simulator::Now (); | |
double cur = (sink->GetTotalRx () - lastTotalRx) * (double) 8 / 1e6; | |
double TotalRx=sink->GetTotalRx ()* (double) 8 / 1e6; | |
double TotalTx=source->GetTotalTx ()* (double) 8 / 1e6; | |
file<<now.GetSeconds ()<<""<<TotalTx<<" "<<TotalRx<<" "<<cur<<"\n"; | |
// std::cout<<now.GetSeconds () << "s 发送数据: \t" <<"send:"<<source->GetTotalTx ()* (double) 8 / 1e6<<"Mbit"<<std::endl; | |
// std::cout<<now.GetSeconds () << "s 接收数据: \t" <<"receive:"<<sink->GetTotalRx ()* (double) 8 / 1e6<<"Mbit"<<std::endl; | |
std::cout << now.GetSeconds () << "s 吞吐量: \t" << cur << "Mbit/s" << std::endl;//throughput | |
//std::cout << now.GetSeconds () << cur << std::endl;//throughput | |
lastTotalRx = sink->GetTotalRx (); | |
file.close (); | |
if (now<Seconds (endTime)) | |
// Simulator::Schedule (MilliSeconds (100), &OrrpExample::CalculateThroughput,this,endTime); | |
Simulator::Schedule (Seconds (1), &OrrpExample::CalculateThroughput,this,endTime); | |
*/ | |
} | |
void writeData() | |
{ | |
/* | |
std::vector<Time> sendTime=source->getSendTimeList (); | |
std::vector<Time> receiveTime=sink->getReceiveTimeList (); | |
std::vector<uint32_t> sendSeq=source->getSendSeqList (); | |
std::vector<uint32_t> receiveSeq=sink->getReceiveSeqList (); | |
Time now = Simulator::Now (); | |
double TotalRx=sink->GetTotalRx ()* (double) 8 / 1e6; | |
double TotalTx=source->GetTotalTx ()* (double) 8 / 1e6; | |
double avgThroughput=TotalRx/(sendTime [sendTime.size ()-1]-sendTime [0]).GetSeconds (); | |
std::vector<Time> delayList; | |
delayList.insert (delayList.begin (),sendTime.size (),Time ()); | |
Time totalDelay=Time (); | |
for (uint32_t i=0;i<receiveTime.size ();i++){ | |
int seq=receiveSeq [i]; | |
delayList [seq]=receiveTime [i]-sendTime [seq]; | |
std::cout<<"序列号:"<<seq<<"的包时延是"<<delayList [seq].GetSeconds ()<<"S"<<std::endl; | |
totalDelay+=delayList [seq]; | |
} | |
//output to file | |
std::ofstream file; | |
file.open ("./result/orrpTest/orrpTest-delay-log",std::ios_base::app); | |
file<<(double) receiveTime.size ()/sendTime.size ()<<""<<(totalDelay/receiveTime.size ()).GetSeconds ()<<" "<<avgThroughput<<"\n"; | |
std::cout<<"丢包率:"<<1-(double) receiveTime.size ()/sendTime.size ()<<std::endl; | |
std::cout<<"平均时延:"<<(totalDelay/receiveTime.size ()).GetSeconds ()<<std::endl; | |
std::cout<<"平均吞吐量:"<<avgThroughput<<std::endl; | |
*/ | |
/* | |
std::cout<<"数据包发送和接收时间"<<std::endl; | |
for (uint32_t i = 0; i < sendTime.size (); i++) | |
{ | |
std::cout<<sendTime [i].GetSeconds ()<<"S 发送了一个数据包"<<"序列号是"<<sendSeq [i]<<std::endl; | |
} | |
for (uint32_t i = 0; i < receiveTime.size (); i++){ | |
std::cout<<receiveTime [i].GetSeconds ()<<"S 接收了一个数据包"<<"序列号是"<<receiveSeq [i]<<std::endl; | |
} | |
*/ | |
} | |
void OrrpExample::InstallApplications() | |
{ | |
std::string dataRate = "1Mbps"; // size of packet, 5/8*1024*1024/1472 | |
// std::string dataRate = "1Mbps"; | |
PacketSinkHelper sinkHelper("ns3::UdpSocketFactory", InetSocketAddress(Ipv4Address::GetAny(), 9)); | |
// sinkHelper.SetAttribute("EnableSeqTsSizeHeader",BooleanValue (true)); | |
// 目的节点 ->sinkApp | |
ApplicationContainer sinkApp = sinkHelper.Install(nodes.Get(size - 1)); | |
sink = StaticCast<PacketSink>(sinkApp.Get(0)); | |
Address remoteAddress; | |
remoteAddress = InetSocketAddress(interfaces.GetAddress(size - 1), 9); | |
/* Install TCP/UDP Transmitter on the station */ | |
OnOffHelper sourceHelper("ns3::UdpSocketFactory", Address()); | |
// OnOffHelper sourceHelper ("ns3::UdpSocketFactory", (InetSocketAddress (interfaces.GetAddress (size-1), 9))); | |
sourceHelper.SetAttribute("Remote", AddressValue(remoteAddress)); | |
sourceHelper.SetAttribute("PacketSize", UintegerValue(256)); | |
sourceHelper.SetAttribute("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1]")); | |
sourceHelper.SetAttribute("OffTime", StringValue("ns3::ConstantRandomVariable[Constant=0]")); | |
sourceHelper.SetAttribute("DataRate", DataRateValue(DataRate(dataRate))); | |
sourceHelper.SetAttribute("EnableSeqTsSizeHeader", BooleanValue(true)); | |
// 发送节点 ->sourceHelperApp | |
ApplicationContainer sourceApp = sourceHelper.Install(nodes.Get(0)); | |
sourceApp.Get(0)->TraceConnectWithoutContext("Tx", MakeCallback(&TxPacket)); | |
source = StaticCast<OnOffApplication>(sourceApp.Get(0)); | |
// 接收应用启动时间 | |
sinkApp.Start(Seconds(3.0)); | |
// 发送应用启动时间 | |
sourceApp.Start(Seconds(3.0)); | |
Config::ConnectWithoutContext("/NodeList/*/ApplicationList/*/$ns3::PacketSink/Rx", MakeCallback(&OrrpExample::ReceivePacket, this)); | |
// progress | |
Simulator::Schedule(Seconds(totalTime / 100), &PrintProgress, totalTime); | |
// Simulator::Schedule (Seconds (6.0), &OrrpExample::CalculateThroughput,this,totalTime-0.5); | |
// Simulator::Schedule(Seconds(totalTime)-Seconds(0.1),&writeData); | |
sinkApp.Stop(Seconds(totalTime) - Seconds(0.2)); | |
sourceApp.Stop(Seconds(totalTime) - Seconds(2)); | |
// printRoute(1.02017); | |
} |
# 结果分析
从上述的代码也可以看出 ns3
的仿真结果可以输出到文件,所以我们可以对文件进行操作,获取想要的结果并生成对应的图像
# gawk 统计
我们可以通过 gawk
来统计文件中数据的均值以做分析。
cat fillName | awk '{if($8!="-nan"){sum+=$5;size=$2+2;n+=1;delay+=$6;cost+=$7;path+=$8}} END {print "Pdr=",sum/n,"reachable =",n/NR,"energyCost=",cost*size/n,"avgCost=",cost/n,"pathLength=",path/n,"delay=",delay/n,"\n",sum/n,"\t",n/NR,"\t",cost*size/n,"\t",cost/n"\t",path/n,"\t",delay/n}' |
事实上同样的场景需要做多次,所以我们可以通过 shell
来进行 seed
等变量的改变,然后通过另一个 shell
脚本进行统计
运行脚本例子如下所示:
#!/bin/bash | |
NODES=(75 100 125 150) | |
INTERFACE=(12) | |
ROUTEPROTO=(3 4 0 2) | |
SEEDS=$(seq 500) | |
NODESMOVE=(1) | |
RANGE=250 | |
NODESLOCATIONTYPE=1 | |
TRIALS=1 | |
TOTALTIMES=60 | |
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:bin/ | |
for interNum in ${INTERFACE[@]} | |
do | |
for nodeMove in ${NODESMOVE[@]} | |
do | |
for range in ${RANGE[@]} | |
do | |
for size in ${NODES[@]} | |
do | |
for proto in ${ROUTEPROTO[@]} | |
do | |
for seed in ${SEEDS[@]} | |
do | |
./waf -v --run "25dTest --nodeSize=$size --nodesMove=$nodeMove --nodesLocationType=$NODESLOCATIONTYPE --seed=$seed --time=$TOTALTIMES --range=$range --route=$proto --interfaceNum=$interNum" | |
echo a task has done | |
# sleep $TOTALTIMES | |
done | |
done | |
done | |
done | |
done | |
done |
awk 统计例子如下所示:
#!/bin/bash | |
NODES=(75 100 125 150) | |
INTERFACE=(8) | |
RANGE=(50) | |
TOTALTIMES=60 | |
ROUTEPROTO=(5) | |
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:bin/ | |
echo $1 | |
IFS=$(echo -en "\n\b")#注意这里 \n 前面没有空格 | |
for interNum in ${INTERFACE[@]}; do | |
for range in ${RANGE[@]}; do | |
for size in ${NODES[@]}; do | |
for proto in ${ROUTEPROTO[@]}; do | |
pname="" | |
case $proto in | |
0) | |
pname="VBF实验结果" | |
resFile="VBF" | |
;; | |
1) | |
pname="CORRP实验结果" | |
resFile="CORRP" | |
;; | |
2) | |
pname="HH VBF实验结果" | |
resFile="HH-VBF" | |
;; | |
3) | |
pname="o orrp实验结果" | |
resFile="ORRP" | |
;; | |
4) | |
pname="vorrp实验结果" | |
resFile="VORR" | |
;; | |
5) | |
pname="R-orrp实验结果" | |
resFile="RORR" | |
;; | |
esac | |
#echo $RANGE"m 范围 -"$size"节点 -"$interNum"interfaceNum-"$TOTALTIMES"S"--$pname | |
#cat $RANGE"m 范围 -"$size"节点 -"$interNum"interfaceNum-"$TOTALTIMES"S"--${pname} | awk '{if ($8!="-nan"){sum+=$5;size=$2+2;n+=1;delay+=$6;cost+=$7;path+=$8}} END {print "Pdr=",sum/n,"reachable =",n/NR,"energyCost=",cost*size/n,"avgCost=",cost/n,"pathLength=",path/n,"delay=",delay/n,"\n",sum/n,"\t",n/NR,"\t",cost*size/n,"\t",cost/n"\t",path/n,"\t",delay/n}' | |
cat $RANGE"m范围-"$size"节点-"$interNum"interfaceNum-"$TOTALTIMES"S"--${pname} | awk '{if($8!="-nan"){sum+=$5;size=$2+2;n+=1;delay+=$6;cost+=$7;path+=$8}} END {print size-2,"\t",sum/n,"\t",n/NR,"\t",cost*size/n,"\t",cost/n"\t",path/n,"\t",delay/n}'>>${resFile}.txt | |
#echo a task has done | |
echo a task has done | |
done | |
done | |
done | |
done | |
IFS=$(echo -en " \n\t")#注意这里 \n 前面有个空格 | |
echo "end" |
# gnuplot 绘制结果图
我们可以采用类似于这样的脚本来绘制图像
set style line 80 lt rgb "#000000" lw 5
set style line 81 lt 0 # dashed
set style line 81 lt rgb "#000000" # grey
set grid back linestyle 81
set ytics 0.1
set xtics 5
set style line 1 lt rgb "#00A000" lw 2 pt 9 pointsize 2
set style line 2 lt rgb "#A00000" lw 2 pt 11 pointsize 2
set style line 3 lt rgb "#5060D0" lw 2 pt 1 pointsize 2
set style line 4 lt rgb "#F25900" lw 2 pt 2 pointsize 2
set style line 5 lt rgb "#A00000" lw 1 pt 8 pointsize 2
set style line 6 lt rgb "#00A000" lw 1 pt 2 pointsize 2
set style line 7 lt rgb "#5060D0" lw 1 pt 4 pointsize 2
set style line 8 lt rgb "#F25900" lw 1 pt 6 pointsize 2
#set output ".pdf"
set xlabel "Numbers of nodes" font ",20"
set ylabel "Packet delivery ratio(%)" font ",20" offset 1.5,0,0
set key at 85,0.4 font ",20" height 0.9 width 0.5 spacing 1
set key box
set xrange [40:90]
set yrange [0:1]
plot "0.5-20-15-orrp2d.txt" u 1:2 title "RR" w lp ls 2, "0.5-20-15-o-orrp.txt" u 1:2 title "ORRP" w lp ls 1, "0.5-20-15-R-ORR.txt" u 1:2 title " R-ORR" w lp ls 7, "v-orrp.txt" u 1:2 title " V-ORR" w lp ls 8
set terminal postscript eps color solid linewidth 2 "Helvetica" 20
set output "pdr.eps"
replot
set output