NS学习整理
最近连续几天的学习NS,终于有一些收获,在此整理一下。
1 设计语言的关系
为了实现NS多方面要求的考虑,在NS的程序设计过程中会涉及到三种脚本语言,具体原因见书本或者相关网摘
1-1 Tcl脚本语言
这是NS为了实现快速建模或者快速搭建一些测试环境而引用的一种解释型脚本语言,这种脚本语言不需要编译就可以执行。他有自己独立的语法格式,书写命令以及自己的一些关键字函数。
1-2 Otcl脚本语言
这是将Tcl脚本引入对象化以及类概念后出现的一种扩展脚本,就像在c语言基础上发展得到的C++语言。这种脚本与TCL的关系见课本第三章。我们要注意的是他的类声明方式以及类的成员变量以及类的成员方法的定义方式,与C++有很大的不同。
1-3 C++脚本语言
在NS的构件库中,每一种构件都会关联到两个相应的类,一个是由Otcl脚本编写,一个是C++编写的。这两种脚本如何关联,可见课本第四章分裂模型。
1-4 Otcl以及C++之间的关系
这两种语言都非专门针对NS2所设计的脚本语言,都是通用的语言,但是在NS2中,为了考虑到方便性以及程序执行效率,综合利用了两种设计语言。两种语言的关联也是NS2的特点之一。这其中就涉及到,Otcl与C++类的对应关系。
u Otcl类命名规则,我们从Otcl类就可以知道其父类以及继承关系。
u NS创建一个构件时,都会同时创建一个Otcl中的对象和一个对应的C++对象。这两个类被互称为影像类,并且可以互相操作。
u OTcl与C++类对象连接起来的类:TclObject和TclClass
当用户创建一个新的TclObject时(也即创建NS构件,比如set tcp [new Agent/TCP]),就会调用该对象的初始化实例过程,init{}就会通过调用create-shadow(这个函数在~tclcl/tcl-object中有使用,但是定义在哪,我也不知)来创建该对象在C++中的影像对象。在所有的C++所编写的类中,必须要有一个继承与TclClass的类在前面申明该C++类与对应的OTcl类的对应,在这个类里面有一个Create函数就会将对应关系描述出来。(见P47).
u 变量绑定
通常,C++成员变量只能在C++代码中访问,Otcl的成员变量只能在Otcl脚本中访问。为了在NS中,建立一种双向的绑定,在c++类的构建函数通过规定的一些绑定方法来可以将C++类中的一些成员变量与对应的解释对象中的一些成员变量绑定起来,然后在解释对象中对这些成员变量进行赋值时,在编译对象中的成员变量也会改变相应的值。(P48)
u Command方法
要在Otclc对象中调用对应的C++对象的方法,NS是通过command()函数来实现的。对于每个TclObject,ns为其Otcl中的解释对象建立一个实例过程,cmd{};该过程就调用影像对象(也即对应的C++对象)中的command(),并将cmd()的参数作为一个参数数组传递给command()方法。如果一个编译对象调用一个不是其方法成员的函数,那么就会调用实例过程unknown{},这个过程就会调用cmd{},从而对应的调用其对应解释类中的command()方法。(p48-p52)
u Tcl类
类Tcl封装了Otcl解释器的实例,并提供了访问解释器的方法。这也是在C++代码调用Otcl中定义方法的途径。具体使用见P52.这其中包括了获取Tcl实例,调用Otcl过程,C++中处理对应的Otcl返回值,Otcl对象库构件查找。
1-5 Otcl脚本所定义类的初始化—EmbeddedTcl类。(~tclcl/tclcl.h ,tclcl.cc)
在~ns/tcl目录下存放着很多的NS各种构件的Otcl代码以及很多初始化配置脚本。在NS刚一开始运行时,这些Otcl脚本所定义的类、过程和变量就都有效了。这时因为在Tcl解释器初始化函数(~ns/common/tclAppInit.cc)中调用了et_ns_lib.load()将~ns/tcl目录下所有的tcl脚本载入了。但是还有一个问题是这样的et_ns_lib.load()这个方法是在~ns/gen/ns_tcl.cc中存在的,这个文件不可能开始就有,因为~ns/tc下面的文件会动态变化,通过阅读ns的Makefile,发现原来这个文件是在编译ns时自动生成的,生成的过程就会把~ns/tcl下面的脚本全部导入到里面的code字符串里面,供后面初始化ns解释器Tcl解释器初始化函数(~ns/common/tclAppInit.cc)时载入。
可得如下关系图
编译ns源文件(安装的过程)――>生成~ns/gen/ns_tcl.cc(会将~ns/tcl下面的脚本全部导入到里面的code字符串)――>初始化ns解释器Tcl解释器初始化函数(~ns/common/tclAppInit.cc)――>载入所有的tcl脚本。
2 Ns构件库
有了前面的基础,可以学习NS构件库了。可见P4有部分的NS构件关系图。具体见解见第五章,NS构件也是构成我们仿真网络环境的组成元素。待补充。
3 杂项
3-1 NS模拟仿真
在NS上仿真有两个层次:一个是基于Otcl编程的层次,利用NS已有的网络元素实现模拟,无需对NS本身进行任何修改,只需要编写Otcl脚本(见书本上第二章例程以及ns自带例子),但是这里虽然是只需要用Otcl脚本编写程序,但是肯定要用c++编写的类,因为NS构件的功能一般都是在C++类中实现的。
一个是基于C++和Otcl编程的层次,这是当NS中没有所需要的网络元素,这就需要利用前面提到的分裂对象模型,添加新的C++类和Otcl类,然后再编写Otcl脚本。见P6.通过师哥的例子快速切换,以及书本上Mflood路由协议的实现有了一个大概的理解与掌握。
当我们完成了NS的扩展过后,就可以进行我们的模拟,具体的过程见课本P6
3-2 NS版本问题
不同的NS版本会有一些不同的函数定义,变量定义,所以在一种版本下实现的程序脚本直接用到另外一种平台上可能报错,见Mflood从ns2.26移植到ns2.29的解决过程。
3-3 NS错误分析(这里有一个网摘,他的错误信息与gcc的报错很相似)
错误代码从错误发生时开始输出,然后返回上一级调用,上一级可能继续返回错误代码的相关信息,最典型的模式是
1 eval $self create-wireless-node $args"# 命令代码
2 (procedure "_o3" line 23) # 命令所在行数
3 (Simulator node line 23) # Simulator 实体的node函数体
4invoked from within #
5"$ns_ node"# 调用代码
此5行大体意思是, 1行对应的命令是从句柄为 "_o3"的Simulator实体的函数 node "函数定义"的第23行调用的
句柄说明
在每一个Simulator对应的模拟中"_o*"标示唯一的一个分裂类实体,也就是说,所有的分裂类实体都有自己的唯一标识 详见《tclcl-1.19/tcl-object.tcl 代码分析 》
对于下面错误代码中提到的几个句柄说明如下:
_o3 是一个Simulator实例句柄, _o14是一个node实例句柄,_o17是一个agent实例句柄
源文档
3-4 NS仿真的相关工具
这主要是一些生成场景,生成数据流,处理结果,画图,动画演示(nam)工具,具体见课本第六章。其中cmu-trace是专门针对无线仿真的过程记录工具。
上面是一个大概性的总结,还有相当多的东西要补充,也有很多东西自己也还没有弄明白,对于第二部分NS构件库的理解,原则是这样的,由于NS是一个包含了很多种类型网络的仿真平台,所以对于一些通用构件进行了解即可,主要是了解与自己相关的无线仿真的构件库部分。对于无线部分,包括无线节点,无线链路,路由,无线信道,无线跟踪工具等等都要好好研究。