NS2学习笔记(四)
这几天学习NS2,虽然国内很多人使用,但系统的教材资料不多,只能一边看中文教材,一边看英文手册,知识点也是零零散散。过段时间等能将所有知识点串上,再总结总结。现只讲一些零碎的点记录一下。
添加新的协议
添加新的协议,实际上是自己新定义了一个Agent的子类。在笔记(三)已经说过,Agent的子类实际上可以用来实现协议,比如TCP,UDP等等。
下面以新添加一个"Ping"协议为例来讲讲怎么添加新协议。
1.定义一个PingClass,它是TclClass的子类,它的定义是模板化的,只要套用就行了。
static class PingClass : public TclClass { public: PingClass():TclClass("Agent/Ping") {} TclObject* create(int, const char*const*) { return (new PingAgent()); } }class_ping;
这里实际上已经有一个PingClass的static对象,class_ping,在创建它的时候已经调用了PingClass的构造函数,继而调用了TclClass的构造函数,将Agent/Ping作为参数传进去了。
2.在仿真的tcl脚本中,新建一个Agent的方法是:set 变量名 [new 协议名],例如 set tcp [new Agent/TCP]。第一步中将Agent/Ping作为参数穿进去,就是为了在新建Ping协议的Agent时,程序认识Agent/Ping这个东西。
在set ping [new Agent/Ping]后,NS会调用PingClass的create方法,返回一个PingAgent的对象,这个类我们得自己定义,它是协议的核心。这第二步就是定义这个类。
class PingAgent : public Agent { public: PingAgent(); int command(int argc, const char*const* argv); void recv(Packet*, Handler*); protected: int off_ping_; };
PingAgent的构造函数完成变量绑定的工作,即tcl脚本中的变量和C++类的成员变量绑定在一起,这样,在tcl脚本中设定一个变量的值时,实际上也设定了C++成员变量的值。
PingAgent::PingAgent() : Agent(PT_PING) { bind("packetSize_", &size_); bind("off_ping_", &off_ping_); }
command()函数是用来实现Tcl脚本中的命令。例如,$ping send命令,就会调用command()函数。
int PingAgent::command(int argc, const char*const* argv) { if(argc == 2) { if(strcmp(arcv[1], "send") == 0) { Packet* pkt = allocpkt(); hdr_ping* hdr = (hdr_ping*)pkt->access(off_ping_); hdr->ret = 0; hdr->send_time = Scheduler::instance().clock(); send(pkt, 0) return (TCL_OK); } } return (Agent::command(argc, argv)); }
这里的hdr_ping是为了这个新协议新定义的一个报头。关于报头的向西内容,后面再补充。
struct hdr_ping { char ret;//标志去程还是返程 double send_time;//发送时间 }
send命令实现的功能是将ret置0,表示该包是去程,同时将该包的发送时间点记录在send_time中。
revc()函数独立在command()函数之外,因为Agent类有recv函数,在新的Agent子类中实际上是重写该函数。