NS3仿真——sixth
·
sixth是一个完整的TCP拥塞控制算法对比工具,对比三种算法:Cubic、NewReno、Vegas。
一、代码整体架构
1.1 头文件引入
#include "ns3/applications-module.h" // 应用程序模块(UDP/TCP应用)
#include "ns3/core-module.h" // 核心模块(时间、事件调度等)
#include "ns3/internet-module.h" // 网络协议栈模块(TCP/IP)
#include "ns3/network-module.h" // 网络设备模块
#include "ns3/point-to-point-module.h"// 点对点链路模块
#include <fstream> // 文件流操作
#include <iostream> // 输入输出流
#include <vector> // 动态数组容器
#include <map> // 关联数组容器
#include <iomanip> // 输出格式控制
#include <algorithm> // 算法函数(排序等)
二、数据结构设计
2.1 AlgorithmStats结构体 - 算法统计信息
struct AlgorithmStats {
std::string name; // 算法名称
std::vector<double> timePoints; // 时间点数组
std::vector<uint32_t> cwndValues; // 对应时间的CWND值数组
double startTime; // 第一个数据点时间
double endTime; // 最后一个数据点时间
uint32_t maxCwnd; // 最大CWND值
uint32_t minCwnd; // 最小CWND值
double avgCwnd; // 平均CWND值
double finalCwnd; // 最终CWND值
double growthRate; // 增长率(bytes/s)
int dataPoints; // 数据点数量
// 构造函数
AlgorithmStats() : name(""), startTime(0), endTime(0),
maxCwnd(0), minCwnd(UINT32_MAX),
avgCwnd(0), finalCwnd(0),
growthRate(0), dataPoints(0) {}
AlgorithmStats(const std::string& n) : name(n), startTime(0), endTime(0),
maxCwnd(0), minCwnd(UINT32_MAX),
avgCwnd(0), finalCwnd(0),
growthRate(0), dataPoints(0) {}
// 添加数据点的方法
void AddDataPoint(double time, uint32_t cwnd) {
timePoints.push_back(time); // 记录时间
cwndValues.push_back(cwnd); // 记录CWND值
if (dataPoints == 0) {
startTime = time; // 设置开始时间
}
endTime = time; // 更新结束时间
maxCwnd = std::max(maxCwnd, cwnd); // 更新最大值
minCwnd = std::min(minCwnd, cwnd); // 更新最小值
finalCwnd = cwnd; // 更新最终值
dataPoints++; // 数据点计数
// 计算平均CWND
double sum = 0;
for (uint32_t val : cwndValues) {
sum += val;
}
avgCwnd = sum / cwndValues.size();
// 计算增长率(基于最近10个点)
if (cwndValues.size() >= 10) {
double recentGrowth = 0;
for (size_t i = cwndValues.size() - 10; i < cwndValues.size() - 1; i++) {
double timeDiff = timePoints[i+1] - timePoints[i];
if (timeDiff > 0) {
recentGrowth += (cwndValues[i+1] - cwndValues[i]) / timeDiff;
}
}
growthRate = recentGrowth / 9.0; // 取平均增长率
}
}
};
2.2 全局数据结构
// 全局存储算法统计数据
std::map<std::string, AlgorithmStats> algorithmStats;
三、回调函数设计
3.1 Cubic算法的CWND变化回调
static void
CwndChangeCubic(uint32_t oldCwnd, uint32_t newCwnd)
{
double currentTime = Simulator::Now().GetSeconds();
algorithmStats["Cubic"].AddDataPoint(currentTime, newCwnd);
static double lastPrintTime = 0; // 静态变量,记录上次打印时间
if (currentTime - lastPrintTime >= 2.0) { // 每2秒打印一次
std::cout << std::fixed << std::setprecision(2)
<< "Cubic @ " << currentTime << "s: "
<< "CWND=" << newCwnd << " bytes ("
<< std::setprecision(1) << newCwnd/1024.0 << " KB)" << std::endl;
lastPrintTime = currentTime;
}
}
3.2 NewReno和Vegas的回调
// NewReno回调(结构相同,输出名称不同)
static void
CwndChangeNewReno(uint32_t oldCwnd, uint32_t newCwnd)
{
// 同上,但操作algorithmStats["NewReno"]
}
// Vegas回调
static void
CwndChangeVegas(uint32_t oldCwnd, uint32_t newCwnd)
{
// 同上,但操作algorithmStats["Vegas"]
}
四、自定义应用类 TcpCwndApp
4.1 类定义
class TcpCwndApp : public Application // 继承自ns3::Application
{
public:
TcpCwndApp();
virtual ~TcpCwndApp();
void Setup(Ptr<Socket> socket, Address address, uint32_t packetSize,
DataRate dataRate); // 配置应用参数
private:
virtual void StartApplication(void); // 应用启动
virtual void StopApplication(void); // 应用停止
void SendPacket(void); // 发送单个数据包
// 成员变量
Ptr<Socket> m_socket; // TCP Socket
Address m_peer; // 目标地址
uint32_t m_packetSize; // 数据包大小
DataRate m_dataRate; // 发送速率
EventId m_sendEvent; // 发送事件ID
bool m_running; // 运行状态标志
};
4.2 应用工作流程
void TcpCwndApp::SendPacket(void)
{
// 1. 创建数据包
Ptr<Packet> packet = Create<Packet>(m_packetSize);
// 2. 发送数据包
m_socket->Send(packet);
// 3. 如果还在运行,安排下一个发送事件
if (m_running) {
// 计算下一个包的发送时间间隔
Time tNext(Seconds(m_packetSize * 8 / static_cast<double>(m_dataRate.GetBitRate())));
m_sendEvent = Simulator::Schedule(tNext, &TcpCwndApp::SendPacket, this);
}
}
五、核心仿真函数 RunAlgorithmSimulation
5.1 函数结构
void RunAlgorithmSimulation(std::string algorithmName, // 算法名称
std::string tcpType, // TCP类型字符串
Callback<void, uint32_t, uint32_t> cwndCallback) // 回调函数
5.2 详细步骤分析
// 初始化统计信息
algorithmStats[algorithmName] = AlgorithmStats(algorithmName);、
// 设置TCP算法类型
Config::SetDefault("ns3::TcpL4Protocol::SocketType", StringValue(tcpType));
// 特别配置Vegas参数
if (algorithmName == "Vegas") {
Config::SetDefault("ns3::TcpVegas::Alpha", UintegerValue(2));
Config::SetDefault("ns3::TcpVegas::Beta", UintegerValue(4));
Config::SetDefault("ns3::TcpVegas::Gamma", UintegerValue(1));
}
// 创建节点
NodeContainer nodes;
nodes.Create(2);
// 创建链路 - 为Vegas设置不同条件
PointToPointHelper pointToPoint;
if (algorithmName == "Vegas") {
pointToPoint.SetDeviceAttribute("DataRate", StringValue("3Mbps"));
pointToPoint.SetChannelAttribute("Delay", StringValue("15ms"));
} else {
pointToPoint.SetDeviceAttribute("DataRate", StringValue("5Mbps"));
pointToPoint.SetChannelAttribute("Delay", StringValue("2ms"));
}
// 安装协议栈
InternetStackHelper stack;
stack.Install(nodes);
// 分配IP地址
Ipv4AddressHelper address;
address.SetBase("10.1.1.0", "255.255.255.252");
Ipv4InterfaceContainer interfaces = address.Assign(devices);
// 创建socket并连接回调
Ptr<Socket> tcpSocket = Socket::CreateSocket(nodes.Get(0), TcpSocketFactory::GetTypeId());
tcpSocket->TraceConnectWithoutContext("CongestionWindow", cwndCallback);
// 创建自定义发送应用
Ptr<TcpCwndApp> app = CreateObject<TcpCwndApp>();
app->Setup(tcpSocket, sinkAddress, 1024, DataRate("1Mbps"));
nodes.Get(0)->AddApplication(app);
app->SetStartTime(Seconds(1.0));
app->SetStopTime(Seconds(25.0));
// 创建接收端
PacketSinkHelper sink("ns3::TcpSocketFactory",
InetSocketAddress(Ipv4Address::GetAny(), sinkPort));
ApplicationContainer sinkApps = sink.Install(nodes.Get(1));
sinkApps.Start(Seconds(0.0));
sinkApps.Stop(Seconds(25.0));
// 运行仿真
Simulator::Stop(Seconds(25));
Simulator::Run();
Simulator::Destroy();
六、结果分析和展示函数
void PrintComparisonTable() {
// 打印表头
std::cout << "\n" << std::string(80, '=') << std::endl;
std::cout << " TCP CONGESTION CONTROL ALGORITHMS COMPARISON" << std::endl;
// 打印网络条件说明
std::cout << " Network Conditions: 5Mbps bandwidth, 2ms delay" << std::endl;
std::cout << " Application: 1Mbps data rate, 1024 byte packets" << std::endl;
// 打印表头和表格数据
std::cout << std::left << std::setw(12) << "Algorithm"
<< std::setw(12) << "Data Pts"
<< std::setw(12) << "Duration(s)"
<< std::setw(15) << "Max CWND(KB)"
<< ... << std::endl;
}
void PrintPerformanceRankings() {
// 1. 按最大CWND排名
std::vector<std::pair<std::string, double>> maxCwndRanking;
for (const auto& pair : algorithmStats) {
maxCwndRanking.push_back({pair.first, pair.second.maxCwnd});
}
std::sort(maxCwndRanking.begin(), maxCwndRanking.end(),
[](const auto& a, const auto& b) { return a.second > b.second; });
// 2. 按平均CWND排名
// 3. 按增长率排名
// 4. 综合评分
}
七、主函数 main
int main(int argc, char *argv[])
{
// 1. 打印程序标题
std::cout << "\n" << std::string(70, '*') << std::endl;
std::cout << " TCP CONGESTION CONTROL ALGORITHM COMPARISON TOOL" << std::endl;
// 2. 运行三种算法的仿真
RunAlgorithmSimulation("Cubic", "ns3::TcpCubic", MakeCallback(&CwndChangeCubic));
RunAlgorithmSimulation("NewReno", "ns3::TcpNewReno", MakeCallback(&CwndChangeNewReno));
RunAlgorithmSimulation("Vegas", "ns3::TcpVegas", MakeCallback(&CwndChangeVegas));
// 3. 打印对比结果
PrintComparisonTable();
PrintPerformanceRankings();
// 4. 最终总结和建议
// ...
return 0;
}
// Cubic仿真
RunAlgorithmSimulation("Cubic", // 算法名称
"ns3::TcpCubic", // TCP类型
MakeCallback(&CwndChangeCubic)); // 回调函数
// MakeCallback的作用:
// 将普通函数指针包装成ns3的Callback对象
// 格式:MakeCallback(返回类型, 参数类型...)
八、关键技术和设计模式
// 1. 定义回调函数
static void MyCallback(uint32_t param1, uint32_t param2);
// 2. 创建Callback对象
Callback<void, uint32_t, uint32_t> cb = MakeCallback(&MyCallback);
// 3. 连接信号和回调
socket->TraceConnectWithoutContext("SignalName", cb);
// 4. 当信号触发时,自动调用MyCallback
// Helper类示例
PointToPointHelper pointToPoint;
InternetStackHelper stack;
Ipv4AddressHelper address;
// 作用:简化复杂对象的创建和配置
// 提供一致的接口
// 隐藏实现细节
NodeContainer nodes; // 节点容器
NetDeviceContainer devices; // 网络设备容器
ApplicationContainer apps; // 应用容器
// 作用:统一管理相关对象
// 方便批量操作
// 提供迭代器访问
输出结果如下:

更多推荐
所有评论(0)