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
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
#2 0x00007ffff6ce3264 in ns3::Callback
#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
#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
#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);
}
this->SetDownTarget (MakeCallback (&Ipv4::Send, ipv4));
被下面函数在Install的时候调用。
void
UdpL4Protocol::NotifyNewAggregate ()