NS by Example 笔记(10)OTcl Linkage

OTcl Linkage 联接

 

 

添加新的基础网络对象去扩展NS,通常需要从C++代码中得到OTcl linkage(联接), 对象的类用C++来编写由于它的高效性。 本节介绍了NS中C++/OTcl联接, 并给出新建一个简单的名叫"MyAgent"代理的示例,"MyAgent"代理没有任何行为(i.e. no packet creation and transmission). Figures 18 到 21 列出了C++ source file for "MyAgent"。 本节最后是一个OTcl脚本用来测试"MyAgent"是否被实现。 

 

 

导出C++类到OTcl Export C++ class to OTcl

 

假设用C++新建了一个网络对象的类"MyAgent",它是从"Agent"类衍生出来, 然后他能够建立一个OTcl对象的实例。为了实现这个功能我们必须定义一个联接对象"MyAgentClass", 它从"TclClass"衍生得来。 这个联接对象创建了一个有指定命名的OTcl对象(这个例子名为是"Agent/MyAgentOtcl"), 并建立一个联接在OTcl对象和C++对象("MyAgent")之间, 它的实例运行"create"成员函数中指定的程序。Figure 18 表示"MyAgent类"和联接类的定义。



 
Figure 18. Example C++ Network Component and The Linkage Object

 

当NS开始运行, 它运行静态变量(static variable) "class_my_agent"的构造函数, 这样一来"MyAgentClass"的实例被建立了。 在这个处理过程中, "Agent/MyAgentOtcl"类和他的方法method(成员函数)也在OTcl的空间内被建立。 无论何时用户在OTcl空间内建立一个对象的实例就会使用命令"new Agent/MyAgentOtcl", 它调用"MyAgentClass::create"去建立"MyAgent"对象并返回它的地址。 这里要当心, 从OTcl中建立一个C++对象的实例并不意味着能够从OTcl调用C++对象实例的成员函数或访问它的成员变量。

 

 

 

导出C++类的变量到OTcl Export C++ class variables to OTcl 

 

假设C++对象"MyAgent"有两个参数变量"my_var1"和"my_var2", 并且我们想轻松的在OTcl中使用模拟脚本来配置(改变)它们 。这需要使用对每个想要输出的C++类的变量的绑定函数(binding function)。 一个绑定函数建立一个给出名字的新成员变量(绑定函数的第一个变量)在对应的OTcl对象类("Agent/MyAgentOtcl")中, 并建立一个双向绑定在OTcl类的变量和C++变量(第二个变量指定的地址)之间。 Figure 19表明如何给Figure 18中"my_var1" 和"my_var2" 建立绑定。



 
Figure 19. Variable Binding Creation Example

 

绑定函数位于"MyAgent"的构造函数中,这样在建立对象的实例时就建立了绑定。NS 支持4种不同的绑定函数对应5种变量类型: 

 

- bind(): real or integer variables
- bind_time(): time variable
- bind_bw(): bandwidth variable
- bind_bool(): boolean variable

 

以这种方式就可以设计和运行一个模拟并且能使用OTcl脚本去改变或访问C++实现的网络组件的配置参数(或变量的值) 。 无论何时导出一个C++变量, 建议还要去设置这个变量的默认值在"ns-2/tcl/lib/ns-lib.tcl"文件中。 否则在建立新对象的实例时将收到警告信息。

 

 

 

导出C++对象的控制命令到OTcl Export C++ Object Control Commands to OTcl 

 

给C++对象("MyAgent")定义一个"command"成员函数作为OTcl命令的解释器。 事实上对于用户来说, 在一个C++对象的"command"成员函数中定义的OTcl命令, 和对应的OTcl对象中的成员函数看起来是一样的。Figure 20给出Figure 18中"MyAgent"对象定义的一个"command"成员函数的例子。



 
Figure 20. Example OTcl command interpreter

 

当一个OTcl影像的实例匹配上在OTcl空间中建立的"MyAgent"对象(i.e. set myagent [new Agent/MyAgentOtcl]), 并且用户调用这个对象的一个成员函数(i.e. $myagent call-my-priv-func), OTcl搜索这个已给的成员函数在OTcl对象中。 如果这个成员函数的名字找不到, 则调用"MyAgent::command"传递已调用的OTcl成员函数名和参数以argc(参数个数)/argv(参数值)的格式。 如果有为OTcl成员函数定义的行为(action)在"command"成员函数中, 则运行它并返回结果。 如果没有, 则递归地调用父类、祖类的"command"函数直到找到为止。 如果在父类、祖类中都找不到的话, 则返回一个错误信息(error message)给OTcl对象, 然后OTcl对象提示错误信息(error message)给用户。 这样,OTcl空间中的用户不能控制C++对象的行为。

 

 

 

从C++中运行OTcl命令 Execute an OTcl command from C++.

 

当用C++实现一个新网络对象时, 可能需要运行OTcl命令在C++对象中。 Figure 21 示例了Figure 18中"MyAgent"的成员函数"MyPrivFunc"的实现, 它让OTcl解释器打印出私有的成员变量"my_var1"和"my_var2"的值。



 
Figure 21. Execute OTcl command from a C++ Object

 

从C++中运行OTcl命令, 必须先得到以静态成员函数形式声明的"Tcl::instance()" 的一个参照(reference), 通过它可以传递OTcl命令到解释器(the first line of "MyPrivFunc" does this)。 这个例子演示了2中方式去传递OTcl命令到解释器。 完整的OTcl命令传值函数(OTcl command passing functions)的列表请参考NS文档。

 

 

 

 

 

编译、运行并测试"MyAgent" 

 

通过运行和测试"MyAgent"例子去更好的理解NS提供的OTcl联接机制。

  1. 下载"ex-linkage.cc" 文件, 并保存在"ns-2"文件夹下。
  2. 打开"Makefile", 在object file list结尾加入add "ex-linkage.o"。
  3. 用"make"命令重新编译NS。
  4. 下载"ex-linkage.tcl"文件, 它包含了"MyAgent"测试OTcl命令。 (见Figure 22 for the input script and the result)
  5. 运行OTcl script 通过命令"ns ex-linkage.tcl"。



 


 
Figure 22. Test OTcl Script and The Result

 

 

 

 

 

 

 

 

 

MyAgent C++ (ex-linkage.cc)源代码

#include <stdio.h>
#include <string.h>
#include "agent.h"


class MyAgent : public Agent {
public:
        MyAgent();
protected:
        int command(int argc, const char*const* argv);
private:
        int    my_var1;
        double my_var2;
        void   MyPrivFunc(void);
};


static class MyAgentClass : public TclClass {
public:
        MyAgentClass() : TclClass("Agent/MyAgentOtcl") {}
        TclObject* create(int, const char*const*) {
                return(new MyAgent());
        }
} class_my_agent;


MyAgent::MyAgent() : Agent(PT_UDP) {
       bind("my_var1_otcl", &my_var1);
       bind("my_var2_otcl", &my_var2);
}


int MyAgent::command(int argc, const char*const* argv) {
      if(argc == 2) {
           if(strcmp(argv[1], "call-my-priv-func") == 0) {
                  MyPrivFunc();
                  return(TCL_OK);
           }
      }
      return(Agent::command(argc, argv));
}


void MyAgent::MyPrivFunc(void) {
      Tcl& tcl = Tcl::instance();
      tcl.eval("puts \"Message From MyPrivFunc\"");
      tcl.evalf("puts \"     my_var1 = %d\"", my_var1);
      tcl.evalf("puts \"     my_var2 = %f\"", my_var2);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值