NS-3概述
NS-3(Network Simulator 3)是一个用于仿真网络的开源软件工具,主要用于研究和教学。NS-3的设计目标是提供一个灵活、可扩展的平台,以支持各种网络协议和应用的仿真。与早期的网络仿真工具(如NS-2)相比,NS-3在设计上更加现代化,使用C++和Python编写,支持多线程和并行仿真,具有更高的性能和更丰富的功能。
NS-3的历史与发展
NS-3项目始于2005年,由Dartmouth College的George F. Hines和Tom Henderson等人发起。NS-3的设计初衷是解决NS-2中存在的问题,如代码复杂性、性能瓶颈和扩展性不足。随着时间的推移,NS-3逐渐成为网络仿真领域的重要工具,得到了广泛的使用和贡献。目前,NS-3由一个活跃的社区维护,不断更新和改进,以适应新的网络技术和研究需求。
NS-3的主要特点
- 灵活性和可扩展性 :NS-3的设计允许用户轻松添加新的模块和协议,支持模块化的仿真。
- 高性能 :NS-3使用C++编写,支持多线程仿真,可以处理大规模网络仿真任务。
- 丰富的模块 :NS-3提供了多种网络仿真模块,包括物理层、链路层、网络层、传输层和应用层等。
- 详细的文档和社区支持 :NS-3拥有详细的文档和活跃的社区,用户可以轻松获取帮助和资源。
- 跨平台支持 :NS-3可以在多种操作系统上运行,包括Linux、Windows和macOS。
NS-3的应用场景
NS-3广泛应用于以下领域:
- 无线通信 :包括Wi-Fi、LTE、5G等无线网络技术的仿真。
- 网络协议研究 :如TCP、UDP、路由协议等。
- 网络安全 :仿真攻击和防御策略。
- 物联网 :研究和测试IoT设备和网络。
- 车联网 :仿真V2V和V2I通信。
基于FlowMonitor 实现:统计包时延、丢包率、流完成时间(FCT)、流吞吐量、网络吞吐量指标
lowMonitor是NS-3中的一个模块,用于监视网络流量,并收集关于数据流的各种统计数据。这些统计数据可以用来评估网络协议或应用的性能。FlowMonitor提供了统一的接口来访问流量相关的度量,如吞吐量、时延、丢包率等。
平均包时延统计函数
平均包时延统计的原理是遍历FlowMonitor统计的每一条流,其中记录的流中每个包时延信息的总和在it.second.delaySum中,累加记录到delaySum中,将它除以每条流的接收数据包的数目it.second.rxPackets的总和packetnum,可以得到总的平均包时延。
void ComputePacketDelay(Ptr<FlowMonitor> fm)
{
// 获取统计结果
FlowMonitor::FlowStatsContainer flowStats = fm->GetFlowStats();
//fm->GetFlowStats() 获取 FlowMonitor 的统计数据,它返回一个 FlowStatsContainer,这个容器包含了网络中每个流的统计信息
double delaySum = 0.0;
int packetnum = 0;
// 计算每个流的数据包时延
for (auto it : flowStats)
{
if (it.second.txPackets > 0 && it.second.rxPackets > 0)
{
// 计算平均时延
packetnum += it.second.rxPackets;
delaySum += it.second.delaySum.GetSeconds();
}
}
double overallAverageDelay = delaySum / packetnum * 1000;
// 计算总体平均包时延
std::cout << "Overall Average Packet Delay: " << overallAverageDelay << " ms" << std::endl;
}
每个流的平均时延是指该流中所有接收到的数据包的平均延迟。它是对单个流的性能进行评估,反映了特定数据流从发送端到接收端的传输延迟。每个流的平均时延是根据该流的发送和接收的数据包进行计算的。
对于每个流,平均时延可以通过以下方式计算:
$$ 平均时延=接收到的数据包数/所有接收包的总延迟 $$//计算单个流的平均时延
double avgDelay = it.second.delaySum.GetSeconds() / it.second.rxPackets * 1000; // 单个流的平均时延(毫秒)
std::cout << "Flow " << it.first << " 平均时延: " << avgDelay << " ms" << std::endl;
在main函数中的具体使用方法:
FlowMonitorHelper fmHelper; // 创建一个 FlowMonitorHelper 对象
Ptr<FlowMonitor> fm = fmHelper.InstallAll(); // 安装 FlowMonitor 到所有节点
Simulator::Stop (Seconds(1500));
Simulator::Run ();
Simulator::Destroy ();
//统计函数
ComputePacketDelay(fm);
return 0;
在仿真开始之前,我们需要安装 FlowMonitor 来监控网络中的流量,通过 InstallAll() 安装的 FlowMonitor 会在仿真过程中实时监控流量,一直到仿真结束。
FlowMonitorHelper fmHelper:这是一个帮助类,用来简化FlowMonitor的安装过程。fmHelper.InstallAll():该方法会在仿真中 所有节点 上安装FlowMonitor。它会开始收集网络中所有流的统计数据,包括每个流的传输包、丢失包、延迟等。fm:这是在仿真开始前安装的FlowMonitor,它包含了所有流的统计信息。ComputePacketDelay(fm):这个函数会访问FlowMonitor中保存的流量数据,并计算并输出每个流的平均时延或其他相关统计结果。
丢包率统计函数
丢包率统计函数的原理是遍历FlowMonitor统计的每一条流,其中记录的流中发送包的数目在it.second.txPackets中,减去记录的被接收的包数量it.second.rxPackets即可得到丢包数目,除以总发包数即为丢包率。
void ComputePacketLossRate(Ptr<FlowMonitor> fm)
{
// 获取统计结果
FlowMonitor::FlowStatsContainer flowStats = fm->GetFlowStats();
uint32_t totalSentPackets = 0;
uint32_t totalReceivedPackets = 0;
// 计算每个流的数据包发送和接收数量
for (auto it : flowStats)
{
if (it.second.txPackets > 0)
{
totalSentPackets += it.second.txPackets;
totalReceivedPackets += it.second.rxPackets;
}
}
// 计算丢包率
uint32_t lostPackets = totalSentPackets - totalReceivedPackets;
double packetLossRate = static_cast<double>(lostPackets) / totalSentPackets * 100.0;
std::cout << "Total Sent Packets: " << totalSentPackets << std::endl;
// std::cout << "Total Received Packets: " << totalReceivedPackets << std::endl;
// std::cout << "Lost Packets: " << lostPackets << std::endl;
std::cout << "Packet Loss Rate: " << packetLossRate << "%" << std::endl;
}
流完成时间统计函数
流完成时间统计函数的原理是遍历FlowMonitor统计的每一条流,其中记录的流中收到最后一个包it.second.timeLastRxPacket减去第一个包发送的时间it.second.timeFirstTxPacket可以得到流完成时间。
void ComputeFlowCompleteTime(FlowMonitorHelper &fmHelper, Ptr<FlowMonitor> fm)
{
// 获取统计结果
FlowMonitor::FlowStatsContainer flowStats = fm->GetFlowStats();
// 计算完成时间
double totalThroughput = 0.0;
double fct = 0;
int validFlows = 0;
for (auto it : flowStats)
{
if (it.second.txBytes > 0)
{
fct += (it.second.timeLastRxPacket - it.second.timeFirstTxPacket).GetSeconds ()*1e3;//单位为毫秒
validFlows++;
}
}
std::cout << "FCT: " << fct/validFlows << " ms" << std::endl;
}
流吞吐量统计函数
流吞吐量统计函数的原理是遍历FlowMonitor统计的每一条流,其中记录的流中收到最后一个包it.second.timeLastRxPacket减去第一个包发送的时间it.second.timeFirstTxPacket可以得到流完成时间,用流的接收数据量it.second.rxBytes(单位是B字节,记得乘以8换算成bytes)除以流完成时间,即可得到流吞吐量。
void ComputeFlowThroughput(FlowMonitorHelper &fmHelper, Ptr<FlowMonitor> fm)
{
// 获取统计结果
FlowMonitor::FlowStatsContainer flowStats = fm->GetFlowStats();
// 计算总吞吐量
double totalThroughput = 0.0;
int validFlows = 0;
for (auto it : flowStats)
{
if (it.second.txBytes > 0)
{
// 确保时间间隔非零
Time duration = it.second.timeLastRxPacket - it.second.timeFirstTxPacket;
if (duration.GetSeconds() > 0)
{
double throughput = it.second.rxBytes * 8.0 / duration.GetSeconds() / 1024 / 1024; // 比特转换为Mbps
totalThroughput += throughput;
//std::cout << "Flow ID: " << it.first << ", Throughput: " << throughput << " Mbps" << std::endl;
}
validFlows++;
}
}
std::cout << "Total Network Throughput: " << totalThroughput << " Mbps" << std::endl;
std::cout << "Avg Network Throughput: " << totalThroughput/validFlows << " Mbps" << std::endl;
}
网络吞吐量指标
网络吞吐量一般被定义为网络单位时间内接收到的数据量,首先统计接收总数据量,是流接收量it.second.rxBytes的累加,之后计算最大的it.second.timeLastRxPacket,为网络收到最后一个包的时间,总接收量除以完成时间即可得到网络吞吐量。
void ComputeNetThroughput(FlowMonitorHelper &fmHelper, Ptr<FlowMonitor> fm)
{
// 获取统计结果
FlowMonitor::FlowStatsContainer flowStats = fm->GetFlowStats();
// 计算总吞吐量
double totalrxbyte = 0.0;
double lastfct = 0;
for (auto it : flowStats)
{
if (it.second.txBytes > 0)
{
// 确保时间间隔非零
Time duration = it.second.timeLastRxPacket - it.second.timeFirstTxPacket;
if (duration.GetSeconds() > 0)
{
double rxbyte = it.second.txBytes * 8.0; // 比特
totalrxbyte += rxbyte;
}
if(it.second.timeLastRxPacket.GetSeconds() > lastfct){
lastfct = it.second.timeLastRxPacket.GetSeconds();
//lastfct 用于记录最后一个接收包的时间。这里通过 timeLastRxPacket.GetSeconds() 获取流的最后接收时间,并更新 lastfct
}
}
}
std::cout << "Network Throughput: " << totalrxbyte/lastfct/1024/1024 << "Mbps" << std::endl;
}
在计算吞吐量时,使用 timeLastRxPacket 作为 流的持续时间 是因为:
- 网络吞吐量的定义 是单位时间内传输的数据量。因此,我们需要知道流 实际传输数据的时长,即从开始传输到所有数据接收完成的时间。
- 最后接收到的包 表示流传输的 结束时刻,它标志着数据传输的完整性。没有收到最后一个包,就意味着数据流传输未完全结束,吞吐量也无法计算