原文地址:http://nile.wpi.edu/NS/linkage.html
图18
1.将C++类导出至OTcl
假定你已经使用C++创建了一个新的网络对象类,比如继承自Agent类的MyAgent,并且你想在OTcl中创建该对象的实例。为此,你必须定义一个继承自TclClass的连接对象,比如MyAgentClass。该连接对象用于创建一个有着特定名称(如该例的Agent/MyAgentOtcl)的OTcl对象,并且在OTcl对象和C++对象(如该例中的MyAgent)之间创建连接。并且在C++对象的create成员函数中指定了实例的开始过程(launching procedure)。
2.将C++变量导出至OTcl
假设你的新的C++对象MyAgent中有两个参数变量,比如my_var1和my_var2,这两个变量必须够够通过使用OTcl模拟脚本来很容易地进行配置(或改变)。为此,你应当对C++类中的每个你想导出的变量使用绑定函数。绑定函数在对应的OTcl对象类(如Agent/MyAgentOtcl)中使用给定的名字(第一个参数)创建新的成员变量,并且建立在OTcl变量和C++变量(变量的地址通过第二个参数确定)之间的双向绑定。图19显示了怎样对图18中的两个变量my_var1和my_var2进行绑定。
图19
注意,为了在对象的实例被创建时建立绑定,绑定函数应放置在MyAgent的构造函数内。NS支持4种不同的绑定函数,适用于如下5种不同的变量类型:
- bind(): 浮点型和整型变量
- bind_time(): 时间变量
- bind_bw(): 带宽变量
- bind_bool(): 布尔变量
通过这种方法,使用OTcl脚本来设计并进行模拟的用户可以对使用C++实现的网络组件中的可以配置的参数(或者变量值)进行访问或者改变。注意,强烈建议无论何时导出一个C++变量,都应当同时在ns-2/tcl/lib/ns-lib.tcl中设置该变量的默认值。否则,当创建新对象的实例时会有警告信息。
3 .将C++对象控制命令导出至OTcl
图20.一个OTcl命令解释器除了要导出你的C++对象的一些变量之外,你可能还想让OTcl得到你的C++对象的控制权。这可以通过定义你的C++对象(例如,MyAgent)的command成员函数来实现。该成员函数充当OTcl命令的解释器的角色。事实上,在C++对象的command成员函数中定义的OTcl命令看起来与相应的展示给用户的OTcl对象的成员函数相同。图20是一个一个对图18中的MyAgent对象的command成员函数的定义例子。
图20
当匹配MyAgent对象的OTcl影像对象的实例在OTcl内被创建(例如,使用了set myagent [newAgent/MyAgentOtcl]命令),并且用户试图调用该对象的成员函数时(例如,使用$myagentcall-my-priv-func),OTcl会在OTcl对象中搜索给定的成员函数名。如果给定的成员函数名未能找到,那么将会调用MyAgent::command来以“参数名/参数值”的形式传递被调用的OTcl成员函数的参数的名称和参数值。如果在command成员函数中存以在被调用的OTcl成员函数的名称定义的操作,那它执行请求并返回结果。如果不存在,command成员函数的祖先会被依次递归调用,直到发现该名称。如果在任何一个祖先中都未能发现该名称,则返回给OTcl对象一个错误信息,并且该OTcl对象显示给用户一条错误信息。通过这种方式,用户可以在OTcl内控制C++对象的行为。
4.从C++中执行OTcl命令
如果你用C++实现了一个新的网络对象,你或许从C++对象中执行一条OTcl命令。图21显示了图18中的MyAgent对象的MyPrivFunc成员函数的实现。它让OTcl解释器打印出私有成员变量my_var1和my_var2的值。
为了从C++中执行一条OTcl命令,你应当取得到Tcl::instance()的引用(reference),该引用被声明为一个成员变量。它给你提供了若干函数,使用这些函数,你可以给解释器传递OTcl命令(MyPrivFunc的第一行)。该例展示了想解释器传递OTcl命令的两种方法。要取得OTcl命令传递函数的完整列表,请参考NS手册。
图21
5.编译,运行和测试
至今为止,我们使用MyAgent例子检测了NS中基本的OTcl连接的可用性。假设运行并且测试该例子可以帮助读者理解得更加深刻。我们给了一个可以帮助你编译、运行、测试MyAgent的步骤。