NS2初学笔记(三)之 最详细讲解ns2运行机制

转载自http://blog.csdn.net/kgn28/article/details/3058810

至于第三点我解释如下:

3,至于ns2的两种语言的交互过程网上有几篇帖子介绍的已经非常的详细了,但还是因为高手们把有一些东西省略了,从而对我这种初学者造成了一定的困难,为了以后的“Beginner”们能够更快的捋顺关系,早日入门ns2,我还是要按我的方法说一下。ns2是这么做的,每一个类都有一个Otcl类和一个c++类,每个需要交互的c++类都有一个链接类(该类包括一个方法,该方法实例化一个指定的类并且返回一个指向该实例的一个指针),该链接类通过其父类的构造方法在编译阶段注册一个方法到TclLinkage(otcl类可以找到并且可以调用该方法),这样在Otcl类初始化一个一个类的时候,调用之前注册过的方法,就可以初始化一个c++类了,并且还会注册一个使得Otcl类可以调用c++的类的方法——通过顺序查找实现的。这样以后在Otcl类就可以调用c++类中的方法了,说的有点乱,但是如果你看过一个例子,就会觉得我说的有道理了。

还是调用网上某位高手的一个例子吧,在这里我就补充说明一下tclunknown机制。

static class ChannelClass : public TclClass {

public:

    ChannelClass() : TclClass("Channel") {}

     TclObject*create(int, const char*const*) {

         return(new Channel);

     }

} class_channel

 

ns instantiating the class_channel object,它会invoke ChannelClass:ChannelC

 

lass();

这会首先invoke TclClass:TclClass("Channel");

 

Tcl.cc文件中:

TclClass::TclClass(const char* classname) : class_(0),classname_(classname)

{

         #如果Otcl语言解释器已存在的话:

         bind();

}

 

void TclClass::bind()

{

          #首先获取Tcl

     Tcl&tcl = Tcl::instance();

 

          #Otcl环境中注册该类名:Channel

          #并且该类的父类是SpliteObject

         #Note:SpliteObject存在于otcl环境中,C++中的TclObject相对应

         tcl.evalf("SplitObject register %s", classname_);

 

          #注册了之后,为这个类添加两个命令:create-shadowdelete-shadow

         #Note:the implementation procedures of these two methods就是

         #TclClass::create_shadow()TclClass::delete_shadow().

          class_= OTclGetClass(tcl.interp(), (char*)classname_);

         OTclAddIMethod(class_, "create-shadow",

               create_shadow, (ClientData)this, 0);

         OTclAddIMethod(class_, "delete-shadow",

               delete_shadow, (ClientData)this, 0);

         otcl_mappings();

}

 

然后当你在ns环境中敲入:new Channel

 

在文件tcl-object.tcl:

proc new { className args } {

     set o[SplitObject getid]

 

          #调用了该类的create函数,Channel:create()函数

          #也就是调用了SpliteObject:create()函数

         if[catch "$className create $o $args" msg] {

            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

}

 

但是SpliteObject并没有implementcreate() 函数,

但是你别忘了在otcl环境中,SpliteObject类是这样声明的:Class SpliteObject

所以这会调用ClassCreate函数

 

Class instproc create() {

...

alloc();

init();

...

}

 

这就会调用SpliteObject instproc init()函数

SplitObject instproc init args {

     $self next

 

          #调用类的create-shadow函数

          #在这个例子中,就是调用了Channel instproc create_shadow函数

          #也就是调用了TclClass::create-shadow()函数,因为在之前的bind()方法中有将这两种操作对应起来。

     if [catch"$self create-shadow $args"] {

         error"__FAILED_SHADOW_OBJECT_" ""

     }

}

 

int TclClass::create_shadow(ClientData clientData,Tcl_Interp *interp,

                int argc, char *argv[])

{

     TclClass* p= (TclClass*)clientData;

 

          #在这里调用了ChannelClass::create()函数

          #也就是调用了C++环境中的:new Channel

          #到这里为止,otcl中的Channelshadow object就生成了

     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);

             deleteo;

            return (TCL_ERROR);

         }

        tcl.result(o->name());

 

                #在这里再次为otcl中的类Channel添加两个instproc:cmdinstvar

                #其中cmd命令是meet the Tcl Unknown mechanism

(如果有同名的tcl方法就调用该方法,如果没有该方法当然是unknown了。

                 #这样的话,当你在ns脚本中输入了一个该类未知的命令,

                #Tclunknown机制就会调用该类的cmd命令

#/tclcl/tcl-object.tcl

SplitObject instproc unknown args {

    if [catch"$self cmd $args" ret] {

        set cls[$self info class]

        globalerrorInfo

        setsavedInfo $errorInfo

        error"error when calling class $cls: $args" $savedInfo

    }

    return $ret

}

               #而这进一步的就会调用该类的shadow objectcommand()过程

                #所以在实现类的C++部分时,你必须实现该类的Command()过程

                #command()中实现所有的命令分发

        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);

     }

}

通过上面的例子可以了解到Otcl可以调用c++类中的方法,而c++中的类可不可以调用Otcl类中的方法呢,答案是可以的,是通过得到一个Tcl实例来实现的,具体请参考everything.pdf里面有详细的介绍(其实我总解的这些也是通过在总结一下学习该文档的经验而已,这个文档真的可以称得上是everything了,包括了ns2的一切内容,就是太长了)。
展开阅读全文

没有更多推荐了,返回首页