NS2仿真的整个流程调用过程

2024-01-20 23:18

本文主要是介绍NS2仿真的整个流程调用过程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

3.4 TclObject 类

当建立解释器的对象时,TclObject类会提供建立编译影子对象的方法。TclObject类属于C++类,与OTcl域中的SplitObject类相对应。这两个类是各自体系内除独立类以外的其他所有类的基类。当OTcl域内的一个对象开始初始化时,会调用基类SplitObject的构造函数来完成初始化。其中一项就是影子对象的初始化。

3.4.1 TclObject 类的引用

OTcl类和C++类接入他们各自对象的方法并不相同。作为编译器,C++直接访问分配给其对象的内存空间。作为解释器,OTcl并不直接访问内存空间,而是用一字符串作为对象的引用(句柄)。NS2规定,SplitObject的这个字符串的命名形式为_<NNN>,其中NNN是由各自的SplitObject产生的唯一序号。例如,_o10.

例子3.8 假设变量c_obj 和otcl_obj分别是C++和OTcl类的一个对象。表3.2列出了这两个C++和OTcl对象的引用值。

image

我们可以用下列代码来查看存在OTcl对象内的值:

set ns [new Simulator]

set tcp [new Agent/Tcp]

puts “The value of tcp is $tcp”

结果如下: "The value of tcp is _o10”

3.4.1 生成和销毁TclObject的影子对象

大多数情况下,TclObject的影子函数在OTcl域内生成和销毁,通常在Tcl仿真脚本当中实现。OTcl用命令creat和destroy来生成和销毁一个独立的OTcl对象。但是,这两个命令在NS2中很少用到。因为他们并不能用来生成影子编译函数。在NS2中,全局函数new{…}和delete{}则经常被用来生成和销毁对象,包括影子编译对象。

生成TclObject对象

全局函数new{…}可以用来生成一个新的TclObject,语法为   new<classname>[<args>]

Program 3.5 列出了new{}函数实现的细节

image

new{className args}函数有两个输入参数。第一个参数<className>(必须有)是OTcl的类名。第二个参数<args>(可选)是传给OTcl构造函数的输入参数。函数new{className args}生成了一个对象,className即为该对象的OTcl类和相应的影子对象的类名。如果构造过程成功,函数会返回引用句柄(11行),否则,会将错误信息打印至屏幕。(9行)

new{className args}函数的内部机制如下:首先第2行为对象检索了一个引用句柄,并存之于变量“O”。SplitObject 类的实例程序 getid()根据3.4.2小节中的的定义和命名规范生成引用句柄。而后,第3行生成了OTcl对象为className的对象,使其与存储在变量“O”的句柄对应。最后,如果对象被成功建立,11行返回引用句柄”O”给调用者,否者,屏幕上会出现错误信息(第9行)。

第3行的OTcl 命令Create调用了实例程序alloc{…}来给className类的对象分配内存空间,然后init{…}函数初始化对象。在大多数情况下,init{…} 会调用一个OTcl类的构造函数。每个类都会在构造函数中重载init{…}函数,定义自己的初始化步骤。

例子 3.9 产生一个OTcl Agent/TCP 对象,我们可以在仿真脚本中执行new Agent/TCP来实现。在解释体系中,Agent/TCP继承自Agent类,而Agent类继承自SplitObject .在编译体系,这三类则分别为TcpAgent类,Agent类和TclObject类。

image

图3.3 画出了Agent/TCP的对象(o)的生成过程。第一步是调用SplitObject类的实例程序getid{…}来获取引用句柄。其次调用上层的init{…}来初始化。在最顶层,SplitObject调用creat-shadow函数来生成影子编译对象(图3.3右侧)。

creat-shadow返回之后,Agent/TCP的初始化函数完成剩余的初始化工作,程序继续进行下去,直至到达Agent/TCP.然后,函数返回creat函数和new函数,返回已生成的对象“o”至调用者。

注意,以上函数用于生成一个连接编译体系的解释型TclObject。独立的C++或者OTcl对象并不需要任何的影子对象,因此不需要上面的过程。他们可以以正常的构造函数完成。

销毁TclObject

OTcl使用实例程序delete{…}来销毁一个解释型对象和其影子函数(通过调用delete-shadow)。实例程序Simulator::use-scheduler{…}调用delete函数删除现有的scheduler(如果需要,第3行),并使用全局函数new{…}生成Scheduler/$type.我们将会在第4章详细讨论实例程序Simulator::use-scheduler{…}的细节。

image

3.4.3 在编译体系和解释体系内绑定变量

通常,无论是解释对象还是影子对象都有它们自己的类变量,不允许互相直接访问自己的变量。因此,NS2提供了一项机制来绑定两个体系的变量。在绑定之后,任何一方已绑定对象的改变都会自动的改变另一个体系的绑定对象。

绑定变量

NS2在影子对象函数的构造函数中将解释类变量绑定于编译对象。TclObject类在构造函数中调用以下特定函数来绑定变量。

image

其中,iname和cname分别代表解释体系和编译体系的变量。本质上来说,第一个参数和第二参数分别为解释器的变量句柄和编译变量的地址。

