You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于ns-3 3.35实现随机无线负载均衡器仿真?

ns-3 3.35 无线负载均衡仿真实现方案

一、拓扑与节点配置

先创建5个Sender、1个负载均衡器、5个Receiver节点,绑定到同一个无线Adhoc网络:

// 创建节点
NodeContainer senderNodes;
senderNodes.Create(5);
NodeContainer loadBalancerNode;
loadBalancerNode.Create(1);
NodeContainer receiverNodes;
receiverNodes.Create(5);
NodeContainer allNodes = NodeContainer(senderNodes, loadBalancerNode, receiverNodes);

// 配置无线信道与物理层
YansWifiChannelHelper channel = YansWifiChannelHelper::Default();
YansWifiPhyHelper phy;
phy.SetChannel(channel.Create());

// 设置1Mbps数据速率(基于802.11b标准)
WifiHelper wifi;
wifi.SetStandard(WIFI_STANDARD_80211b);
wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
                              "DataMode", StringValue("DsssRate1Mbps"),
                              "ControlMode", StringValue("DsssRate1Mbps"));

// 配置Adhoc模式MAC层
NqosWifiMacHelper mac = NqosWifiMacHelper::Default();
mac.SetType("ns3::AdhocWifiMac");

NetDeviceContainer devices = wifi.Install(phy, mac, allNodes);

