美文网首页js css html
ns3 uan模块数据收发过程分析

ns3 uan模块数据收发过程分析

作者: help_youself | 来源:发表于2023-02-10 19:20 被阅读0次

     离散事件仿真器,主要原理是在当前的时刻,计算某个未来事件的发生时刻[1],并向仿真调度器中调度。仿真器按照时戳大小,对未来事件进行调度[2][3]。离散仿真器中的时间与操作系统时钟无关。
     参考博客[3]。比如一条传输链路,网卡的发送速率10Mbps,单向传输时延100ms。当网卡设备向外发送一个数据包A(长度为L字节)时,会模拟处理时延:

    Time txTime = m_bps.CalculateBytesTxTime (p->GetSize ());
    bool result = m_channel->TransmitStart (p, this, txTime);//发送到channel中模拟链路传输时延
    

    经过 Time txCompleteTime = txTime之后,网卡才能处理下一个数据包B。数据包A在链路上传输时,有一个传输时延(100ms,m_delay)。也就是经过txTime + m_delay的时间后,仿真器才会向下一跳的网卡传输数据。

    bool
    PointToPointChannel::TransmitStart (
      Ptr<const Packet> p,
      Ptr<PointToPointNetDevice> src,
      Time txTime)
    {
      Simulator::ScheduleWithContext (m_link[wire].m_dst->GetNode ()->GetId (),txTime + m_delay, &PointToPointNetDevice::Receive, m_link[wire].m_dst, p->Copy ());//经过txTime + m_delay时延后,通过回调进行数据上传
    }
    

     以uan-cw-example.cc为例,分析水声通信模块的数据包处理流程。
     打包程序采用的是OnOffHelper,为仿真节点Node(可以理解为传感器节点或者主机)安装发包应用。

        OnOffHelper app ("ns3::PacketSocketFactory", Address (socket));
        app.SetAttribute ("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]"));
        app.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0]"));
        app.SetAttribute ("DataRate", DataRateValue (m_dataRate));
        app.SetAttribute ("PacketSize", UintegerValue (m_packetSize));
    
        ApplicationContainer apps = app.Install (nc);
        apps.Start (Seconds (0.5));//Applicaion 的启动时间
    

     OnOffHelper在安装ns3::OnOffApplication应用的时候,会对OnOffApplication设置属性值。

    OnOffHelper::OnOffHelper (std::string protocol, Address address)
    {
      m_factory.SetTypeId ("ns3::OnOffApplication");
      m_factory.Set ("Protocol", StringValue (protocol));
      m_factory.Set ("Remote", AddressValue (address));
    }
    ApplicationContainer
    OnOffHelper::Install (Ptr<Node> node) const
    {
      return ApplicationContainer (InstallPriv (node));
    }
    Ptr<Application>
    OnOffHelper::InstallPriv (Ptr<Node> node) const
    {
      Ptr<Application> app = m_factory.Create<Application> ();
      node->AddApplication (app);
    
      return app;
    }
    

     在主文件uan-cw-example.cc中,app.SetAttribute函数第一个参数表示属性,在OnOffApplication有对应的配置点。没有配置的属性,则采用默认值。m_cbrRate数据包发送速率,m_pktSize数据包长度。m_tid代表SocketFactory的类型,属性字符串为"Protocol",在主程序中被配置为"ns3::PacketSocketFactory"。

    TypeId
    OnOffApplication::GetTypeId (void)
    {
      static TypeId tid = TypeId ("ns3::OnOffApplication")
        .SetParent<Application> ()
        .SetGroupName("Applications")
        .AddConstructor<OnOffApplication> ()
        .AddAttribute ("DataRate", "The data rate in on state.",
                       DataRateValue (DataRate ("500kb/s")),
                       MakeDataRateAccessor (&OnOffApplication::m_cbrRate),
                       MakeDataRateChecker ())
        .AddAttribute ("PacketSize", "The size of packets sent in on state",
                       UintegerValue (512),
                       MakeUintegerAccessor (&OnOffApplication::m_pktSize),
                       MakeUintegerChecker<uint32_t> (1))
        .AddAttribute ("Remote", "The address of the destination",
                       AddressValue (),
                       MakeAddressAccessor (&OnOffApplication::m_peer),
                       MakeAddressChecker ())
        .AddAttribute ("Local",
                       "The Address on which to bind the socket. If not set, it is generated automatically.",
                       AddressValue (),
                       MakeAddressAccessor (&OnOffApplication::m_local),
                       MakeAddressChecker ())
        .AddAttribute ("OnTime", "A RandomVariableStream used to pick the duration of the 'On' state.",
                       StringValue ("ns3::ConstantRandomVariable[Constant=1.0]"),
                       MakePointerAccessor (&OnOffApplication::m_onTime),
                       MakePointerChecker <RandomVariableStream>())
        .AddAttribute ("OffTime", "A RandomVariableStream used to pick the duration of the 'Off' state.",
                       StringValue ("ns3::ConstantRandomVariable[Constant=1.0]"),
                       MakePointerAccessor (&OnOffApplication::m_offTime),
                       MakePointerChecker <RandomVariableStream>())
        .AddAttribute ("MaxBytes", 
                       "The total number of bytes to send. Once these bytes are sent, "
                       "no packet is sent again, even in on state. The value zero means "
                       "that there is no limit.",
                       UintegerValue (0),
                       MakeUintegerAccessor (&OnOffApplication::m_maxBytes),
                       MakeUintegerChecker<uint64_t> ())
        .AddAttribute ("Protocol", "The type of protocol to use. This should be "
                       "a subclass of ns3::SocketFactory",
                       TypeIdValue (UdpSocketFactory::GetTypeId ()),
                       MakeTypeIdAccessor (&OnOffApplication::m_tid),
                       // This should check for SocketFactory as a parent
                       MakeTypeIdChecker ())
      ;
      return tid;
    }
    

     ns3中可能有三种SocketFactory:UdpSocketFactory,TcpSocketFactory,PacketSocketFactory,分别可以创建UdpSocket,TcpSocket和PacketSocket。PacketSocket可能主要针对一些传感器网络。
     apps.Start (Seconds (0.5)),仿真器在0.5秒时刻启动OnOffApplication。m_tid对应PacketSocketFactory。

    void OnOffApplication::StartApplication () // Called at time specified by Start
    {
     m_socket = Socket::CreateSocket (GetNode (), m_tid);
     ScheduleStartEvent ();
    }
    //socket.cc
    Socket::CreateSocket (Ptr<Node> node, TypeId tid)
    {
      NS_LOG_FUNCTION (node << tid);
      Ptr<Socket> s;
      NS_ASSERT (node != 0);
      Ptr<SocketFactory> socketFactory = node->GetObject<SocketFactory> (tid);
      NS_ASSERT (socketFactory != 0);
      s = socketFactory->CreateSocket ();
      NS_ASSERT (s != 0);
      return s;
    }
    //packet-socket-factory.cc
    Ptr<Socket> PacketSocketFactory::CreateSocket (void)
    {
      NS_LOG_FUNCTION (this);
      Ptr<Node> node = GetObject<Node> ();
      Ptr<PacketSocket> socket = CreateObject<PacketSocket> ();
      socket->SetNode (node);
      return socket;
    }
    

     经过offInterval时刻后,OnOffApplication向网络中发包。假设时刻t1,ScheduleStartEvent向仿真器的调度器中注册一个事件(OnOffApplication::StartSending,距离当前时刻的间隔为offInterval,t2=t1+offInterval)。当t1时刻到来,仿真器就会回调StartSending函数。

    void OnOffApplication::ScheduleStartEvent ()
    {  // Schedules the event to start sending data (switch to the "On" state)
      NS_LOG_FUNCTION (this);
    
      Time offInterval = Seconds (m_offTime->GetValue ());
      NS_LOG_LOGIC ("start at " << offInterval.As (Time::S));
      m_startStopEvent = Simulator::Schedule (offInterval, &OnOffApplication::StartSending, this);
    }
    

     StartSending。ScheduleNextTx中按照配置的速率向外发送数据包。仿真器中需要频繁地注册未来事件,Simulator::Schedule的返回值可以认为是一个定时器事件。

    // Event handlers
    void OnOffApplication::StartSending ()
    {
      NS_LOG_FUNCTION (this);
      m_lastStartTime = Simulator::Now ();
      ScheduleNextTx ();  // Schedule the send packet event
      ScheduleStopEvent ();
    }
    void OnOffApplication::ScheduleNextTx ()
    {
      NS_LOG_FUNCTION (this);
    
      if (m_maxBytes == 0 || m_totBytes < m_maxBytes)
        {
          NS_ABORT_MSG_IF (m_residualBits > m_pktSize * 8, "Calculation to compute next send time will overflow");
          uint32_t bits = m_pktSize * 8 - m_residualBits;
          NS_LOG_LOGIC ("bits = " << bits);
          Time nextTime (Seconds (bits /
                                  static_cast<double>(m_cbrRate.GetBitRate ()))); // Time till next packet
          NS_LOG_LOGIC ("nextTime = " << nextTime.As (Time::S));
          m_sendEvent = Simulator::Schedule (nextTime,
                                             &OnOffApplication::SendPacket, this);
        }
    }
    

     SendPacket会调用m_socket(类型为PacketSocket)将数据包发送出去。

    void OnOffApplication::SendPacket (){
    int actual = m_socket->Send (packet);
    }
    

     看下PacketSocket的发送逻辑。

    int
    PacketSocket::Send (Ptr<Packet> p, uint32_t flags)
    {
      NS_LOG_FUNCTION (this << p << flags);
      if (m_state == STATE_OPEN ||
          m_state == STATE_BOUND)
        {
          m_errno = ERROR_NOTCONN;
          return -1;
        }
      return SendTo (p, flags, m_destAddr);
    }
    int
    PacketSocket::SendTo (Ptr<Packet> p, uint32_t flags, const Address &address)
    {
    device->Send (p, dest, ad.GetProtocol ())
    }
    

     device发送数据包。主文件uan-cw-example.cc,在安装channnel时候,返回了网卡设备。

    //uan-cw-example.cc
    NetDeviceContainer devices = uan.Install (nc, channel);
    //uan-helper.cc
    NetDeviceContainer
    UanHelper::Install (NodeContainer c, Ptr<UanChannel> channel) const
    {
      NetDeviceContainer devices;
      for (NodeContainer::Iterator i = c.Begin (); i != c.End (); i++)
        {
          Ptr<Node> node = *i;
    
          Ptr<UanNetDevice> device = Install (node, channel);
    
          devices.Add (device);
          NS_LOG_DEBUG ("node=" << node << ", mob=" << node->GetObject<MobilityModel> ());
        }
      return devices;
    }
    Ptr<UanNetDevice>
    UanHelper::Install (Ptr<Node> node, Ptr<UanChannel> channel) const
    {
      Ptr<UanNetDevice> device = CreateObject<UanNetDevice> ();
    
      Ptr<UanMac> mac = m_mac.Create<UanMac> ();
      Ptr<UanPhy> phy = m_phy.Create<UanPhy> ();
      Ptr<UanTransducer> trans = m_transducer.Create<UanTransducer> ();
    
      mac->SetAddress (Mac8Address::Allocate ());
      device->SetMac (mac);
      device->SetPhy (phy);
      device->SetTransducer (trans);
      device->SetChannel (channel);
    
      node->AddDevice (device);
    
      return device;
    }
    

     device->Send,在UanNetDevice类中查看Send函数的实现。

    //uan-net-devices.cc
    bool
    UanNetDevice::Send (Ptr<Packet> packet, const Address &dest, uint16_t protocolNumber)
    {
      uint8_t tmp [6];
      dest.CopyTo (tmp);
      Mac8Address udest (tmp[0]);
    
      return m_mac->Enqueue (packet, protocolNumber, udest);
    }
    

     UanHelper默认的mac协议实现为UanMacAloha,默认的trans为UanTransducerHd,phy的默认配置为UanPhyGen。

    //uan-helper.cc
    UanHelper::UanHelper ()
    {
      m_mac.SetTypeId ("ns3::UanMacAloha");
      m_phy.SetTypeId ("ns3::UanPhyGen");
      m_transducer.SetTypeId ("ns3::UanTransducerHd");
    }
    

     针对m_mac->Enqueue,在类UanMacAloha查看其实现。

    //uan-mac-aloha.cc
    bool
    UanMacAloha::Enqueue (Ptr<Packet> packet, uint16_t protocolNumber, const Address &dest)
    {
    m_phy->SendPacket (packet, GetTxModeIndex ());
    }
    

     在类UanPhyGen,查看m_phy->SendPacket的实现。GetTxModeIndex ()获取调制模式。查找代码,没有看到对调制模式的配置,但是有这样的接口(UanMac::SetTxModeIndex)。UanTxMode 中罗列的调制模式有PSK,QAM,FSK。

    //uan-phy-gen.cc
    void
    UanPhyGen::SendPacket (Ptr<Packet> pkt, uint32_t modeNum)
    {
      NS_LOG_DEBUG ("PHY " << m_mac->GetAddress () << ": Transmitting packet");
      if (m_state == DISABLED)
        {
          NS_LOG_DEBUG ("Energy depleted, node cannot transmit any packet. Dropping.");
          return;
        }
    
      if (m_state == TX)
        {
          NS_LOG_DEBUG ("PHY requested to TX while already Transmitting.  Dropping packet.");
          return;
        }
      else if (m_state == SLEEP)
        {
          NS_LOG_DEBUG ("PHY requested to TX while sleeping.  Dropping packet.");
          return;
        }
    
      UanTxMode txMode = GetMode (modeNum);
    
      if (m_pktRx != 0)
        {
          m_minRxSinrDb = -1e30;
          m_pktRx = 0;
        }
    
      m_transducer->Transmit (Ptr<UanPhy> (this), pkt, m_txPwrDb, txMode);
      m_state = TX;
      UpdatePowerConsumption (TX);
      double txdelay = pkt->GetSize () * 8.0 / txMode.GetDataRateBps ();
      m_pktTx = pkt;
      m_txEndEvent = Simulator::Schedule (Seconds (txdelay), &UanPhyGen::TxEndEvent, this);
      NS_LOG_DEBUG ("PHY " << m_mac->GetAddress () << " notifying listeners");
      NotifyListenersTxStart (Seconds (txdelay));
      m_txLogger (pkt, m_txPwrDb, txMode);
    }
    

      m_transducer->Transmit函数中携带有发送功率和调制模式参数。在类UanTransducerHd,查看m_transducer->Transmit的实现。如果已经处于传输模式,说明设备忙,丢弃数据包,反之,则进入else之后的处理。不同的调制模式,传输速率不同。

    //uan-transducer-hd.cc
    void
    UanTransducerHd::Transmit (Ptr<UanPhy> src,
                               Ptr<Packet> packet,
                               double txPowerDb,
                               UanTxMode txMode)
    {
      if (m_state == TX)
        {
          m_endTxEvent.Cancel ();
          src->NotifyTxDrop(packet);           // traced source netanim
        }
      else
        {
          m_state = TX;
          src->NotifyTxBegin(packet);             // traced source netanim
        }
    //不同的调制模式,传输速率不同。
      Time delay = Seconds (packet->GetSize () * 8.0 / txMode.GetDataRateBps ());
      UanPhyList::const_iterator it = m_phyList.begin ();
      for (; it != m_phyList.end (); it++)
        {
          if (src != (*it))
            {
              (*it)->NotifyTransStartTx (packet, txPowerDb, txMode);
            }
        }
      m_channel->TxPacket (Ptr<UanTransducer> (this), packet, txPowerDb, txMode);
    
    
      delay = std::max (delay, m_endTxTime - Simulator::Now ());
    
      m_endTxEvent = Simulator::Schedule (delay, &UanTransducerHd::EndTx, this);
      m_endTxTime = Simulator::Now () + delay;
      Simulator::Schedule(delay, &UanPhy::NotifyTxEnd, src, packet);    // traced source netanim
    }
    

     m_channel->TxPacket,查看其实现。

    //uan-channel.cc
    void
    UanChannel::TxPacket (Ptr<UanTransducer> src, Ptr<Packet> packet,
                          double txPowerDb, UanTxMode txMode)
    {
      UanDeviceList::const_iterator i = m_devList.begin ();
      for (; i != m_devList.end (); i++)
        {
          if (src != i->second)
            {
              NS_LOG_DEBUG ("Scheduling " << i->first->GetMac ()->GetAddress ());
              Ptr<MobilityModel> rcvrMobility = i->first->GetNode ()->GetObject<MobilityModel> ();
              Time delay = m_prop->GetDelay (senderMobility, rcvrMobility, txMode);
              UanPdp pdp = m_prop->GetPdp (senderMobility, rcvrMobility, txMode);
              double rxPowerDb = txPowerDb - m_prop->GetPathLossDb (senderMobility,
                                                                    rcvrMobility,
                                                                    txMode);
    
              NS_LOG_DEBUG ("txPowerDb=" << txPowerDb << "dB, rxPowerDb="
                                         << rxPowerDb << "dB, distance="
                                         << senderMobility->GetDistanceFrom (rcvrMobility)
                                         << "m, delay=" << delay);
    
              uint32_t dstNodeId = i->first->GetNode ()->GetId ();
              Ptr<Packet> copy = packet->Copy ();
              Simulator::ScheduleWithContext (dstNodeId, delay,
                                              &UanChannel::SendUp,
                                              this,
                                              j,
                                              copy,
                                              rxPowerDb,
                                              txMode,
                                              pdp);
            }
          j++;
        }
    }
    

     主文件uan-cw-example.cc中,就配置了一个channel,所有的网络节点共用此channel,符合传感器网络通信的特点。在上述代码中,数据包会向所有的节点,提交数据包的拷贝( Ptr<Packet> copy=packet->Copy ())。另外这里有一些路径损失(GetPathLossDb )的计算,信道模型用到功率延迟分布(PDP,power delay profile),细节参见博客[4][5]。

    Ptr<UanChannel> channel = CreateObjectWithAttributes<UanChannel> ("PropagationModel", PointerValue (prop));
    

     UanChannel向目标节点发送数据包过程。UanTransducerHd的m_state == RX,才能成功收包。

    //uan-channel.cc
    void
    UanChannel::SendUp (uint32_t i, Ptr<Packet> packet, double rxPowerDb,
                        UanTxMode txMode, UanPdp pdp)
    {
      NS_LOG_DEBUG ("Channel:  In sendup");
      m_devList[i].second->Receive (packet, rxPowerDb, txMode, pdp);
    }
    //uan-transducer-hd.cc
    void
    UanTransducerHd::Receive (Ptr<Packet> packet,
                              double rxPowerDb,
                              UanTxMode txMode,
                              UanPdp pdp)
    {
      NS_LOG_FUNCTION (this << packet << rxPowerDb << txMode << pdp);
      //Apply receiver gain in dB
      rxPowerDb = ApplyRxGainDb (rxPowerDb, txMode);
    
      UanPacketArrival arrival (packet,
                                rxPowerDb,
                                txMode,
                                pdp,
                                Simulator::Now ());
    
      m_arrivalList.push_back (arrival);
      Time txDelay = Seconds (packet->GetSize () * 8.0 / txMode.GetDataRateBps ());
      Simulator::Schedule (txDelay, &UanTransducerHd::RemoveArrival, this, arrival);
      NS_LOG_DEBUG (Now ().As (Time::S) << " Transducer in receive");
      if (m_state == RX)
        {
          NS_LOG_DEBUG ("Transducer state = RX");
          UanPhyList::const_iterator it = m_phyList.begin ();
          for (; it != m_phyList.end (); it++)
            {
              NS_LOG_DEBUG ("Calling StartRx");
              (*it)->StartRxPacket (packet, rxPowerDb, txMode, pdp);
            }
        }
    }
    

     StartRxPacket函数中,需要计算SINR(Signal to Interference plus Noise Ratio),设置一些状态装换。txdelay = pkt->GetSize () * 8.0 / txMode.GetDataRateBps (),模拟接受侧网卡的处理时延(解调?)。

    //uan-phy-gen.cc
    void
    UanPhyGen::StartRxPacket (Ptr<Packet> pkt, double rxPowerDb, UanTxMode txMode, UanPdp pdp)
    {
      NS_LOG_DEBUG ("PHY " << m_mac->GetAddress () << ": rx power after RX gain = " << rxPowerDb << " dB re uPa");
    
      switch (m_state)
        {
        case DISABLED:
          NS_LOG_DEBUG ("Energy depleted, node cannot receive any packet. Dropping.");
          NotifyRxDrop (pkt); // traced source netanim
          return;
        case TX:
          NotifyRxDrop (pkt); // traced source netanim
          NS_ASSERT (false);
          break;
        case RX:
          {
            NS_ASSERT (m_pktRx);
            double newSinrDb = CalculateSinrDb (m_pktRx, m_pktRxArrTime, m_rxRecvPwrDb, m_pktRxMode, m_pktRxPdp);
            m_minRxSinrDb  =  (newSinrDb < m_minRxSinrDb) ? newSinrDb : m_minRxSinrDb;
            NS_LOG_DEBUG ("PHY " << m_mac->GetAddress () << ": Starting RX in RX mode.  SINR of pktRx = " << m_minRxSinrDb);
            NotifyRxBegin (pkt); // traced source netanim
          }
          break;
    
        case CCABUSY:
        case IDLE:
          {
            NS_ASSERT (!m_pktRx);
            bool hasmode = false;
            for (uint32_t i = 0; i < GetNModes (); i++)
              {
                if (txMode.GetUid () == GetMode (i).GetUid ())
                  {
                    hasmode = true;
                    break;
                  }
              }
            if (!hasmode)
              {
                break;
              }
    
    
            double newsinr = CalculateSinrDb (pkt, Simulator::Now (), rxPowerDb, txMode, pdp);
            NS_LOG_DEBUG ("PHY " << m_mac->GetAddress () << ": Starting RX in IDLE mode.  SINR = " << newsinr);
            if (newsinr > m_rxThreshDb)
              {
                m_state = RX;
                UpdatePowerConsumption (RX);
                NotifyRxBegin (pkt); // traced source netanim
                m_rxRecvPwrDb = rxPowerDb;
                m_minRxSinrDb = newsinr;
                m_pktRx = pkt;
                m_pktRxArrTime = Simulator::Now ();
                m_pktRxMode = txMode;
                m_pktRxPdp = pdp;
                double txdelay = pkt->GetSize () * 8.0 / txMode.GetDataRateBps ();
                m_rxEndEvent = Simulator::Schedule (Seconds (txdelay), &UanPhyGen::RxEndEvent, this, pkt, rxPowerDb, txMode);
                NotifyListenersRxStart ();
              }
    
          }
          break;
        case SLEEP:
          NS_LOG_DEBUG ("Sleep mode. Dropping packet.");
          NotifyRxDrop (pkt); // traced source netanim
          break;
        }
    
      if (m_state == IDLE && GetInterferenceDb ( (Ptr<Packet>) 0) > m_ccaThreshDb)
        {
          m_state = CCABUSY;
          NotifyListenersCcaStart ();
        }
    
    }
    

     UanPhyGen::RxEndEvent中会计算packer error rate(m_per->CalcPer),m_pg是个随机数生成器,生成值高于per,才会继续向上提交数据包。

    void
    UanPhyGen::RxEndEvent (Ptr<Packet> pkt, double rxPowerDb, UanTxMode txMode)
    {
      if (m_pg->GetValue (0, 1) > m_per->CalcPer (m_pktRx, m_minRxSinrDb, txMode))
        {
          m_rxOkLogger (pkt, m_minRxSinrDb, txMode);
          NotifyListenersRxGood ();
          if (!m_recOkCb.IsNull ())
            {
              m_recOkCb (pkt, m_minRxSinrDb, txMode);
            }
    
        }
    }
    

     m_recOkCb的回调函数的配置点。m_recOkCb最终会调用UanMacAloha::RxPacketGood函数。目的地址是自身的设备地址,才会继续向上层提交(m_forUpCb )。

    void
    UanMacAloha::AttachPhy (Ptr<UanPhy> phy)
    {
      m_phy = phy;
      m_phy->SetReceiveOkCallback (MakeCallback (&UanMacAloha::RxPacketGood, this));
      m_phy->SetReceiveErrorCallback (MakeCallback (&UanMacAloha::RxPacketError, this));
    }
    void
    UanMacAloha::RxPacketGood (Ptr<Packet> pkt, double sinr, UanTxMode txMode)
    {
      NS_UNUSED (sinr);
      UanHeaderCommon header;
      pkt->RemoveHeader (header);
      NS_LOG_DEBUG ("Receiving packet from " << header.GetSrc () << " For " << header.GetDest ());
    
      if (header.GetDest () == GetAddress () || header.GetDest () == Mac8Address::GetBroadcast ())
        {
          m_forUpCb (pkt, header.GetProtocolNumber (), header.GetSrc ());
        }
    
    }
    

     m_forUpCb的设置函数为SetForwardUpCb 。m_forUpCb最终调用UanNetDevice::ForwardUp函数。

    void
    UanMacAloha::SetForwardUpCb (Callback<void, Ptr<Packet>, uint16_t, const Mac8Address&> cb)
    {
      m_forUpCb = cb;
    }
    void
    UanNetDevice::SetMac (Ptr<UanMac> mac)
    {
    m_mac->SetForwardUpCb (MakeCallback (&UanNetDevice::ForwardUp, this));
    }
    

     UanNetDevice::ForwardUp的处理过程。

    void
    UanNetDevice::SetReceiveCallback (NetDevice::ReceiveCallback cb)
    {
      m_forwardUp = cb;
    }
    void
    UanNetDevice::ForwardUp (Ptr<Packet> pkt, uint16_t protocolNumber, const Mac8Address &src)
    {
      NS_LOG_DEBUG ("Forwarding packet up to application");
      m_rxLogger (pkt, src);
      m_forwardUp (this, pkt, protocolNumber, src);
    
    }
    

     m_forwardUp是在哪里被设置的呢?

    Ptr<UanNetDevice>
    UanHelper::Install (Ptr<Node> node, Ptr<UanChannel> channel) const
    {
    Ptr<UanNetDevice> device = CreateObject<UanNetDevice> ();
    node->AddDevice (device);
    }
    uint32_t
    Node::AddDevice (Ptr<NetDevice> device)
    {
    device->SetReceiveCallback (MakeCallback (&Node::NonPromiscReceiveFromDevice, this));
    }
    void
    UanNetDevice::SetReceiveCallback (NetDevice::ReceiveCallback cb)
    {
      m_forwardUp = cb;
    }
    

     m_forwardUp最终调用Node::NonPromiscReceiveFromDevice。

    bool
    Node::NonPromiscReceiveFromDevice (Ptr<NetDevice> device, Ptr<const Packet> packet, uint16_t protocol,
                                       const Address &from)
    {
      NS_LOG_FUNCTION (this << device << packet << protocol << &from);
      return ReceiveFromDevice (device, packet, protocol, from, device->GetAddress (), NetDevice::PacketType (0), false);
    }
    bool
    Node::ReceiveFromDevice (Ptr<NetDevice> device, Ptr<const Packet> packet, uint16_t protocol,
                             const Address &from, const Address &to, NetDevice::PacketType packetType, bool promiscuous)
    {
      for (ProtocolHandlerList::iterator i = m_handlers.begin ();
           i != m_handlers.end (); i++){
            i->handler (device, packet, protocol, from, to, packetType);
    }
    }
    

     m_handlers的注册过程:

    int
    PacketSocket::DoBind (const PacketSocketAddress &address)
    {
      m_node->RegisterProtocolHandler (MakeCallback (&PacketSocket::ForwardUp, this),
                                       address.GetProtocol (), dev);
    }
    void
    Node::RegisterProtocolHandler (ProtocolHandler handler, 
                                   uint16_t protocolType,
                                   Ptr<NetDevice> device,
                                   bool promiscuous){
    m_handlers.push_back (entry);
    }
    

     i->handler最终调用的函数为PacketSocket::ForwardUp。

    void 
    PacketSocket::ForwardUp (Ptr<NetDevice> device, Ptr<const Packet> packet, 
                             uint16_t protocol, const Address &from,
                             const Address &to, NetDevice::PacketType packetType)
    {
      if ((m_rxAvailable + packet->GetSize ()) <= m_rcvBufSize)
        {
            m_deliveryQueue.push (std::make_pair (copy, address));
           NotifyDataRecv ();
        }
    }
    

     NotifyDataRecv会通知上层Application读取数据包。主程序uan-cw-example.cc设置了数据包读取函数。

    sinkSocket->SetRecvCallback (MakeCallback (&Experiment::ReceivePacket, this));
    void
    Experiment::ReceivePacket (Ptr<Socket> socket)
    {
      Ptr<Packet> packet;
      while ((packet = socket->Recv ()))
        {
          m_bytesTotal += packet->GetSize ();
        }
    }
    

     物理层的退避,信噪比的计算,需要相关领域的人员具体分析。我不是搞无线网络的。

    Reference:
    [1]ns3 simulator离散模拟机制
    [2]ns3源码阅读(一)UdpSocketFactory的创建
    [3]ns3源码阅读(二)net-device和channel
    [4]基于PDP的信道建模
    [5]学习笔记(十六):商用Wi-Fi的功率延迟分布

    相关文章

      网友评论

        本文标题:ns3 uan模块数据收发过程分析

        本文链接:https://www.haomeiwen.com/subject/vwukkdtx.html