NS2机制

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

一、定义信道基类

  1. 定义channel的 C++类

#ns-2.31\mac\channel.h

class Channel : public TclObject {

public:

Channel(void);

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

... ... ...

};

  1. 定义用于连接的类

#ns-2.31\mac\channel.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.19\Tcl.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);

        }

}

时间: 2024-08-01 00:54:12

NS2机制的相关文章

NS2

NS是一种针对网络技术的源代码公开的.免费的软件模拟平台,研究人员使用它可以很容易的进行网络技术的开发,而且发展到今天,它所包含的模块已经非常丰富,几乎涉及到了网络技术的所有方面.所以,NS成了目前学术界广泛使用的一种网络模拟软件.在每年国内外发表的有关网络技术的学术论文中,利用NS给出模拟结果的文章最多,通过这种方法得出的研究结果也是被学术界所普遍认可的,此外,NS也可作为一种辅助教学的工具,已被广泛应用在了网络技术的教学方面.因此,目前在学术界和教育界,有大量的人正在使用或试图使用NS. 然

Linux Namespace机制简介

最近Docker技术越来越受到关注,作为Docker中很重要的一项技术,Namespace也就经常在Docker的简介里面看到. 在这里总结一下它的内部机制.也解决一下自己原来的一些疑惑. Namespace是什么: C++中的Namespace: 首先,先提一下Namespace是什么.最早知道这个名词是在学习C++语言的时候.由于现在的系统越来越复杂,代码中不同的模块就可能使用相同变量,于是就出现了Namespace,来对全局作用域进行划分. 比如C++的标注库都定义在STD Namespa

link中使用动态算子实现排序的机制是什么,怎么样能优化?

问题描述 link中使用动态算子实现排序的机制是什么,怎么样能优化? link中使用动态算子实现排序的机制是什么,怎么样能优化? 解决方案 使用dynamic其实是运行时反射,要想效率高,用查询表达式,google MakeMemberAccess LINQ

[转载]Linux 线程实现机制分析

  自从多线程编程的概念出现在 Linux 中以来,Linux 多线应用的发展总是与两个问题脱不开干系:兼容性.效率.本文从线程模型入手,通过分析目前 Linux 平台上最流行的 LinuxThreads 线程库的实现及其不足,描述了 Linux 社区是如何看待和解决兼容性和效率这两个问题的.   一.基础知识:线程和进程 按照教科书上的定义,进程是资源管理的最小单位,线程是程序执行的最小单位.在操作系统设计上,从进程演化出线程,最主要的目的就是更好的支持SMP以及减小(进程/线程)上下文切换开

[Android] 缓存机制

移动开发本质上就是手机和服务器之间进行通信,需要从服务端获取数据.反复通过网络获取数据是比较耗时的,特别是访问比较多的时候,会极大影响了性能,Android中可通过缓存机制来减少频繁的网络操作,减少流量.提升性能. 实现原理 把不需要实时更新的数据缓存下来,通过时间或者其他因素 来判别是读缓存还是网络请求,这样可以缓解服务器压力,一定程度上提高应用响应速度,并且支持离线阅读.  Bitmap的缓存 在许多的情况下(像 ListView, GridView 或 ViewPager 之类的组件 )我

8天玩转并行开发——第五天 同步机制(下)

         承接上一篇,我们继续说下.net4.0中的同步机制,是的,当出现了并行计算的时候,轻量级别的同步机制应运而生,在信号量这一块 出现了一系列的轻量级,今天继续介绍下面的3个信号量 CountdownEvent,SemaphoreSlim,ManualResetEventSlim.   一:CountdownEvent      这种采用信号状态的同步基元非常适合在动态的fork,join的场景,它采用"信号计数"的方式,就比如这样,一个麻将桌只能容纳4个 人打麻将,如果

PHP的错误机制总结

PHP的错误机制总结 PHP的错误机制也是非常复杂的,做了几年php,也没有仔细总结过,现在就补上这一课. 特别说明:文章的PHP版本使用5.5.32 PHP的错误级别 首先需要了解php有哪些错误.截至到php5.5,一共有16个错误级别 注意:尝试下面的代码的时候请确保打开error_log: error_reporting(E_ALL); ini_set('display_errors', 'On'); E_ERROR 这种错误是致命错误,会在页面显示Fatal Error, 当出现这种错

Java的Package与Import机制之我的理解(初学者的心得)

初学|心得    以下内容的测试条件是你的机器上,设置了path命令PATH= D:\JDK1.4\BIN;D:\JDK1.4\LIB;,可以正常执行java和javac命令,不用设置classpath路径的情况下.       从一个简单的例子谈谈package与import机制 基本原则:为什么需要将Java文件和类文件切实安置到其所归属之Package所对应的相对路径下. 为什么要这样做呢?如果你在程序中,用到打包命令package,并且直接编译和执行该程序.例如:以下面程序为例: pac

mfc-MFC消息机制谁帮我做个注释,请逐行注释。不要回复无关内容

问题描述 MFC消息机制谁帮我做个注释,请逐行注释.不要回复无关内容 class CMsgFrame : public CFrameWnd { private: static const AFX_MSGMAP_ENTRY _messageEntries[]; protected: static AFX_DATA const AFX_MSGMAP messageMap; static const AFX_MSGMAP* PASCAL _GetBaseMessageMap(); virtual co