// 安装IPv4协议栈
InternetStackHelper stack;
stack.Install(allNodes);
Ipv4AddressHelper address;
address.SetBase("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer interfaces = address.Assign(devices);

二、Receiver误码率配置

为每个Receiver节点的无线物理层设置0.0001的误码率:

// 遍历所有Receiver节点配置误码率模型
for (uint32_t i = 0; i < receiverNodes.GetN(); ++i) {
  uint32_t devIdx = senderNodes.GetN() + loadBalancerNode.GetN() + i;
  Ptr<WifiNetDevice> wifiDev = DynamicCast<WifiNetDevice>(devices.Get(devIdx));
  Ptr<YansWifiPhy> wifiPhy = DynamicCast<YansWifiPhy>(wifiDev->GetPhy());
  
  Ptr<YansErrorRateModel> errorModel = CreateObject<YansErrorRateModel>();
  errorModel->SetAttribute("ErrorRate", DoubleValue(0.0001));
  wifiPhy->SetErrorRateModel(errorModel);
}

三、随机负载均衡逻辑实现

负载均衡器需完成TCP连接初始化、UDP数据包接收与随机转发两个核心逻辑:

1. 与Receiver建立TCP连接

Ptr<Node> lbNode = loadBalancerNode.Get(0);
std::vector<Ptr<Socket>> lbTcpSockets;

// 为每个Receiver建立TCP连接
for (uint32_t i = 0; i < receiverNodes.GetN(); ++i) {
  Ptr<Node> recvNode = receiverNodes.Get(i);
  TypeId tid = TypeId::LookupByName("ns3::TcpSocketFactory");
  Ptr<Socket> socket = lbNode->GetObject<SocketFactory>(tid)->CreateSocket();
  
  InetSocketAddress recvAddr(recvNode->GetObject<Ipv4>()->GetAddress(1, 0).GetLocal(), 5000);
  socket->Connect(recvAddr);
  lbTcpSockets.push_back(socket);
}

2. UDP接收与随机转发回调

// 负载均衡器UDP接收回调:随机选择TCP连接转发数据包
void LbUdpReceiveCallback(Ptr<Socket> socket, std::vector<Ptr<Socket>>& tcpSockets) {
  Ptr<Packet> packet;
  Address from;
  while ((packet = socket->RecvFrom(from))) {
    // 生成随机索引选择Receiver
    uint32_t randIdx = rand() % tcpSockets.size();
    Ptr<Socket> targetSocket = tcpSockets[randIdx];
    targetSocket->Send(packet);
  }
}

// 初始化负载均衡器UDP监听
TypeId udpTid = TypeId::LookupByName("ns3::UdpSocketFactory");
Ptr<Socket> lbUdpSocket = lbNode->GetObject<SocketFactory>(udpTid)->CreateSocket();
InetSocketAddress lbUdpAddr(Ipv4Address::GetAny(), 4000);
lbUdpSocket->Bind(lbUdpAddr);
lbUdpSocket->SetRecvCallback(MakeBoundCallback(&LbUdpReceiveCallback, lbTcpSockets));

四、Sender与Receiver应用实现

1. 带时间戳的Sender UDP发送

给数据包添加时间戳,用于后续计算端到端延迟:

class TimestampedUdpClient : public UdpClient {
protected:
  void Send() override {
    Ptr<Packet> packet = CreatePacket();
    TimestampTag timestamp;
    timestamp.SetTimestamp(Simulator::Now());
    packet->AddByteTag(timestamp);
    m_socket->Send(packet);
    m_sendEvent = Simulator::Schedule(m_interval, &TimestampedUdpClient::Send, this);
  }
};

// 安装Sender应用
for (uint32_t i = 0; i < senderNodes.GetN(); ++i) {
  Ptr<Node> senderNode = senderNodes.Get(i);
  Ptr<TimestampedUdpClient> udpClient = CreateObject<TimestampedUdpClient>();
  
  udpClient->SetRemote(lbNode->GetObject<Ipv4>()->GetAddress(1, 0).GetLocal(), 4000);
  udpClient->SetAttribute("Interval", TimeValue(Seconds(0.001)));
  udpClient->SetAttribute("PacketSize", UintegerValue(1024));
  
  senderNode->AddApplication(udpClient);
  udpClient->SetStartTime(Seconds(1.0));
  udpClient->SetStopTime(Seconds(10.0));
}

2. Receiver TCP接收与性能统计

在Receiver端统计吞吐量与平均端到端延迟:

class ReceiverApp : public Application {
public:
  ReceiverApp() : m_totalBytes(0), m_totalDelay(0), m_packetCount(0) {}
  static TypeId GetTypeId() {
    static TypeId tid = TypeId("ReceiverApp")
      .SetParent<Application>()
      .AddConstructor<ReceiverApp>();
    return tid;
  }
  
  void StartApplication() override {
    TypeId tid = TypeId::LookupByName("ns3::TcpSocketFactory");
    m_socket = GetNode()->GetObject<SocketFactory>(tid)->CreateSocket();
    InetSocketAddress localAddr(Ipv4Address::GetAny(), 5000);
    m_socket->Bind(localAddr);
    m_socket->SetRecvCallback(MakeCallback(&ReceiverApp::ReceivePacket, this));
  }
  
  void ReceivePacket(Ptr<Socket> socket) {
    Ptr<Packet> packet;
    Address from;
    while ((packet = socket->RecvFrom(from))) {
      m_totalBytes += packet->GetSize();
      // 提取时间戳计算延迟
      TimestampTag timestamp;
      if (packet->FindFirstMatchingByteTag(timestamp)) {
        Time delay = Simulator::Now() - timestamp.GetTimestamp();
        m_totalDelay += delay.GetSeconds();
        m_packetCount++;
      }
    }
  }
  
  void StopApplication() override {
    // 计算并输出统计结果
    double throughput = (m_totalBytes * 8.0) / (10.0 - 1.0) / 1024 / 1024; // 单位:Mbps
    double avgDelay = m_totalDelay / m_packetCount * 1000; // 单位:毫秒
    std::cout << "Receiver " << GetNode()->GetId() 
              << " 吞吐量: " << std::fixed << std::setprecision(3) << throughput << " Mbps"
              << ", 平均延迟: " << std::fixed << std::setprecision(3) << avgDelay << " ms" << std::endl;
  }
  
private:
  Ptr<Socket> m_socket;
  uint64_t m_totalBytes;
  double m_totalDelay;
  uint32_t m_packetCount;
};

// 安装Receiver应用
for (uint32_t i = 0; i < receiverNodes.GetN(); ++i) {
  Ptr<ReceiverApp> recvApp = CreateObject<ReceiverApp>();
  receiverNodes.Get(i)->AddApplication(recvApp);
  recvApp->SetStartTime(Seconds(0.5));
  recvApp->SetStopTime(Seconds(10.0));
}

五、仿真启动与注意事项

  1. 添加必要头文件:#include "ns3/core-module.h"、#include "ns3/network-module.h"、#include "ns3/wifi-module.h"、#include "ns3/internet-module.h"、#include "ns3/applications-module.h"、#include <iomanip>等。
  2. 设置随机数种子保证仿真可复现:RngSeedManager::SetSeed(1);
  3. 启动仿真:Simulator::Run(); Simulator::Destroy();

内容的提问来源于stack exchange,提问作者Hesam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 00:30:39