NS-3多WiFi客户端UDP通信问题:服务器仅接收单个节点数据包求助
NS-3多客户端WiFi UDP通信问题修复
问题根源
- WiFi角色倒置:服务器节点使用
ns3::StaWifiMac(客户端模式),客户端节点使用ns3::ApWifiMac(接入点模式),违反Infrastructure WiFi网络的工作逻辑,导致多数客户端无法与服务器建立连接,仅第一个客户端节点能偶然通信。 - 位置配置不足:Mobility模块仅分配3个位置,但实际有1个服务器+3个客户端共4个节点,服务器节点无独立位置配置。
- 缺乏回复逻辑:仅使用
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; }
关键修改说明
- 角色修正:服务器作为AP节点提供接入,客户端作为STA节点连接服务器,确保所有客户端能正常建立WiFi连接。
- 延迟收集:客户端发送数据包时记录纳秒级时间戳,服务器回复时原封不动返回该时间戳,客户端收到回复后计算时间差得到往返延迟。
- 位置配置:为每个节点分配独立位置,避免位置冲突导致的通信异常。
- 回复逻辑:通过
UdpSocket的接收回调实现服务器自动回复,满足双向通信需求。
内容的提问来源于stack exchange,提问作者Manos
相关产品推荐
相关产品推荐

