[我在之前看的是以ping协议为实例来理解TclCL机制和分裂对象模型]

本文以channel实例的创建过程为例,试图说明ns2的分裂机制,请在阅读本文前阅读《The NS Manual》有关分裂机制章节,由于篇幅有限,作者能力有限,本文章不能分析得非常彻底,时间仓促,有不当之处请大家给予批评指正。

一、定义信道基类

  1. 定义channel的 C++类

#ns-2.31macchannel.h

class Channel : public TclObject {

public:

Channel(void);

virtual int command(int argc, const char*const* argv);

... ... ...

};

  1. 定义用于连接的类

#ns-2.31macchannel.cc

static class ChannelClass : public TclClass {

public:

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

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

return (new Channel);

}

}class_channel ;

[注意]一个类声明为static,那么当ns刚开始初始化的时候,便会调用该类的构造函数,当静态变量class_channel 第一次被创建时,ns 将执行其构造函数,这就建立了适当的方法和解释类层次.具体解释请看第三节Otcl注册过程

二、Otcl注册过程

继续第一节,当ns初始化时会创建实体class_channel,它会调用类的构造函数ChannelClass() : TclClass("Channel") {}

首先执行TclClass:TclClass("Channel"),"Channel" 会传给参数此classname_ .

下面我们看一下TclClass()的具体实现

//->tclcl-1.19Tcl.cc

TclClass* TclClass::all_; //[problem]什么意思? 在c++里

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

{

if (Tcl::instance().interp()!=NULL) {

#解释器已经存在,解释器是一个动态连接库的一部分

bind(); # 变量绑定函数

} else {

... ... ...

}

}

void TclClass::bind()

{

Tcl& tcl = Tcl::instance();

//获取Tcl 句柄 [参考1]

tcl.evalf("SplitObject register %s", classname_); # $classname_ == "Channel"

//上句利用句柄调用otcl命令,在Otcl环境中注册该类名:Channel

该类的父类是SpliteObject

//SpliteObject是一个具有C++映像类的OTcl类,他是所有OTcl映像类的基类

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

# 调用命令就是TclClass::create_shadow(),TclClass::delete_shadow().

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

//class_

OTclAddIMethod(class_, "create-shadow",

(Tcl_CmdProc *) create_shadow, (ClientData)this, 0);

OTclAddIMethod(class_, "delete-shadow",

(Tcl_CmdProc *) delete_shadow, (ClientData)this, 0);

otcl_mappings();

}

下边来讲讲我们在tcl脚本里自己能控制的实例化过程

四、实例化过程
然后当你在tcl 脚本中调用 new Channel时,ns2使用tclsh解释执行tcl脚本, 调用tcl函数new函数

//tclcl-1.19/tcl-object.tcl

146 proc new { className args } {

set o [SplitObject getid]

#得到一个新的分裂实体编号"_o*" _o*有类SplitObject 的变量 id 标识,从_o0开始

#可见在每一个Simulator对应的模拟中"_o*"标示唯一的一个分裂类实体,

#也就是说,所有的分裂类实体都有自己的唯一标识 ,这个标识就是句柄

#注意SplitObject 与 TclObject 的关系

if [catch "$className create $o $args" msg] { #创建实体

if [string match "__FAILED_SHADOW_OBJECT_" $msg] {

# 如果创建影像类失败,删除 o对象

delete $o

return ""

}

global errorInfo

error "class $className: constructor failed: $msg" $errorInfo

}

return $o

}

但是SpliteObject并没有create函数, 所以动态调用其父类 Class 的 create 函数

Class instproc create {obj args} { # obj是 _oxxx了

set h [$self info heritage] # 取得类继承链测试结果是“SplitObject Object”

foreach i [concat $self $h] {

#沿着继承链从子类到父类递归产生相应实体

#concat后字符串为:”Channel SplitObject Object”

if {[$i info commands alloc] != {}} then { # 判断命令alloc的是否存在

set args [eval [list $i] alloc [list $obj] $args] # 分配空间

$obj class $self

eval [list $obj] init $args #调用init,最终导致shadow对象的产生

return $obj

}

}

error {No reachable alloc}

}

上面调用的init 会动态调用 SpliteObject instproc init()

SplitObject instproc init args {

$self next

#调用类的create-shadow函数

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

error "__FAILED_SHADOW_OBJECT_" ""

}

}

在这个例子中,动态调用了Channel instproc create_shadow函数,channel没有次函数,调用父类的,实质上最后调用了TclClass::create-shadow()函数,创建

int TclClass::create_shadow(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])

{

TclClass* p = (TclClass*)clientData; #把channel指针转换为父类型的指针

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

#也就是调用了C++环境中的:new Channel 见函类ChannelClass定义

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

TclObject* o = p->create(argc, argv);

#动态调用那个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());

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

# 其中cmd命令是用来运行处理未知命令机制的

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

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

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

# 所以在实现类的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);

}

}

