把一个tcl脚本中可以显式看到的类和函数写了出来,还有很多地方不是很理解,如果有人帮忙解答或改错,感激不尽
我的想法:
一般的方法都是在C++中定义的, OTcl一般通过unknown{},cmd{},调用C++的comand{},然后在调用到C++的方法; 而直接在Otcl中定义方法的情况比较少见,但也不是没有
几点疑问:
很多tcl中的类没有类声明,我猜可能是隐藏了或运行时自动生成
Node label方法我找了很久, 找不到是如何调用C++的,在command中找不到,只在net-interface.cc中看到有关”label”的command()
关于调用父类同名函数的问题,是否需要显式的把调用父类的代码写出来,比如$cbr1 attach-agent $udp1,我是在Application类中找到的command()函数中有相关的代码,而在Application/Traffic/CBR和Application/Traffic中都没有command()函数,NS是否会自己向上代用
感想:
NS代码很多,对于一个学习的人来说理解起来很困难,我现在大概知道了tcl脚本运行时的流程,不过要进行内部协议和代码的编写还有一定困难,主要是对接口API了解不多以及NS的技术手册不可能写的很详细(东西太多了),只有针对要研究的方向,读相关的代码.
举例说明《移动IP技术与NS-2模拟》
9.2.2 无线网络中的UDP模拟Page 101
set val(proc) Propagation/TwoRayGround
set val(netif) Phy/WirelessPhy
set val(mac) Mac/802_11
set val(ifq) Queue/DropTail/PriQueue
set val(ll) LL
set val(ant) Antenna/OmniAntenna
set val(ifqlen) 50
set val(rp) DSDV
#tcl
#ns-lib.tcl
#类 Class Simulator 方法 Simulator instproc init args
#
#我没有找到解释层次的Simulator类,只在ns-lib.tcl的Line128看到”#Class Simulator”
##Class Simulator
#...
#Simulator instproc init args {}
#
#C++
#Simulator.{h.cc}
#类class Simulator 类 class SimulatorClass 方法 Simulator()
#
#class Simulator : public TclObject {}
#static class SimulatorClass : public TclClass {
#public:
# SimulatorClass() : TclClass("Simulator") {}
# TclObject* create(int argc, const char*const* argv) {
# return (new Simulator);
# }
#
#} simulator_class;
#
# Simulator() : nodelist_(NULL), rtobject_(NULL), nn_(0), /
# size_(0) {}
set ns_ [new Simulator]
#tcl
#找不到
#
#C++
#topography.{h.cc}
#类 class Topography 类 class TopographyClass 方法 Topography()
#
#class Topography : public TclObject {}
#
#static class TopographyClass : public TclClass {
#public:
# TopographyClass() : TclClass("Topography") {}
# TclObject* create(int, const char*const*) {
# return (new Topography);
# }
#} class_topography;
#
# Topography() { maxX = maxY = grid_resolution = 0.0; grid = 0; }
set topo [new Topography]
#tcl
# topography.cc
#Otcl的类是小于C++的类,这个tcl的实现是用unknown{},cmd{},command{}实现的
#
#int
#Topography::command(int argc, const char*const* argv)
#{
# …
# else if(argc == 4) {
# if(strcmp(argv[1], "load_flatgrid") == 0) {
# if(load_flatgrid(atoi(argv[2]), atoi(argv[3])))
# return TCL_ERROR;
# return TCL_OK;
# }
# }
# else if(argc == 5) {
# if(strcmp(argv[1], "load_flatgrid") == 0) {
# if(load_flatgrid(atoi(argv[2]), atoi(argv[3]), atoi(argv[4])))
# return TCL_ERROR;
# return TCL_OK;
# }
# }
# return TclObject::command(argc, argv);
#}
#
#C++
#topography.{h.cc}
#方法 load_flatgrid ()
#
#int
#Topography::load_flatgrid(int x, int y, int res)
#{
# /* No Reason to malloc a grid */
#
# grid_resolution = res; // default is 1 meter
# maxX = (double) x;
# maxY = (double) y;
#
# return 0;
#}
$topo load_flatgrid 700 700
set f [open 2-2.tr w]
#tcl
#ns-lib.tcl
# 方法 trace-all
#
#Simulator instproc trace-all file {
# $self instvar traceAllFile_
# set traceAllFile_ $file
#}
#
#C++无
$ns_ trace-all $f
#tcl
#ns-lib.tcl
# 方法 eventtrace-all
#
#Simulator instproc eventtrace-all {{file ""}} {
# $self instvar eventTraceAll_ eventtraceAllFile_ traceAllFile_
# set eventTraceAll_ 1
# if {$file != ""} {
# set eventtraceAllFile_ $file
# } else {
# set eventtraceAllFile_ $traceAllFile_
# }
#
#}
#
#C++无
$ns_ eventtrace-all
set nf [open 2-2.nam w]
#tcl
#ns-lib.tcl
# 方法 namtrace-all-wireless 和 namtrace-all
#
#Simulator instproc namtrace-all-wireless {file optx opty} {
# $self instvar namtraceAllFile_
#
# # indicate that we need a W event written to the trace
# $self set namNeedsW_ 1
# if { $optx != "" && $opty != "" } {
# $self set namWx_ $optx
# $self set namWy_ $opty
# }
#
# $self namtrace-all $file
#}
#
#Simulator instproc namtrace-all file {
# $self instvar namtraceAllFile_
# if {$file != ""} {
# set namtraceAllFile_ $file
# } else {
# unset namtraceAllFile_
# }
#}
#
#C++无
$ns_ namtrace-all-wireless $nf
#tcl
#com.tcl
#类 Class God 方法 create-god{}
#
##Class God
#
#proc create-god { nodes } {
# #global ns_ god_ tracefd
# set god [God info instances]
# if { $god == "" } {
# set god [new God]
# }
# $god num_nodes $nodes
# return $god
#}
#
#C++
#god.{h,cc}
#类 class God 类 class GodClass
#数值2通过com.tcl中的num_nodes传给god.cc中的int num_nodes
#
# class God : public BiConnector {}
#
# static class GodClass : public TclClass {
#public:
# GodClass() : TclClass("God") {}
# TclObject* create(int, const char*const*) {
# return (new God);
# }
#} class_God;
create-god 2
#tcl
#ns-lib.tcl
#方法 node-config
#
#Simulator instproc node-config args {
# …
# set args [eval $self init-vars $args]
# ...
#}
#
#C++
#没有或者我不知道,我觉得是把每个变量的值用变量绑定的用法传给对应的C++中的变量
$ns_ node-config -adhocRouting $val(rp)/
-llType $val(ll)/
-macType $val(mac)/
-ifqType $val(ifq)/
-ifqLen $val(ifqlen)/
-antType $val(ant)/
-propType $val(prop)/
-phyType $val(netif)/
-channelType Channel/WirelessChannel/
-topoInstance $topo/
-agentTrace ON/
-routerTrace OFF/
-macTrace ON/
-movementTrace OFF
#tcl
#ns-lib.tcl; ns-mobilenode.tcl
#方法 node; create-wireless-node; create-node-instance 类 Node/MobileNode 方法 init
#
# Simulator instproc node args {
# …
# # wireless-ready node
# if { [info exists routingAgent_] && ($routingAgent_ != "") } {
# set node [eval $self create-wireless-node $args]
# …
# return $node
# }
# …
#}
#
# Simulator instproc create-wireless-node args{
# …
# set node [eval $self create-node-instance $args]
# …
#}
#
# Simulator instproc create-node-instance args {
# …
# else {
# set nodeclass Node/MobileNode
# }
# return [eval new $nodeclass $args]
#}
#
#Node/MobileNode instproc init args {
# …
# eval $self next $args
# …
#}
#
#C++
#mobilenode.{h,cc}
#类 class MobileNode 类 class MobileNodeClass 方法 MobileNode(void)
#
# class MobileNode : public Node {}
#
# static class MobileNodeClass : public TclClass {
#public:
# MobileNodeClass() : TclClass("Node/MobileNode") {}
# TclObject* create(int, const char*const*) {
# return (new MobileNode);
# }
#} class_mobilenode;
#
# MobileNode::MobileNode(void) : pos_handle_(this){}
set node_(0) [$ns_ node]
set node_(1) [$ns_ node]
#tcl
#在tcl中没有label方法,然后我去查看对应的C++中的command方法,但是没有查到,凭感觉#是调用C++中的Node::label(),不过没有找到如何使Node::label()运行的command方法
#
#C++
#node.cc
#方法 label()
#
#void
#Node::label(const char* name, int anchor) {
# delete []label_;
# label_ = new char[strlen(name) + 1];
# strcpy(label_, name);
# anchor_ = anchor;
#}
$node_(0) label "Node 0"
$node_(0) set X_ 10.0
$node_(0) set Y_ 10.0
$node_(0) set Z_ 0.0
$node_(1) label "Node 1"
$node_(1) set X_ 600.0
$node_(1) set Y_ 600.0
$node_(1) set Z_ 0.0
#tcl
#找不到
#
#C++
#udp.{h,cc}
#类 class UdpAgent 类 class UdpAgentClass 方法 UdpAgent(){}
# class UdpAgent : public Agent {}
#
#static class UdpAgentClass : public TclClass {
#public:
# UdpAgentClass() : TclClass("Agent/UDP") {}
# TclObject* create(int, const char*const*) {
# return (new UdpAgent());
# }
#} class_udp_agent;
#
#UdpAgent::UdpAgent() : Agent(PT_UDP), seqno_(-1)
#{
# bind("packetSize_", &size_);
#}
set udp1 [new Agent/UDP]
#tcl
#ns-agent.tcl
#类 Class Agent/Null 方法 Agent/Null instproc init args{}
#
# Class Agent/Null -superclass Agent
#
#Agent/Null instproc init args {
# eval $self next $args
#}
#
#C++
#没有,Otcl中的Agent/Null 继承于Agent,调用C++中类Agent的初始化
set null1 [new Agent/Null]
#tcl
#ns-lib.tcl, ns-node.tcl
#方法 attach-agent{} 方法attach{} 方法 add-target
#
# Simulator instproc attach-agent { node agent } {
# $node attach $agent
# …
#}
#
#Node instproc attach { agent { port "" } } {
# …
# $self add-target $agent $port
#}
#
# Node instproc add-target { agent port } {}
#
#C++
#没有
$ns_ attach-agent $node_(0) $udp1
$ns_ attach-agent $node_(1) $null1
#tcl
#ns-lib.tcl
#方法 connect{} 方法 simplex-connect{}
#
#Simulator instproc connect {src dst} {
# …
# $self simplex-connect $src $dst
# $self simplex-connect $dst $src
# …
#}
#
#Simulator instproc simplex-connect { src dst } {
# …
# return $src
#}
#
#C++
#没有
$ns_ connect $udp1 $null1
#tcl
#找不到
#
#C++
#cbr_traffic.{h,cc}
#类 class CBR_Traffic 类 class CBRTrafficClass 方法 CBR_Traffic()
#
# class CBR_Traffic : public TrafficGenerator {}
#
#static class CBRTrafficClass : public TclClass {
# public:
# CBRTrafficClass() : TclClass("Application/Traffic/CBR") {}
# TclObject* create(int, const char*const*) {
# return (new CBR_Traffic());
# }
#} class_cbr_traffic;
#
#CBR_Traffic::CBR_Traffic() : seqno_(0)
#{
# bind_bw("rate_", &rate_);
# bind("random_", &random_);
# bind("packetSize_", &size_);
# bind("maxpkts_", &maxpkts_);
#}
set cbr1 [new Application/Traffic/CBR]
#tcl
#ns-source.tcl
# 方法Application/Traffic/CBR instproc set args{}, Application/Traffic instproc set args{}
#
# Application/Traffic/CBR instproc set args {
# $self instvar packetSize_ rate_
# if { [lindex $args 0] == "interval_" } {
# if { [llength $args] == 2 } {
# set ns_ [Simulator instance]
# set interval_ [$ns_ delay_parse [lindex $args 1]]
# $self set rate_ [expr $packetSize_ * 8.0/$interval_]
# return
# } elseif { [llength $args] == 1 } {
# return [expr $packetSize_ * 8.0/$rate_]
# }
# }
# eval $self next $args
#}
#
#Application/Traffic instproc set args {
# $self instvar packetSize_ rate_
# if { [lindex $args 0] == "packet_size_" } {
# if { [llength $args] == 2 } {
# set packetSize_ [lindex $args 1]
# return
# } elseif { [llength $args] == 1 } {
# return $packetSize_
# }
# }
##应该还会继续调用父类方法,可是我找不到Application instproc set args{}
# eval $self next $args
#}
#
#C++
#没有
$cbr1 set rate_ 0.5Mb
$cbr1 set packetSize_ 200
#tcl
#app.cc
#通过unknown{},cmd{},command{}实现的
#
#int Application::command(int argc, const char*const* argv)
#{
# …
# else if (argc == 3) {
# if (strcmp(argv[1], "attach-agent") == 0) {
# agent_ = (Agent*) TclObject::lookup(argv[2]);
# if (agent_ == 0) {
# tcl.resultf("no such agent %s", argv[2]);
# return(TCL_ERROR);
# }
# agent_->attachApp(this);
# return(TCL_OK);
# }
# …
# }
# return (Process::command(argc, argv));
#}
#
#C++
#tclcl.h
#方法 TclObject::lookup(),Tcl::instance().lookup(), …, Tcl::lookup()
#
# inline static TclObject* lookup(const char* name) {
# return (Tcl::instance().lookup(name));
# }
#
# TclObject* Tcl::lookup(const char* name)
#{
# /*XXX use tcl hash table */
# Tcl_HashEntry* he = Tcl_FindHashEntry(&objs_, (char*)name);
# if (he != 0)
# return ((TclObject*)Tcl_GetHashValue(he));
# return (0);
#}
$cbr1 attach-agent $udp1
#tcl
#ns-lib.tcl
#方法 Simulator instproc at args{}
#
# Simulator instproc at args {
# $self instvar scheduler_
# return [eval $scheduler_ at $args]
#}
#
#C++
#没有
#
#tcl
#app.cc
#通过unknown{},cmd{},command{}实现的
#
# int Application::command(int argc, const char*const* argv)
#{
# Tcl& tcl = Tcl::instance();
#
# if (argc == 2) {
# if (strcmp(argv[1], "start") == 0) {
# // enableRecv_ only if recv() exists in Tcl
# tcl.evalf("[%s info class] info instprocs", name_);
# char result[1024];
# sprintf(result, " %s ", tcl.result());
# enableRecv_ = (strstr(result, " recv ") != 0);
# enableResume_ = (strstr(result, " resume ") != 0);
# start();
# return (TCL_OK);
# }
# …
# }
# …
# return (Process::command(argc, argv));
#}
#
#C++
#app.cc
#方法start()
#
# void Application::start(){}
#
# void CBR_Traffic::start()
#{
# init();
# running_ = 1;
# timeout();
#}
$ns_ at 5.0 "$cbr1 start"
#tcl
#ns-node.tcl
#方法reset{}, list-modules {}
#
#Node instproc reset {} {
# $self instvar agents_
# foreach a $agents_ {
# $a reset
# }
# foreach m [$self list-modules] {
# $m reset
# }
#}
#
#Node instproc list-modules {} {
# $self instvar reg_module_
# set ret ""
# foreach n [array names reg_module_] {
# lappend ret $reg_module_($n)
# }
# return $ret
#}
#
#C++
#有可能调用agent instproc reset 若没有, 则调用class agent的command(), 不过我找了这两#个地方没找到,所以我觉得有可能要看是具体哪个agent,然后调用agent的子类的#command()
$ns_ at 0.0 "$node_(0) reset"
$ns_ at 0.0 "$node_(1) reset"
#tcl
#mobilenode.cc
#通过unknown{},cmd{},command{}实现的
#
#int
#MobileNode::command(int argc, const char*const* argv)
#{
# …
# else if (argc == 5) {
# if (strcmp(argv[1], "setdest") == 0) {
# /* <mobilenode> setdest <X> <Y> <speed> */
##ifdef DEBUG
# fprintf(stderr, "%d - %s: calling set_destination()/n",
# address_, __FUNCTION__);
##endif
#
# if (set_destination(atof(argv[2]), atof(argv[3]),
# atof(argv[4])) < 0)
# return TCL_ERROR;
# return TCL_OK;
# }
# }
# return Node::command(argc, argv);
#}
#
#C++
#mobilenode.cc
#方法 MobileNode::set_destination()
#
#int
MobileNode::set_destination(double x, double y, double s)
{
assert(initialized());
if(x >= T_->upperX() || x <= T_->lowerX())
return -1;
if(y >= T_->upperY() || y <= T_->lowerY())
return -1;
update_position(); // figure out where we are now
destX_ = x;
destY_ = y;
speed_ = s;
…
return 0;
}
$ns_ at 0.6 "$node_(0) setdest 300.0 250.0 60.0"
$ns_ at 1.1 "$node_(1) setdest 300.0 300.0 60.0"
$ns_ at 40 "$node_(0) setdest 600.0 600.0 20.0"
$ns_ at 40.1 "$node_(1) setdest 100.0 100.0 20.0"
$ns_ at 50.0 "finish"
#tcl
#ns-lib.tcl
# 方法Simulator instproc halt {}
#
#Simulator instproc halt {} {
# $self instvar scheduler_
# #puts "time: [clock format [clock seconds] -format %X]"
# $scheduler_ halt
#}
#
#C++
#scheduler.{h,cc}
#方法 command()
#
# int
#Scheduler::command(int argc, const char*const* argv)
#{
# …
# else if (strcmp(argv[1], "halt") == 0) {
# halted_ = 1;
# return (TCL_OK);
#
# }
# …
#}
$ns_ at 50.1 "puts /"NS EXITING.../"; $ns_ halt"
proc finish {} {
global ns_ f nf val
$ns_ flush-trace
close $f
close $nf
}
puts "Starting Simulation..."
#tcl, C++
#ns-lib.tcl, priqueue.cc, ns-namsupp.tcl, scheduler.cc
#方法 Simulator instproc run {}, 这其中做了一系列初始化check-smac{}, check-node-num{}, #rtmodel-configure{}, get-routelogic{}…(若这些不在Simulator instproc中定义,那就是通过#command()在C++中定义的);
#Node instproc reset{};
#Queue reset 通过command传给PriQueue::command()来执行; 然后调用了Terminate()
#Simulator instproc init-nam {}; s
#scheduler run通过command传给Scheduler::command()中定义的,然后调用了reset(); run()
#
# Simulator instproc run {} {
# …
# foreach nn [array names Node_] {
# $Node_($nn) reset
# …
# }
# }
# …
# foreach qn [array names link_] {
# set q [$link_($qn) queue]
# $q reset
# }
# …
# $self init-nam
# …
# return [$scheduler_ run]
#}
#
#int
#PriQueue::command(int argc, const char*const* argv)
#{
# if (argc == 2 && strcasecmp(argv[1], "reset") == 0)
# {
# Terminate();
# //FALL-THROUGH to give parents a chance to reset
# }
# return DropTail::command(argc, argv);
#}
#
#Simulator instproc init-nam {} {
# #一系列初始化
# …
#}
#
#int
#Scheduler::command(int argc, const char*const* argv)
#{
# …
# if (argc == 2) {
# if (strcmp(argv[1], "run") == 0) {
# /* set global to 0 before calling object reset methods */
# reset(); // sets clock to zero
# run();
# return (TCL_OK);
# }
$ns_ run