OTcl与C++交互—AODV路由协议

我们先来看看Otcl脚本:

set val(chan)       Channel/WirelessChannel      ;#无线信道类型
set val(prop)       Propagation/TwoRayGround     ;#无线传输模型
set val(netif)      Phy/WirelessPhy              ;#网络接口类型
set val(mac)        Mac/802_11                   ;#MAC层协议
set val(ifq)        Queue/DropTail/PriQueue      ;#队列接口类型
#set val(ifq)       CMUPriQueue                  ;#队列接口类型,DSR协议
set val(ll)         LL                           ;#逻辑链路层类型
set val(ant)        Antenna/OmniAntenna          ;#天线模型
set val(adhocRouting)   AODV                     ;#无线路由协议
••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
#配置无线节点
$ns_ node-config -adhocRouting $val(adhocRouting) \
                 -llType $val(ll) \
                 -macType $val(mac) \
                 -ifqType $val(ifq) \
                 -ifqLen $val(ifqlen) \
••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••


上面的代码描述了无线节点会通过AODV路由协议来进行配置,现在看看AODV路由协议是怎么执行的。在aodv.cc中:

static class AODVclass : public TclClass {
public:
        AODVclass() : TclClass("Agent/AODV") {} //构造函数调用其基类的构造函数
        TclObject* create(int argc, const char*const* argv) {
          assert(argc == 5);
          //return (new AODV((nsaddr_t) atoi(argv[4])));
//返回一个新建的编译类的实例对象
      return (new AODV((nsaddr_t) Address::instance().str2addr(argv[4])));
        }
} class_rtProtoAODV;

类AODVclass实际上只有两个函数:构造函数和creat()函数。构造函数AODVclass()实际上调用了其父类TclClass的构造函数,并且传递了Agent/AODV作为参数。接下来看看TclClass是如何工作的:

TclClass::TclClass(const char* classname) : class_(0), classname_(classname)
{
    if (Tcl::instance().interp()!=NULL) {//如果解释器存在
                bind();
    } else {

        next_ = all_;
        all_ = this;
    }
}

下面看看bind()函数是如何执行的:

void TclClass::bind()
{
    Tcl& tcl = Tcl::instance();
//在Otcl环境中注册类名:Agent/AODV。其父类是SplitObject
    tcl.evalf("SplitObject  register %s", classname_);
    class_ = OTclGetClass(tcl.interp(), (char*)classname_);
//这两行代码实际上是为这个类创建了create-shadow和delete-shadow这两个命令
// create-shadow是创建OTcl影像类的命令
    OTclAddIMethod(class_, "create-shadow",
               create_shadow, (ClientData)this, 0);
    OTclAddIMethod(class_, "delete-shadow",
               delete_shadow, (ClientData)this, 0);
    otcl_mappings();
}

此时我们已经在OTcl环境中注册了OTcl类:Agent/AODV。但是对应于Otcl解释类的编译类还没有被构造,并且也没有被关联。

当我们在OTcl脚本中使用AODV配置节点时,会创建一个OTcl解释类对象实例,这就会调用tclcl-1.15\tcl-object.tcl中的new过程

proc new { className args } {
    set o [SplitObject getid]
    if [catch "$className create $o $args" msg] {//调用了该类的creat函数
        if [string match "__FAILED_SHADOW_OBJECT_" $msg] {
            #
            # The shadow object failed to be allocated.
            # 
            delete $o
            return ""
        }
        global errorInfo
        error "class $className: constructor failed: $msg" $errorInfo
    }
    return $o
}

上面显示的调用了该类的creat函数,实际上是调用了Agent/AODV:creat(),实际上也是调用了其父类SplitObject的creat()函数,SplitObject实际上没有creat()函数,它调用了Classcreate()函数

Class instproc create {obj args} {              
  set h [$self info heritage]                   
  foreach i [concat $self $h] {                 
    if {[$i info commands alloc] != {}} then {  
      set args [eval [list $i] alloc [list $obj] $args]       
      $obj class $self                          
      eval [list $obj] init $args   ;#调用了init过程                   
      return $obj                               
    }                                           
  }                                             
  error {No reachable alloc}                    
}
这实际上又调用了SplitObject的init()函数
SplitObject instproc init args {
    $self next
    if [catch "$self create-shadow $args"] {
        error "__FAILED_SHADOW_OBJECT_" ""
    }
}
这实际上调用了Agent/AODV 的create-shadow()函数
int TclClass::create_shadow(ClientData clientData, Tcl_Interp *interp,
                int argc, CONST84 char *argv[])
{
    TclClass* p = (TclClass*)clientData;
    TclObject* o = p->create(argc, argv);
    Tcl& tcl = Tcl::instance();
    if (o != 0) {
        o->name(argv[0]);
        tcl.enter(o);
        if (o->init(argc - 2, argv + 2) == TCL_ERROR) {
            tcl.remove(o);
            delete o;
            return (TCL_ERROR);
        }
        tcl.result(o->name());
//在这里添加了两个命令:cmd和instvar。
        OTclAddPMethod(OTclGetObject(interp, argv[0]), "cmd",
                   dispatch_cmd, (ClientData)o, 0);
        OTclAddPMethod(OTclGetObject(interp, argv[0]), "instvar",
                   dispatch_instvar, (ClientData)o, 0);
        o->delay_bind_init_all();
        return (TCL_OK);
    } else {
        tcl.resultf("new failed while creating object of class %s",
                p->classname_);
        return (TCL_ERROR);
    }
}



cmd()命令激活影像对象的command()方法,并将cmd()的参数以向量形式传递给command()方法,因此此函数必须实现,其用途就是用来接收cmd()传递的OTcl命令。














原文链接: https://www.cnblogs.com/yue-/archive/2012/06/10/6260054.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/52415

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月9日 上午3:52
下一篇 2023年2月9日 上午3:52

相关推荐