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

NS-3多WiFi客户端UDP通信问题:服务器仅接收单个节点数据包求助

NS-3多客户端WiFi UDP通信问题修复

问题根源

  1. WiFi角色倒置:服务器节点使用ns3::StaWifiMac(客户端模式),客户端节点使用ns3::ApWifiMac(接入点模式),违反Infrastructure WiFi网络的工作逻辑,导致多数客户端无法与服务器建立连接,仅第一个客户端节点能偶然通信。
  2. 位置配置不足:Mobility模块仅分配3个位置,但实际有1个服务器+3个客户端共4个节点,服务器节点无独立位置配置。
  3. 缺乏回复逻辑:仅使用PacketSink只能接收数据包,无法实现服务器回复,无法收集往返延迟。

解决方案

  • 调整WiFi角色:服务器设为AP模式,客户端设为STA模式,确保正常WiFi连接。
  • 修正Mobility配置:为所有节点分配独立位置。
  • 实现服务器回复:通过UdpSocket回调实现数据包回复逻辑。
  • 添加延迟收集:客户端发送数据包时记录时间戳,收到回复后计算往返延迟。

修正后代码

#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/wifi-module.h"
#include "ns3/mobility-module.h"
#include "ns3/internet-module.h"
#include "ns3/applications-module.h"
#include "ns3/packet.h"
#include "ns3/log.h"

using namespace ns3;

NS_LOG_COMPONENT_DEFINE ("WirelessNetwork");

// 客户端收到回复时计算往返延迟
void ClientRxCallback(Ptr<const Packet> packet, const Address& from) {
    uint64_t txTime;
    packet->CopyData(reinterpret_cast<uint8_t*>(&txTime), sizeof(txTime));
    double delay = Simulator::Now().GetSeconds() - static_cast<double>(txTime) / 1e9;
    NS_LOG_UNCOND("客户端 " << InetSocketAddress::ConvertFrom(from).GetIpv4() 
                  << " 收到回复,往返延迟: " << delay << " 秒");
}

// 服务器收到数据包后回复客户端
void ServerRxCallback(Ptr<UdpSocket> socket, Ptr<Packet> packet, const Address& from) {
    uint8_t txTimeBuffer[sizeof(uint64_t)];
    packet->CopyData(txTimeBuffer, sizeof(uint64_t));
    Ptr<Packet> replyPacket = Create<Packet>(txTimeBuffer, sizeof(uint64_t));
    socket->SendTo(replyPacket, 0, from);
    NS_LOG_UNCOND("服务器收到来自 " << InetSocketAddress::ConvertFrom(from).GetIpv4() 
                  << " 的数据包,已回复");
}

