ns3中callback的机制

callback的机制是不好理解的,但正如其名,回调就是回调。通过指针互相关联。

因此将callback相关的api开放出来很难,这导致用python直接写ns3例子时,一旦出现callback注册就会卡壳。因此使用python编码不如仍然使用C++开发。(当然,依然可以使用python作为成熟api的开发语言)

以下面的样子为例子

  IpL4Protocol::DownTargetCallback m_downTarget;   //!< Callback to send packets over IPv4

1 其定义来自于

  /**
   * \brief callback to send packets over IPv4
   */
  typedef Callback, Ipv4Address, Ipv4Address, uint8_t, Ptr > DownTargetCallback;

2 注册在(参考附录[2])

  virtual void SetDownTarget (DownTargetCallback cb) = 0;
  SetDownTarget (MakeCallback (&Ipv4::Send, ipv4));

3 使用方法,参考附录[1]

  m_downTarget (packet, saddr, daddr, PROT_NUMBER, route);

  m_downTarget (packet, saddr, daddr, PROT_NUMBER, 0);

4 不易理解的地方在于,使用方法3接着会干什么?Ipv4::Send?

如何将使用方法3和注册2结合在一起的?

5 大体处理

m_downTarget是callback,所以会查注册的Ipv4::Send,而这个函数是需要继承的,继承者是ns3::Ipv4L3Protocol::Send

处理过程就是:

直接调用ns3::Ipv4L3Protocol::Send(),这个就是回调。

在gdb中无法单步跟踪,因为回调函数是个指针,所以需要手工在回调函数上直接设置断点跟踪。


6 验证

#0  ns3::Ipv4L3Protocol::Send (this=0x6c1ae0, packet=..., source=..., destination=..., protocol=17 '\021', route=...) at ../src/internet/model/ipv4-l3-protocol.cc:620

#1  0x00007ffff6ce5a05 in ns3::MemPtrCallbackImpl, void (ns3::Ipv4::*)(ns3::Ptr, ns3::Ipv4Address, ns3::Ipv4Address, unsigned char, ns3::Ptr), void, ns3::Ptr, ns3::Ipv4Address, ns3::Ipv4Address, unsigned char, ns3::Ptr, ns3::empty, ns3::empty, ns3::empty, ns3::empty>::operator() (this=0x67d8a0, a1=..., a2=..., a3=..., a4=17 '\021', a5=...) at ./ns3/callback.h:452
#2  0x00007ffff6ce3264 in ns3::Callback, ns3::Ipv4Address, ns3::Ipv4Address, unsigned char, ns3::Ptr, ns3::empty, ns3::empty, ns3::empty, ns3::empty>::operator() (this=0x67d6e0, a1=..., a2=..., a3=..., a4=17 '\021', a5=...) at ./ns3/callback.h:1137
#3  0x00007ffff6ce0ed4 in ns3::UdpL4Protocol::Send (this=0x67d690, packet=..., saddr=..., daddr=..., sport=646, dport=646, route=...)
    at ../src/internet/model/udp-l4-protocol.cc:454
#4  0x00007ffff6d13c13 in ns3::UdpSocketImpl::DoSendTo (this=0x7fffdc0065c0, p=..., dest=..., port=646) at ../src/internet/model/udp-socket-impl.cc:645
#5  0x00007ffff6d16ce2 in ns3::UdpSocketImpl::SendTo (this=0x7fffdc0065c0, p=..., flags=64, address=...) at ../src/internet/model/udp-socket-impl.cc:857
#6  0x00007ffff7a45384 in ns3::UnixDatagramSocketFd::MainSendTo (this=0x7fffdc007ed0, r=0x7ffff0a2be9c, p=..., f=64, ad=...) at ../model/unix-datagram-socket-fd.cc:510
#7  0x00007ffff7a45d17 in ns3::EventImpl* ns3::MakeEvent, unsigned int, ns3::Address), ns3::UnixDatagramSocketFd*, int*, ns3::Ptr, int, ns3::Address>(void (ns3::UnixDatagramSocketFd::*)(int*, ns3::Ptr, unsigned int, ns3::Address), ns3::UnixDatagramSocketFd*, int*, ns3::Ptr, int, ns3::Address)::EventMemberImpl4::Notify() (this=0x7fffdc024ae0) at /home/z/new/dce/build/include/ns3.23/ns3/make-event.h:452
#8  0x00007ffff733e5e7 in ns3::EventImpl::Invoke (this=0x7fffdc024ae0) at ../src/core/model/event-impl.cc:51
#9  0x00007ffff7a8ab2e in ns3::TaskManager::Schedule (this=0x67dc00) at ../model/task-manager.cc:441
#10 0x00007ffff7a8cb21 in ns3::EventImpl* ns3::MakeEvent(void (ns3::TaskManager::*)(), ns3::TaskManager*)::EventMemberImpl0::Notify() (this=0x6733c0) at /home/z/new/dce/build/include/ns3.23/ns3/make-event.h:323
#11 0x00007ffff733e5e7 in ns3::EventImpl::Invoke (this=0x6733c0) at ../src/core/model/event-impl.cc:51
#12 0x00007ffff73432ac in ns3::DefaultSimulatorImpl::ProcessOneEvent (this=0x6b1870) at ../src/core/model/default-simulator-impl.cc:147
#13 0x00007ffff7343638 in ns3::DefaultSimulatorImpl::Run (this=0x6b1870) at ../src/core/model/default-simulator-impl.cc:200
#14 0x00007ffff733f378 in ns3::Simulator::Run () at ../src/core/model/simulator.cc:204
#15 0x000000000040c564 in main (argc=1, argv=0x7fffffffdc08) at ../myscripts/ns-3-dce-quagga/example/dce-quagga-mpls.cc:194
(gdb)

附录:

1 典型使用方法

方法一

void
UdpL4Protocol::Send (Ptr packet,
                     Ipv4Address saddr, Ipv4Address daddr,
                     uint16_t sport, uint16_t dport, Ptr route)
{
  NS_LOG_FUNCTION (this << packet << saddr << daddr << sport << dport << route);

  UdpHeader udpHeader;
  if(Node::ChecksumEnabled ())
    {
      udpHeader.EnableChecksums ();
      udpHeader.InitializeChecksum (saddr,
                                    daddr,
                                    PROT_NUMBER);
    }
  udpHeader.SetDestinationPort (dport);
  udpHeader.SetSourcePort (sport);

  packet->AddHeader (udpHeader);

  m_downTarget (packet, saddr, daddr, PROT_NUMBER, route);
}

方法二

void
UdpL4Protocol::Send (Ptr packet, 
                     Ipv4Address saddr, Ipv4Address daddr, 
                     uint16_t sport, uint16_t dport)
{
  NS_LOG_FUNCTION (this << packet << saddr << daddr << sport << dport);

  UdpHeader udpHeader;
  if(Node::ChecksumEnabled ())
    {
      udpHeader.EnableChecksums ();
      udpHeader.InitializeChecksum (saddr,
                                    daddr,
                                    PROT_NUMBER);
    }
  udpHeader.SetDestinationPort (dport);
  udpHeader.SetSourcePort (sport);

  packet->AddHeader (udpHeader);

  m_downTarget (packet, saddr, daddr, PROT_NUMBER, 0);
}

2 注册方法

      this->SetDownTarget (MakeCallback (&Ipv4::Send, ipv4));

被下面函数在Install的时候调用。

void
UdpL4Protocol::NotifyNewAggregate ()




你可能感兴趣的:(ns3)