例子3.10 .两个体系的Test类绑定。假设icount_,idelay_,ispeed_,ivirtuar_,iis_running_为OTcl类的变量,其类型分别为整数,实数,带宽,时间和布尔。下面这些代码为C++的Test类的构造函数:

image

所有的类变量都在编译体系下的构造函数中绑定。通常,我们约定,两个体系内需要绑定的变量名相同,在本例中只是为了说明起见。

设置默认值

NS2在~ns/tcl/lib/ns-default.tcl中设定绑定变量的初始值。语法如下:<className> set <instvar> <def_value>.意为将<className>类的instvar变量<instvar>的值设为<def_value>。

为了设定变量的默认值,NS2调用了SplitObject的实例程序init-instvar{…}。该函数从~ns/tcl/lib/ns-default.tcl中读取变量的默认值并赋值给绑定变量。如果我们绑定了某个变量却没有设置默认值,实例函数SplitObject::warn-instvar{…}将会在屏幕上产生一个警告信息,但如果默认值设置的是一个无效值(例如,没有绑定或不存在),NS2不会打印警告信息。

3.4.4 OTcl command

3.2.2小节指出了一种从编译体系内访问解释体系的方法。本节讨论的恰好相反:如何从解释体系内访问编译体系,该方法称为“命令 command”

回顾一下实例程序的调用机制

在我们具体讲解之前,让我们先回顾一下OTcl实例程序的调用机制。我们一般按下列步调用一个实例程序。

$obj <instproc> [<args>]

其中<instproc>为必须,<args>为可选。实例程序调用内部机制如下:

i) 在对象类中查找对应的实例程序名,如果找到,执行对应的实例函数并返回,如果没有找到,执行下一步。

ii) 查找实例函数unknow{…}.如果找到了,执行unknow{…}函数并返回,如果没有找到,执行下一步。实例程序unknown{…}是一个默认的实例程序,如果没有找到对应的实例程序,unknow{…}函数就会被调用。

iii)对对象的基类 重复步骤i)和ii)

iv)  如果调用至最顶层的基类,仍没有找到输入的实例程序和unknow{…}函数,报告错误并退出程序。

OTcl 命令调用

对OTcl命令的调用语法类似于实例程序: $obj <cmd_name> [<args>]

由于语法类似于调用实例程序,OTcl函数执行命令的方法类似于实例程序。下面,我们将讲述OTcl Agent/TCP对象命令的调用机制(见程序3.9)。图3.4画出了命令调用机制的内部机制:

image

i) 执行 “$tcp <cmd_name> <args>”语句

ii)在OTcl的Agent/TCP类中查找名为<cmd_name>的实例程序,如果找到,调用该实例函数并完成剩下的程序。否则,进行下一步。

iii)在OTcl的Agent/TCP类中查找unknown{…}函数,如果找到,调用unknown函数完成程序,否则,进行下一步。

iv)重复步骤ii)和iii),直至上溯到SplitObject类为止,若在继承树上的所有类中都没有找到unknown函数,NS2将会执行下列语句SplitObject unknown。SplitObject类的 unknown函数在~tclcl/tcl-object.tcl中定义。这里,将会执行"$self cmd $args”语句,其中args是unknown函数的输入参数,根据以上的调用,这语句变为 SplitObject cmd <cmd_args> ,其中<cmd_args> 为<cmd_name> <args>.

v) cmd 实例程序将整个语句(i,e.,”cmd <cmd_args>”)做为输入参数矢量(argv)给影子对象(此为TcpAgent)的“command(argc,argv)”函数。如程序3.9所示,该函数总是携带两个参数。第二个输入参数argv为字符数组,包含着由cmd传送过来的输入参数。第一个参数argc,是所有输入参数的个数(例如,argv中的非空元素的个数)。argv的第一个和第二个输入参数分别为cmd和命令名。剩余的元素包含着原始调用的输入参数。见表3.3

image

vi) command(argc,argv)函数检查argv中的参数个数和argv[1]中的命令名。如果对应,则会激发需要的程序(程序3.9中的第6-7行),并返回TCL-OK。如果不对应,程序将会跳到最后一行。

vii) 程序3.9中的第12行调用了基类的command(argc,argv)函数。

viii) 重复步骤vi)和vii),直至上溯至最顶层的类TclObject。若一直到TclObject类都没有相对应的命令,TclObject类的command函数将会报错,返回TCL_ERROR。

xi) 返回下边的类体系中。当到达C++类的TcpAgent类,带着返回值返回OTcl类(分别为cmd函数和unknown函数),完成命令调用。

OTcl命令的另一种调用方法

在上一部分中,我们用这个语法调用OTcl命令:

$tcp <cmd_name> <args>

该命令起始于图3.4中的位置(1).但是,还有另外一种的调用方式,该方式图3.4中的位置(2),语法如下:

$tcp cmd <cmd_name> <args>

第二种调用方式避免了实例程序和OTcl命令相同时候的麻烦。

OTcl命令的返回机制

