ns2中command的用法

command()函数与ns的分裂对象模型TclCL有关。这里的代码来自aomdv.cc,相关解释学习自NS与网络模拟一书。

与分裂对象模型有关的类主要为TclObject和TclClass。TclObject类是所有编译类(c++)的基类,SplitObject类是所有解释类(TclCL)类的基类,而类TciClass包含了这两个类间的映射关系。

创建对象时,用户通过tcl脚本创建解释对象的同时在c++类结构中创建了对应的类。通过变量绑定bind可以同时在OTcl类和c++类中访问和修改成员变量。

static class AOMDVclass : public TclClass {
public:
	AOMDVclass() : TclClass("Agent/AOMDV") {}
	TclObject* create(int argc, const char*const* argv) {
		assert(argc == 5);
		//return (new AODV((nsaddr_t) atoi(argv[4])));
		return (new AOMDV((nsaddr_t) Address::instance().str2addr(argv[4])));
	}
} class_rtProtoAOMDV;
以上的AOMDVclass继承自TclClass,其中包含了构造函数和create()函数。构造函数直接使用父类TclClass的构造函数,而create()函数使用new创建了相应的c++类(顺便做了对应类的登记工作)。

create()函数的参数组包括:

(1)argv[0],对象名

(2)argv[1-3],$self,$class,$proc.

(3)argv[4],提供给用户的任意附加参数。


AOMDV::AOMDV(nsaddr_t id) : Agent(PT_AOMDV),
btimer(this), htimer(this), ntimer(this), 
rtimer(this), lrtimer(this), rqueue() {
	
	// AOMDV code
	aomdv_max_paths_ = 3;
	bind("aomdv_max_paths_", &aomdv_max_paths_);
	
	aomdv_prim_alt_path_len_diff_ = 1;
	bind("aomdv_prim_alt_path_len_diff_", &aomdv_prim_alt_path_len_diff_);
	
	index = id;
	seqno = 2;
	bid = 1;
	
	LIST_INIT(&nbhead);
	LIST_INIT(&bihead);
	
	logtarget = 0;
	AOMDVifqueue = 0;
}
以上是AOMDV类的构造函数,其中包含了变量的绑定bind。通过bind可以建立双向的绑定,使得OTcl类或对应的c++类中任意一边的变量值改变时,另一边也跟着改变。

 

int
AOMDV::command(int argc, const char*const* argv) {
	if(argc == 2) {
		Tcl& tcl = Tcl::instance();
		
		if(strncasecmp(argv[1], "id", 2) == 0) {
			tcl.resultf("%d", index);
			return TCL_OK;
		}
		// AOMDV code - should it be removed?
		if (strncasecmp(argv[1], "dump-table", 10) == 0) {
			printf("Node %d: Route table:\n", index);
			rtable.rt_dumptable();
			return TCL_OK;
		}    
		if(strncasecmp(argv[1], "start", 2) == 0) {
			btimer.handle((Event*) 0);
			
#ifndef AOMDV_LINK_LAYER_DETECTION
			htimer.handle((Event*) 0);
			ntimer.handle((Event*) 0);
#endif // LINK LAYER DETECTION
			
			rtimer.handle((Event*) 0);
			return TCL_OK;
		}ns command
	}
	else if(argc == 3) {
		if(strcmp(argv[1], "index") == 0) {
			index = atoi(argv[2]);
			return TCL_OK;
		}
		
		else if(strcmp(argv[1], "log-target") == 0 || strcmp(argv[1], "tracetarget") == 0) {
			logtarget = (Trace*) TclObject::lookup(argv[2]);
			if(logtarget == 0)
				return TCL_ERROR;
			return TCL_OK;
		}
		else if(strcmp(argv[1], "drop-target") == 0) {
			int stat = rqueue.command(argc,argv);
			if (stat != TCL_OK) return stat;
			return Agent::command(argc, argv);
		}
		else if(strcmp(argv[1], "if-queue") == 0) {
			AOMDVifqueue = (PriQueue*) TclObject::lookup(argv[2]);
			
			if(AOMDVifqueue == 0)
				return TCL_ERROR;
			return TCL_OK;
		}
		// AODV ns-2.31 code
		else if (strcmp(argv[1], "port-dmux") == 0) {
			dmux_ = (PortClassifier *)TclObject::lookup(argv[2]);
			if (dmux_ == 0) {
				fprintf (stderr, "%s: %s lookup of %s failed\n", __FILE__,
							argv[1], argv[2]);
				return TCL_ERROR;
			}
			return TCL_OK;
		}
	}
	return Agent::command(argc, argv);
}
要在OTcl类中调用c++类对象的方法,就需要使用command()函数。该函数对传递的参数进行匹配,若匹配成功,则进入相应的处理函数并返回TCL_OK。若没有匹配的操作,则调用父类的command()方法且返回相应的状态值。


下面是涉及到的几个tips。

1.strncasecmp:

表头文件:#include <string.h>
函数定义:int strncasecmp(const char *s1, const char *s2, size_t n)
函数说明:strncasecmp()用来比较参数s1和s2字符串前n个字符,比较时会自动忽略大小写的差异。
返回值 :若参数s1和s2字符串相同,则返回0; 若s1大于s2,则返回大于0的值; 若s1小于s2,则返回小于0的值。


2.(int agrc,const char* const* argv):

在NS2代码库中,经常看到以(int agrc,const char* const* argv)为参数的函数。agrc表示参数的个数。argv是指向函数参数列表的指针,其中argv[0]是函数名,argv[1]~argv[argc-1]是函数的参数。

argv其实就是个二级指针(即是指向指针的指针),第一个const修鉓是表示argv指向的指针指向了一个常量,不能修改;第二个const修鉓是表示argv指向的指针是个常量,不能对其进行增减操作。argv[0]其实就是argv指向的第一个指针(char* 类型指针),它实际上指向 一个以'\'结束的字符串。按照助记法,const char* const* argv应读为 argv is (a pointer to (a const pointer ( to a const char))).


关于指针的助记法:

Bjarne在他的The C++ Programming Language里面给出过一个助记的方法: 
把一个声明从右向左读。 
char * const cp; ( * 读成 pointer to ) 
cp is a const pointer to char 

const char * p; 
p is a pointer to const char;

你可能感兴趣的:(ns2中command的用法)