ns3 回调和跟踪机制(callback and trace) 以及 Config(Connect和path设置)使用

source

  • ns3 manual of Callbacks
  • tutorial of tracing 能回答包括但不限于如下的几个问题:
    • Trace/Connect & Trace/ConnectWithoutContext 的关系
    • how to find available traces
    • how to find config path
    • how to find signature of traces (有的在当前类,有的是ns3名字空间的,后者我反正一开始是没找到
    • how to solve frequentlt seen error messages (是不是就是把context打出来然后grep去查看…有点不太记得了…哈哈回头再看看吧

callback

// 回调函数
int myCallback(...){...}	
// 注册回调的函数
Callback<int,...> callbackHook  = MakeCallback<int,...>(myCallback);	

这里要区分的是:myCallback是我们自己实现的回调函数,MakeCallback是用于注册的,返回的是一个Callback<int,…>对象(这里底层是基于C++的模版实现的)

ns3 manual of Callbacks说明了:

  • C语言回调函数的原理(functor之类的… tl;dr,但感觉很有用,回头补上… )
  • MakeCallback 和 MakeBoundCallback之间的联系与区别

    基于C++的回调机制实现的

    • MakeBoundCallback是在这样的场景下使用:回调函数的参数不希望提供给MakeBoundCallback的函数 (maunal里面举了例子),所以这两个不能随便乱用哈哈…
      • 举了一个main-callback.cc里面的例子
        我自己代码的例子:
        void DevicePacketsInQueueTrace(uint32_t device, uint32_t node, uint32_t oldValue, uint32_t newValue)
        {
        NS_LOG_DEBUG("DevicePacketsInQueue " << oldValue << " to " << newValue << " at " << device << "@" << node);
        nodeStatus[node].UpdateDeviceQueue(device, newValue);
        }
        
        for (auto iter = devicesInfo.begin(); iter != devicesInfo.end(); iter++) {
          uint32_t device_idx = distance(devicesInfo.begin(), iter);
          Ptr<PointToPointNetDevice>      ptpnd =
              ns3::DynamicCast<PointToPointNetDevice>   (iter->    first);
          Ptr<Queue<Packet>       >       queue = ptpnd->    GetQueue();
          assert(queue);
          queue->   TraceConnectWithoutContext(
              "PacketsInQueue", MakeBoundCallback(&DevicePacketsInQueueTrace,
                                                  device_idx, i)); //排队情况
        
        这里DevicePacketsInQueueTrace相对于PacketsInQueue对应的回调函数,还额外多了两个固定的绑定参数 device_idx和i

trace

  • 实际上利用了callback机制去实现的
  • 比较典型的参考文件是examples/tcp/tcp-variants-comparison.cc
  • trace sink的定义:使用 .addTrace(…) , 实际上是联系了三方面的事情,trace源、callback函数、config系统,这样算是实现了一个trace
    class MyObject : public Object
    {
    public:
      static TypeId GetTypeId (void)
      {
        static TypeId tid = TypeId ("MyObject")
          .SetParent (Object::GetTypeId ())
          .SetGroupName ("MyGroup")
          .AddConstructor<MyObject> ()
          .AddTraceSource ("MyInteger",
                           "An integer value to trace.",
                           MakeTraceSourceAccessor (&MyObject::m_myInt),
                           "ns3::TracedValueCallback::Int32");
          .AddTraceSource ("hesyCallBack",
                           "callback function get from packet.h",
                           MakeTraceSourceAccessor (&MyObject::m_myCBFunction),
                           "ns3::MyObject::TracedCallback");
        return tid;
      }
    
      MyObject () {}
      TracedValue<int32_t> m_myInt;
      typedef void (* TracedCallback) (Ptr<const Packet> packet);
    	ns3::TracedCallback< Ptr<const Packet> >  m_myCBFunction;
    };
    
    void
    IntTrace (int32_t oldValue, int32_t newValue)
    {
      std::cout << "Traced " << oldValue << " to " << newValue << std::endl;
    }
    
    int
    main (int argc, char *argv[])
    {
      Ptr<MyObject> myObject = CreateObject<MyObject> ();
      myObject->TraceConnectWithoutContext ("MyInteger", MakeCallback (&IntTrace));
    
      myObject->m_myInt = 1234;
    }
    
    • 第一个参数给了trace source一个名字,使得可以在config path里main找到这个trace;
    • 第二个参数是帮助文档
    • 第三个参数(最重要的) &MyObject::m_myInt 是添加到类中的 TracedValue类型的数据,同时也是当前类的类数据成员。【我觉得他这个数据结构和泛型的参数也是暗示了 提供给回调函数的参数形式
    • 第四个参数,是一个string,指向一个签名形式,是一个typedef定义的回调函数的形式

    The final argument is the name of a typedef for the TracedValue type, as a string. This is used to generate documentation for the correct Callback function signature, which is useful especially for more general types of Callbacks.

    • TracedValue<int32_t> m_myInt; 实际上就是在这个类里面定义了这个属性,以便config去access
    • 所以就是三个元素: .addTrace, 然后定义trace source, 然后就是给出参数签名

      如果是TraceCallBack,由于一般都是每个类里面的参数类型(packet类啊,tag类啊)往往是不一样的,所以在每个类里面会重新typedef一个(头文件中 typedef TraceCallBack\<curClass inst, XXX xxx \>),所以一般第四个参数给的签名都是 ns3::ClassName::TraceCallBack; 而TraceValue一般都是传入一个int的参数,不用重新定义,所以一般第四个参数给的签名都是ns3::TraceValueInteger(也会有float对应的啦 >w< )

config path的定义

tutorial - tracing: config-paths 里面描述得很详细了。

basis

  • 形式一般是:
    “/NodeList/7/$ns3::MobilityModel/CourseChange”
    一个配置路径的最后一段必须是某个Object的Attribute
    从nodelist中找出第七个object的指针,然后找到他聚合的MobilityModel对象,然后从这个对象里面找到其CourseChange属性。
  • 两种access方式
    • [namespace-based access]使用config
      Config::Connect (oss.str (), MakeCallback (&CourseChange));
      
    • [object-based access]使用Ptr<Node>来将callback Connect 到 trace
      Ptr<Object> theObject = wifiStaNodes.Get (nWifi - 1);
      theObject->TraceConnectWithoutContext ("CourseChange", MakeCallback (&CourseChange));
      
      • 如果想要额外给callback传递一个 context参数的话,就用TraceConnect() , 不需要的话就是 TraceWithoutContext
      • 对于内部代码 Config::ConnectWithoutContext和Config::Connect实际找到对应的Ptr<Object>并调用相应的TraceConnect 底层方法。
  • TraceValue的使用和operator重载 (加减乘除赋值,>> , <<) 也在这页的底部有说明

系列递进问题

  • 如何知道有哪些trace sources 以及 如何找到trace source的config path (实际上都在doxygen documents里面~)
    在这里插入图片描述
    • 新版本doxygen关于trace和config讲的不是很清楚,可以看这个3.29版本
    • 原来,新版本doxygen里面关于traces的在core module里面
  • 有了如上两个,如何知道我的回调函数的返回类型和形式参数需要是什么?

    看头文件里面的参数签名就可以了, 一般都用TraceWithoutContext,如果用了Trace,callback函数还得留第一个参数的位置用于接受不了trace source提供的字符串形式的context参数

坑点注意

  • 动态 实时 hook , ref here

    记得这个问题还蛮经典的…但是没有仔细看…下次再补充起来吧…

misc

config.h 本身也就那么多功能啊哈哈,常用的就是如下的,基本都掌握了…
在这里插入图片描述

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C#中,委托和事件都是用于实现调函数的机制。委托是一种类型,它可以存储对一个或多个方法的引用,而事件则是委托的一种特殊用法,它只能用于触发事件时调用方法。 调函数是一种编程模式,它允许我们将一个函数作为参数传递给另一个函数,并在需要时调用该函数。调函数通常用于异步编程中,例如在网络编程中,当数据到达时,我们可以使用调函数来处理数据。 委托和事件都可以用于实现调函数的机制。委托可以将一个方法作为参数传递给另一个方法,并在需要时调用该方法。事件则是一种特殊的委托,它只能用于触发事件时调用方法。 使用调函数的步骤如下: 1. 定义一个委托类型,该委托类型定义了调函数的签名。 2. 在需要使用调函数的方法中,将该委托类型的实例作为参数传递给另一个方法。 3. 在另一个方法中,将该委托类型的实例保存下来,并在需要时调用该委托实例。 下面是一个简单的示例代码: ``` // 定义一个委托类型 delegate void MyCallback(int result); class MyClass { // 定义一个方法,该方法接受一个调函数作为参数 public void DoSomethingAsync(int arg, MyCallback callback) { // 异步执行一些操作 int result = arg * 2; // 调用调函数 callback(result); } } class Program { static void Main(string[] args) { MyClass obj = new MyClass(); // 创建一个委托实例,该委托实例引用了一个方法 MyCallback callback = new MyCallback(MyCallbackFunction); // 调用DoSomethingAsync方法,并传递委托实例作为调函数 obj.DoSomethingAsync(10, callback); } // 定义一个调函数 static void MyCallbackFunction(int result) { Console.WriteLine("Result: " + result); } } ``` 在上面的示例代码中,我们定义了一个委托类型`MyCallback`,它定义了一个接受一个整数参数的调函数。然后我们定义了一个类`MyClass`,它有一个方法`DoSomethingAsync`,该方法接受一个整数参数和一个调函数作为参数。在`DoSomethingAsync`方法中,我们异步执行一些操作,并在完成后调用调函数。在`Main`方法中,我们创建了一个委托实例,并将其作为调函数传递给`DoSomethingAsync`方法。最后,在调函数`MyCallbackFunction`中,我们输出了结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值