【NS2】NS2机制浅显分析一下(转载)的更多相关文章

  1. Java虚拟机类加载机制——案例分析

    转载: Java虚拟机类加载机制--案例分析   在<Java虚拟机类加载机制>一文中详细阐述了类加载的过程,并举了几个例子进行了简要分析,在文章的最后留了一个悬念给各位,这里来揭开这个悬 ...

  2. Redis 发布/订阅机制原理分析

    Redis 通过 PUBLISH. SUBSCRIBE 和 PSUBSCRIBE 等命令实现发布和订阅功能.   这些命令被广泛用于构建即时通信应用,比如网络聊天室(chatroom)和实时广播.实时 ...

  3. Android 中View的绘制机制源代码分析 三

    到眼下为止,measure过程已经解说完了,今天開始我们就来学习layout过程.只是在学习layout过程之前.大家有没有发现我换了编辑器,哈哈.最终下定决心从Html编辑器切换为markdown编 ...

  4. Android AdapterView 源码分析以及其相关回收机制的分析

    忽然,发现,网上的公开资料都是教你怎么继承一个baseadapter,然后重写那几个方法,再调用相关view的 setAdpater()方法, 接着,你的item 就显示在手机屏幕上了.很少有人关注a ...

  5. 10.hibernate缓存机制详细分析(转自xiaoluo501395377)

    hibernate缓存机制详细分析   在本篇随笔里将会分析一下hibernate的缓存机制,包括一级缓存(session级别).二级缓存(sessionFactory级别)以及查询缓存,当然还要讨论 ...

  6. Netfilter之连接跟踪实现机制初步分析

    Netfilter之连接跟踪实现机制初步分析 原文: http://blog.chinaunix.net/uid-22227409-id-2656910.html 什么是连接跟踪 连接跟踪(CONNT ...

  7. 阿里系产品Xposed Hook检测机制原理分析

    阿里系产品Xposed Hook检测机制原理分析 导语: 在逆向分析android App过程中,我们时常用的用的Java层hook框架就是Xposed Hook框架了.一些应用程序厂商为了保护自家a ...

  8. Android 中View的绘制机制源代码分析 一

    尊重原创: http://blog.csdn.net/yuanzeyao/article/details/46765113 差点儿相同半年没有写博客了,一是由于工作比較忙,二是认为没有什么内容值得写, ...

  9. Android 中View的绘制机制源代码分析 二

    尊重原创:http://blog.csdn.net/yuanzeyao/article/details/46842891 本篇文章接着上篇文章的内容来继续讨论View的绘制机制,上篇文章中我们主要解说 ...

随机推荐

  1. 跟我一起了解koa(一)

    安装koa2 1.初始化package.json npm init 2.新建app.js,并且安装koa cnpm install --save koa //app.js const koa = re ...

  2. 浅谈java.util.ConcurrentModificationException(并发修改异常)

    java中的list集合是我们经常使用的集合,而对集合进行增加和删除元素是我们最常用的操作.那么在什么时候对list集合什么样的操作,就会发生java.util.ConcurrentModificat ...

  3. Rabbitmq交换机三种模式介绍

    1.topic 将路由键和某模式进行匹配.此时队列需要绑定要一个模式上.符号“#”匹配一个或多个词,符号“*”匹配不多不少一个词.因此“abc.#”能够匹配到“abc.def.ghi”,但是“abc. ...

  4. LintCode刷题笔记-- Maximum Product Subarray

    标签: 动态规划 描述: Find the contiguous subarray within an array (containing at least one number) which has ...

  5. ngVerify - 更高效的 angular 表单验证

    ngVerify v1.5.0 a easy Angular Form Validation plugin.简洁高效的__angular表单验证插件__ See how powerful it.看看它 ...

  6. redis的安装,以及主从实现同步

    Redis的主从复制功能非常强大,一个master可以拥有多个slave,而一个slave又可以拥有多个slave,如此下去,形成了强大的多级服务器集群架构.下面我演示下怎样在多台服务器上进行Redi ...

  7. Listview的条目item内的点击响应事件

    还是这张图 这里的历史列表就是一个ListView,抛开该界面中ScrollView或者RecycleView与该ListView会有冲突,所谓的冲突,说白了就是父控件与子控件两者间的关系冲突,该冲突 ...

  8. PHP判断一个文件是否能够被打开

    <?php // 需求:因为系统涉及大量的文档知识库,用户可以在线进行查看.为了验证文档是否正常打开.先需要从数据库取出路径和文件名,判断是否可以从对应的路径下打开文件.header(" ...

  9. TypeScript高级类型

    交叉类型 将多个类型合并成一个类型,去两个类型的并集.与继承的区别是,继承可以有自己的属性,而交叉没有. interface DogInterface { run():void } interface ...

  10. 2017年浙工大迎新赛热身赛 J Forever97与寄信 【数论/素数/Codeforces Round #382 (Div. 2) D. Taxes】

    时间限制:C/C++ 1秒,其他语言2秒空间限制:C/C++ 131072K,其他语言262144K64bit IO Format: %lld 题目描述 Forever97与未央是一对笔友,他们经常互 ...