NS2学习(1)——分裂对象模型

来源:互联网 发布:域名邮箱反差 编辑:程序博客网 时间:2024/05/16 09:33

      NS2使用了C++和OTcl两种不同的编程语言,其中C++负责后端的封包处理,OTcl负责前端的控制管理。如此有很多优势,却也增加了学习门槛。许多类,许多方法,好像怎么理都理不清,无奈写文记下,以备查看。这里以TCP协议为例,按照执行顺序一步步查看源码,大致上理解所谓“分裂对象模型”,具体细节以后再慢慢总结了。

      例子中涉及到两个类:编译类TcpAgent和解释类Agent/TCP,这两个类由类TCPClass连接。

一.   OTcl注册的过程
ns启动后,因为class_tcp是静态对象,所以首先建立。


文件:~ns/tcp/tcp.cc
源代码:
static class TcpClass : public TclClass {
public:
 TcpClass() : TclClass("Agent/TCP") {}
 TclObject* create(int , const char*const*) {
  return (new TcpAgent());
 }
} class_tcp

 

建立静态对象class_tcp的步骤:

1.首先会执行父类TclClass的构造函数(参数为Agent/TCP)
2.执行TcpClass的构造函数(不执行任何操作)                                                     

 

步骤1.执行父类TclClass的构造函数,主要功能为存储类名和调用TclClass::bind()方法。


文件:~tclcl/Tcl.cc
源代码:
TclClass::TclClass(const char* classname) : class_(0), classname_(classname) 

                                                               //存储类名Agent/TCP至 classname_
{
 if (Tcl::instance().interp()!=NULL) {

 

  bind();                                                     //调用bind()函数,定义如下
 } else {
   
  next_ = all_;
  all_ = this;
 }
}

bind()函数定义如下
void TclClass::bind()
{
 Tcl& tcl = Tcl::instance();                                                     //获取Tcl句柄
 tcl.evalf("SplitObject register %s", classname_);  

                                                                    //(1)调用SplitObject的过程register{}
 class_ = OTclGetClass(tcl.interp(), (char*)classname_); 

                                                                   //将字符串转为class pointer
 OTclAddIMethod(class_, "create-shadow",
         (Tcl_CmdProc *) create_shadow, (ClientData)this, 0);
 OTclAddIMethod(class_, "delete-shadow",
         (Tcl_CmdProc *) delete_shadow, (ClientData)this, 0);
 //为解释类Agent/TCP增加了两个过程 create-shadow{}和delete-shadow{},以便调用TclClass::create_shadow()和TclClass::delete_shadow()

 otcl_mappings();
}

(1)调用SplitObject的过程register{}
文件:~tclcl/tcl-object.tcl
源代码:
SplitObject proc register className {
 set classes [split $className /]
 set parent SplitObject
 set path ""
 set sep ""
 foreach cl $classes {
  set path $path$sep$cl
  if ![$self is-class $path] {
   Class $path -superclass $parent
  }
  set sep /
  set parent $path
 }
}
功能:在解释类层次的路径上依次建立多个新的解释类。例子中Agent解释类已经存在,所以只建立Agent/TCP一个解释类,并将其置入解释类层次。

 

至此完成了TclClass的构造函数的初始化工作。

 

 


二.实例化的过程
1.建立split object
当你在Tcl脚本中使用语句 set tcp [new Agent/TCP]时,即调用了全局过程new{}


文件:~tclcl/tcl-object.tcl
源代码:
proc new { className args } {
 set o [SplitObject getid]       

                                       //调用SplitObject的过程getid{}, 为将要建立的Otcl实例取得UID                        
 if [catch "$className create $o $args" msg] {                    //(1)实例化Agent/TCP
  if [string match "__FAILED_SHADOW_OBJECT_" $msg] {

   delete $o
   return ""
  }
  global errorInfo
  error "class $className: constructor failed: $msg" $errorInfo
 }
 return $o
}

(1)实例化Agent/TCP
          代码"$className create $o $args"使用Agent/TCP的过程create{}来实例化Agent/TCP,但是Agent/TCP是由编译类利用TclClass机制产生的,而由此机制自动建立的解释类只被增加了两个过程,即 create-shadow{} 和delete-shadow{}。因此应调用其父类Agent的create{}过程,但是Agent类也是由编译类自动产生,同理应调用Agent的父类SplitObject的create{}过程。但是在~tclcl/tcl-object.tcl 中,SplitObject并沒有create{}过程,所以此处的 create{}应该是直接使用 Class(OTcl 中所有 classes 的 root)所定义的过程create{}。

          依据OTcl的说明网页(~otcl/doc/class.html),create{}会执行alloc{},并调用Agent/TCP的init{}过程。依序执行完所有解释类的init{}后,Agent/TCP的实例(一个split object):tcp,就完成了建立工作。


2.建立shadow object
      因为要建立的OTcl object属于split object,所以最后会调用SplitObject的init{},来建立相应的shadow object。


文件:~tclcl/tcl-object.tcl
源代码:
SplitObject instproc init args {
 $self next
 if [catch "$self create-shadow $args"] {                      //(1)调用create_shadow()
  error "__FAILED_SHADOW_OBJECT_" ""
 }
}
(1)调用create_shadow()
$self即Agent/TCP的实例,所以调用的是Agent/TCP的create-shadow{}过程,其对应的方法是TclClass::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);                   //(2)调用TcpClass::create()
 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());
  OTclAddPMethod(OTclGetObject(interp, argv[0]), "cmd",
          (Tcl_CmdProc *) dispatch_cmd, (ClientData)o, 0);
  OTclAddPMethod(OTclGetObject(interp, argv[0]), "instvar",
          (Tcl_CmdProc *) dispatch_instvar, (ClientData)o, 0);
                                                                        //增加两个过程cmd{}和instvar{}
  o->delay_bind_init_all();
  return (TCL_OK);
 } else {
  tcl.resultf("new failed while creating object of class %s",
       p->classname_);
  return (TCL_ERROR);
 }
}
(2)调用TcpClass::create()
此过程见文章开头,只有一条语句return (new TcpAgent());至此建立了shadow object,即TcpAgent,在文件~ns/tcp/tcp.cc中定义。

 

    先记下这些了,有点条理了,只是还有很多细节函数没有解释清楚,以后再接再厉了。

 

参考:

http://203.208.37.132/search?q=cache:I90w-_gM7-EJ:203.68.111.3:8080/97_1_course/CSIE_G_ACN/03_c_in_OTcl.pdf+C%2B%2B%E4%B8%8EOtcl&cd=27&hl=zh-CN&ct=clnk&gl=cn&client=aff-cs-360se&st_usg=ALhdy29Sa2TiDgok7Wk68JgcAxy7JEgs9w

 

原创粉丝点击