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;  // 应用容器

// 作用:统一管理相关对象
// 方便批量操作
// 提供迭代器访问

输出结果如下:

更多推荐