+ 1. 13450 tcp 1000 ———
- 1. 13450 tcp 1000 ———
+ 1. 13450 tcp 1000 ———
- 1. 13450 tcp 1000 ———
+ 1. 26454 cbr 300 ———13. 01. 0 37 186
r 1. 26570 ack 40 ———23. 21. 1 12 179
⋯⋯
各列的具体含义解释如下:第1 列表示跟踪类型( + 入队列、- 出队列、r 接收、d 丢弃) ;第2 列表示事件发生时间;第3、4列是源和目的节点号;第5 列是包类型;第优列表示包大小;第七列表示当前支持ECN;第8 列是IP 流标识号;9、10 两列表示源和目的地址;第11 列是流内顺序号;第12 列表示仿真生成包的标识号。而监视是指有选择的记录包的行为(如某链路上丢包的数目) 或使用流监视器(flow monitor) 记录每个流的情况。其输出数据包括事先约定的流标识、包类型、流的字节数,丢包数、丢包字节数等,最多可有19 项。监视获得的数据可在Linux 下用Xgraph 或Xmgr ,也可在Windows下用Excel 或Origin 等画图工具转换成便于观察和分析的X、Y坐标图。此外,在仿真的过程中可以启动NAM进行动态模拟,但是无法进行定量分析。整个流程从用户的角度看来如图2.2所示。
若图片无法显示请联系QQ752018766图2.2
所以说,用NS2 进行仿真的过程就是根据需要先对C + +编译层进行修改或建立新的协议集,然后编写OTcl 脚本源程序,包括用NS 命令定义网络拓扑结构、配置业务源、业务接收点、收集统计信息,然后启动NS 仿真器,调用其C + + 程序内核运行仿真,输出感兴趣的仿真结果,并对结果进行分析。
NS基类共有6种,这一小节详细说明每一基类的作用、构造和工作机制。
Ø Tcl类:C++代码与Tcl代码之间的桥梁;
Ø TclObject类:所有仿真对象的基类;
Ø TclClass类:定义了解释类的类层次,并允许用户实例化TclObject,与TclObject一一对应;
Ø TclCommand类:封装了C++代码和Tcl代码相互调用命令的方法;
Ø EmbeddedTcl类:封装了装载更高级别的内置命令的方法;
Ø InstVar类:访问C++成员变量,如Otcl变量方法。
Tcl类最重要的功能有以下优种:
(1)获得访问Tcl实例的入口:
C++代码将整个Tcl平台视为一个类,首先取到访问此类的入口:
Tcl& tcl = Tcl::instance();
(2)通过解释器调用Otcl过程,总共有四种方法,对应有四个成员函数:
void eval(char *s):通过调用解释器的Tcl_GlobalEval()执行命令*s。
void evalc(const char *s):将串*s复制入内部buffer,然后调用[char *s]eval,完成对*s的执行。
void eval:假定命令已存入Tcl.bp_,先通过tcl.buffer()获得Tcp.bp_的指针p,然后调用tcl.eval(char *p),执行命令*p。
void evalf(const char *fmt,…) 带不定个数的参数,第一参数*fmt为输出格式。
举例如下:
Tcl& tcl = Tcl::instance();
char wrk[128];
strcpy(wrk, "Simulator set NumberInterfaces_ 1");
tcl.eval(wrk);
sprintf(tcl.buffer(), "Agent/SRM set requestFunction_ %s", "Fixed");
tcl.eval();
tcl.evalc("puts stdout hello world");
tcl.evalf("%s request %d %d", name_, sender, msgid);
(3)与解释器交换结果:
解释器调用C++方法,期望将结果返回并写入私有成员变量tcl_->result。有两种方法:
tcl.result(const char *s):将结果串*s写入tcl_->result。
tcl.resultf(const char* fmt, . . . ):按格式*fmt,将结果写入tcl_->result。
看个例子: if (strcmp(argv[1], "now") == 0) {
tcl.resultf("%
return TCL_OK;
}
tcl.result("Invalid operation specified");
return TCL_ERROR;
当C++方法调用Otcl命令时,解释器也将结果返回到tcl_->result,使用的方法是不带参数的tcl.result(void),应该注意到返回的结果是字串,所以,还要将它转变成相应的数据类型。例如:
tcl.evalc("Simulator set NumberInterfaces_");
char* ni = tcl.result();
if (atoi(ni) != 1)
tcl.evalc("Simulator set NumberInterfaces_ 1");
(5)报告出错状况,并以统一方式退出:
相应的成员函数是:tcl.error(const char*s),此函数将*s、tcl->result写入stdout,退出并置error code为1。
tcl.resultf("cmd = %s", cmd);
tcl.error("invalid command specified");
注:调用Tcl::error(),不同于函数tcl.result()中返回TCL_ERROR。后者在解释器内部产生一个异常,用户可以跟踪此异常,并有可能从错误中恢复,若用户没有指定任何跟踪,解释器将输出错误信息,并退出。但如果代码调用了error(),则仿真用户不能跟踪错误,同时,ns不会输出任何错误信息。
(5)存储、查找TclObject类对象:
ns将每一个TclObject对象的入口都存储在一个哈希表里,并以TclObject对象名为关键字,对哈希表进行操作。类Tcl提供了一组方法:
tcl.enter(TclObject*):将一个指向TclObject对象的指针插入哈希表,通常是在生成一个新的对象时,由函数TclClass::create_shadow()调用。
tcl.lookup(char*):参数为TclObject对象名,由TclObject::lookup()调用。
tcl.remove(TclObject*):当需要释放一TclObject对象TclClass::delete_shadow()调用此函数。
注:以上三个函数只在类TclObject或类TclClass内部使用
(6)取解释器的句柄:
若以上的方法不够用,我们只好直接取到解释器的句柄,再自己写代码,获得解释器句柄的方法是:
tcl.interp(void)
类TclObject是ns中绝大多数类的基类,封装了绑定、跟踪和对相关命令的调用机制。
(1) 生成和释放:new{}和delete{}。
生成(create):new操作返回类TclObject的解释对象。解释器调用对象的构造函数,初始函数init{},还有相应的编译类的构造函数以生成相应的编译对象。最后,new{}返回对象的句柄。
详细过程如下:
Ø New{}调用方法name(){},在解释器的名字空间(name space)取一句柄返回给用户。通常,句柄由getid{}产生,为_o<NNN>型, 此处<NNN>是一整数。
Ø 执行新对象的构造函数,该构造函数会调用其父类的构造函数,最后会调用到TclObject的构造函数。
Ø TclObject的构造函数为调用实例过程create-shadow(void){},构造编译对象,并完成一系列的初始化、绑定。
Ø 生成编译对象后,create_shadow(void) 还要完成以下工作:将新对象加入TclObjects哈希表中;为新的解释对象实现cmd{},cmd{}过程将用来调用编译对象的command() 完成想要的操作。
注:以上的过程仅发生在用户通过解释器构造新的对象,而直接用C++代码生成对象不会如此。其流程图如下:若图片无法显示请联系QQ752018766
上一页 [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] ... 下一页 >>