执行了C++的程序之后,NS2会返回适当的返回值,在nsallinone-2.30/tcl8.4.13/generic/tcl.h,NS2定义了以下5种返回值(0~5),如程序3.10.通知了解释器命令调用结果。

image

TCL_OK: 命令执行完全正确。

TCL_ERROR: 命令没有完成,解释器将会解释错误原因。

TCL_RETURN:从C++返回以后,解释器从当前的实例程序中退出,不运行剩下的实例程序。

TCL_BREAK: 从C++返回以后,解释器终止当前循环,这类似于C++中的关键字break。

TCL_CONTINUE:从C++返回以后,解释器继续运行下面的程序。类似于C++中的关键字continue。

在以上5种类型中,TCL_OK和TCL_ERROR是最常用的两个。如果C++返回TCL_OK,解释器将会读取从C++域返回的值。回顾3.2.3节,解释器不读取返回值,而是阅读返回值指定的语句。TCL_OK命令只告诉OTcl,储存在tcl.result(…)的值是有效的。

 

原作地址:http://blog.sina.com.cn/s/blog_6405cfd20100n6jn.html

这篇关于NS2仿真的整个流程调用过程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/627667

相关文章

Java调用Python代码的几种方法小结

《Java调用Python代码的几种方法小结》Python语言有丰富的系统管理、数据处理、统计类软件包,因此从java应用中调用Python代码的需求很常见、实用,本文介绍几种方法从java调用Pyt... 目录引言Java core使用ProcessBuilder使用Java脚本引擎总结引言python

最新版IDEA配置 Tomcat的详细过程

《最新版IDEA配置Tomcat的详细过程》本文介绍如何在IDEA中配置Tomcat服务器,并创建Web项目,首先检查Tomcat是否安装完成,然后在IDEA中创建Web项目并添加Web结构,接着,... 目录配置tomcat第一步,先给项目添加Web结构查看端口号配置tomcat    先检查自己的to

SpringBoot集成SOL链的详细过程

《SpringBoot集成SOL链的详细过程》Solanaj是一个用于与Solana区块链交互的Java库,它为Java开发者提供了一套功能丰富的API,使得在Java环境中可以轻松构建与Solana... 目录一、什么是solanaj?二、Pom依赖三、主要类3.1 RpcClient3.2 Public

Android数据库Room的实际使用过程总结

《Android数据库Room的实际使用过程总结》这篇文章主要给大家介绍了关于Android数据库Room的实际使用过程,详细介绍了如何创建实体类、数据访问对象(DAO)和数据库抽象类,需要的朋友可以... 目录前言一、Room的基本使用1.项目配置2.创建实体类(Entity)3.创建数据访问对象(DAO

SpringBoot使用minio进行文件管理的流程步骤

《SpringBoot使用minio进行文件管理的流程步骤》MinIO是一个高性能的对象存储系统,兼容AmazonS3API,该软件设计用于处理非结构化数据,如图片、视频、日志文件以及备份数据等,本文... 目录一、拉取minio镜像二、创建配置文件和上传文件的目录三、启动容器四、浏览器登录 minio五、

SpringBoot整合kaptcha验证码过程(复制粘贴即可用)

《SpringBoot整合kaptcha验证码过程(复制粘贴即可用)》本文介绍了如何在SpringBoot项目中整合Kaptcha验证码实现,通过配置和编写相应的Controller、工具类以及前端页... 目录SpringBoot整合kaptcha验证码程序目录参考有两种方式在springboot中使用k

java如何调用kettle设置变量和参数

《java如何调用kettle设置变量和参数》文章简要介绍了如何在Java中调用Kettle,并重点讨论了变量和参数的区别,以及在Java代码中如何正确设置和使用这些变量,避免覆盖Kettle中已设置... 目录Java调用kettle设置变量和参数java代码中变量会覆盖kettle里面设置的变量总结ja

SpringBoot整合InfluxDB的详细过程

《SpringBoot整合InfluxDB的详细过程》InfluxDB是一个开源的时间序列数据库,由Go语言编写,适用于存储和查询按时间顺序产生的数据,它具有高效的数据存储和查询机制,支持高并发写入和... 目录一、简单介绍InfluxDB是什么?1、主要特点2、应用场景二、使用步骤1、集成原生的Influ

SpringBoot实现websocket服务端及客户端的详细过程

《SpringBoot实现websocket服务端及客户端的详细过程》文章介绍了WebSocket通信过程、服务端和客户端的实现,以及可能遇到的问题及解决方案,感兴趣的朋友一起看看吧... 目录一、WebSocket通信过程二、服务端实现1.pom文件添加依赖2.启用Springboot对WebSocket

Nginx、Tomcat等项目部署问题以及解决流程

《Nginx、Tomcat等项目部署问题以及解决流程》本文总结了项目部署中常见的four类问题及其解决方法:Nginx未按预期显示结果、端口未开启、日志分析的重要性以及开发环境与生产环境运行结果不一致... 目录前言1. Nginx部署后未按预期显示结果1.1 查看Nginx的启动情况1.2 解决启动失败的