int main (int argc, char *argv[])
{
    LogComponentEnable ("WirelessNetwork", LOG_LEVEL_INFO);

    bool verbose = true;
    uint32_t nWifi = 3;
    double simulationTime = 10;
    uint16_t port = 9;
    
    CommandLine cmd;
    cmd.AddValue("nWifi", "客户端节点数量", nWifi); 
    cmd.AddValue("verbose", "启用详细日志", verbose);
    cmd.Parse(argc,argv);
    
    if (verbose) {
        LogComponentEnable("UdpSocketImpl", LOG_LEVEL_INFO);
        LogComponentEnable("UdpClient", LOG_LEVEL_INFO);
        LogComponentEnable("UdpServer", LOG_LEVEL_INFO);
    }
    
    // 创建节点:1个服务器(AP),nWifi个客户端(STA)
    NodeContainer serverNode;
    serverNode.Create(1);
    NodeContainer clientNodes;
    clientNodes.Create(nWifi);
    
    // 配置WiFi信道和PHY层
    YansWifiChannelHelper channel = YansWifiChannelHelper::Default();
    YansWifiPhyHelper phy;
    phy.SetChannel(channel.Create());
    
    WifiHelper wifi;
    wifi.SetStandard(WIFI_STANDARD_80211n);
    WifiMacHelper mac;
    Ssid ssid = Ssid("ns3-wifi");
    
    // 客户端安装STA模式MAC
    mac.SetType("ns3::StaWifiMac", 
                "Ssid", SsidValue(ssid),
                "ActiveProbing", BooleanValue(false));
    NetDeviceContainer clientDevices = wifi.Install(phy, mac, clientNodes);
    
    // 服务器安装AP模式MAC
    mac.SetType("ns3::ApWifiMac", 
                "Ssid", SsidValue(ssid));
    NetDeviceContainer serverDevice = wifi.Install(phy, mac, serverNode);
    
    // 配置移动性:服务器在中心,客户端分布在周围
    MobilityHelper mobility;
    Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator>();
    positionAlloc->Add(Vector(0.0, 0.0, 0.0)); // 服务器位置
    for (uint32_t i = 0; i < nWifi; ++i) {
        positionAlloc->Add(Vector((i+1)*1.0, 0.0, 0.0)); // 客户端位置
    }
    mobility.SetPositionAllocator(positionAlloc);
    mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
    mobility.Install(serverNode);
    mobility.Install(clientNodes);
    
    // 安装互联网协议栈
    InternetStackHelper stack;
    stack.Install(serverNode);
    stack.Install(clientNodes);
    
    // 分配IP地址
    Ipv4AddressHelper address;
    address.SetBase("192.168.1.0", "255.255.255.0");
    Ipv4InterfaceContainer serverInterface = address.Assign(serverDevice);
    Ipv4InterfaceContainer clientInterfaces = address.Assign(clientDevices);
    
    // 配置服务器Socket:绑定端口,设置接收回调
    Ptr<UdpSocket> serverSocket = Socket::CreateSocket(serverNode.Get(0), UdpSocketFactory::GetTypeId());
    InetSocketAddress serverAddr(Ipv4Address::GetAny(), port);
    serverSocket->Bind(serverAddr);
    serverSocket->SetRecvCallback(MakeCallback(&ServerRxCallback));
    
    // 配置客户端Socket:设置接收回调,定时发送带时间戳的数据包
    for (uint32_t i = 0; i < clientNodes.GetN(); ++i) {
        Ptr<UdpSocket> clientSocket = Socket::CreateSocket(clientNodes.Get(i), UdpSocketFactory::GetTypeId());
        clientSocket->SetRecvCallback(MakeCallback(&ClientRxCallback));
        
        Simulator::Schedule(Seconds(1.0 + i*2), [clientSocket, serverInterface, port, i]() {
            // 每个客户端发送2个数据包,间隔1秒
            for (int j = 0; j < 2; ++j) {
                uint64_t txTime = Simulator::Now().GetNanoSeconds();
                Ptr<Packet> packet = Create<Packet>(reinterpret_cast<uint8_t*>(&txTime), sizeof(txTime));
                clientSocket->SendTo(packet, 0, InetSocketAddress(serverInterface.GetAddress(0), port));
                NS_LOG_UNCOND("客户端 " << clientNodes.Get(i)->GetId() 
                              << " 发送数据包,时间戳: " << txTime/1e9 << " 秒");
                if (j == 0) {
                    Simulator::Schedule(Seconds(1), [clientSocket, serverInterface, port, i]() {
                        uint64_t txTime = Simulator::Now().GetNanoSeconds();
                        Ptr<Packet> packet = Create<Packet>(reinterpret_cast<uint8_t*>(&txTime), sizeof(txTime));
                        clientSocket->SendTo(packet, 0, InetSocketAddress(serverInterface.GetAddress(0), port));
                        NS_LOG_UNCOND("客户端 " << clientNodes.Get(i)->GetId() 
                                      << " 发送数据包,时间戳: " << txTime/1e9 << " 秒");
                    });
                }
            }
        });
    }
    
    Ipv4GlobalRoutingHelper::PopulateRoutingTables();
    
    Simulator::Stop(Seconds(simulationTime + 1));
    Simulator::Run();
    Simulator::Destroy();
    return 0;
}

关键修改说明

  1. 角色修正:服务器作为AP节点提供接入,客户端作为STA节点连接服务器,确保所有客户端能正常建立WiFi连接。
  2. 延迟收集:客户端发送数据包时记录纳秒级时间戳,服务器回复时原封不动返回该时间戳,客户端收到回复后计算时间差得到往返延迟。
  3. 位置配置:为每个节点分配独立位置,避免位置冲突导致的通信异常。
  4. 回复逻辑:通过UdpSocket的接收回调实现服务器自动回复,满足双向通信需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 03:05:54