1 安装linux
(1)windows下删除卷,为安装linux提供空间
(2)下载ubantuISO文件,通过ultraISO刻录到U盘
(3)按照网上教程分配空间,完成linux安装
2 安装NS-2
(1)根据[https://www.cnblogs.com/wlzy/p/5962853.html]下载安装
(2)发现有错误。gcc与g++版本过高。下载5版本
(3)安装完毕,并可以通过打ns显示%,说明环境变量配置正确。
(4)不可以打开例程/home/qx/ns-allinone-2.35/ns-2.35/tcl/ex/simple.tcl,百度+谷歌,最终发现是在/usr/bin里有重复的nam,需要删除。
完毕后,终于打开了num界面,显示了simple.tcl的仿真。
3 熟悉tcl语法
(1)直接在终端输入tclsh进入交互编写程序/以文本形式保存为.tcl文件,chmod +x XXX.tcl赋予执行权限,./XXX.tcl执行
(2)仅仅支持字符串string。
行首或段首可使用#注释,行末一定要用;#注释!!!行末一定要用;#注释!!!行末一定要用;#注释!!!
基本语法格式:cmd arg1 arg2 … cmd为内置命令或过程,arg为该命令的参数,以空格或Tab分隔,以换行或分号结束。
(3)变量:set var value unset var 变量代表的值:$val
(4)字符串处理:
索引:
%string index abcd 2
c
%string index abcd end
d
判断:
%string is alnum abc123
1
%string is alpha abc123
0
匹配:
*匹配任意数量字符,?匹配一个字符,[chars]匹配指定chars内的任意一个字符
%string match a*d abcd
1
% string match a?b abc
0
% string match a??d abcd
1
% string match {[a-z][A-Z][A-Z]} aBC
1
大小:
% string length abcd
4
大小写转换:
% string toupper abcd
ABCD
% string tolower ABCDabcd
abcdabcd
% string toupper abcdabcd 3 5
abcDABcd
% string totitle abcdABCD
Abcdabcd
剪切:
% string trimright abcdabcd "cd"
abcdab
% string trimleft abcdabcd "ab"
cdabcd
% string trim abcdabcd "a d"
bcdabc
(5)数学运算
函数:
% expr sin(3.1415926/2)
0.9999999999999997
% expr int(2.33)
2
% expr sqrt(4)
2.0
% expr rand(5)
too many arguments for math function "rand"
% expr rand()
0.6298105524060366
% expr abs(-2)
2
% expr log10(10)
1.0
% expr log(2)
0.6931471805599453
% expr pow(2,4)
16.0
逻辑:
% expr 3^2
1
% expr 3&2
2
%
% expr 3|2
3
% expr 3||2
1
% expr 3&&2
1
% expr 1?(2+1):(2*1)
3
操作:
% expr 4<<2
16
% expr 4>>2
1
%
% expr 2==1
0
% expr 2!=1
1
% expr 2>1
1
% expr !2
0
% expr ~2
-3
% expr ~(-2)
1
(6)流控语句
if语句:
if {$x<0} {
puts "input num $x less than 0"
} elseif {$x==0} {
puts "input num $x equal 0"
} else {
puts "input num $x more than 0"
}
switch语句:
# -exact严格匹配 -glob模糊匹配/通配符 -regexp正则表达式
switch -exact $x {
0 {puts "input is 0"}
10 {puts "input is 10"}
100 {puts "input is 100"}
default {puts "hello"}
}
while语句:
root@qx-IdeaPad-U430p:/home/qx/files# cat while.tcl
#!/usr/bin/tclsh8.5
puts "input a num: "
flush stdout;
set x [gets stdin]
set j 0
set i 1
while {$i<$x} {
set j [expr $j+$i]
incr i;#i加一,incr i-1为递减
}
puts $j
root@qx-IdeaPad-U430p:/home/qx/files# chmod +x while.tcl
root@qx-IdeaPad-U430p:/home/qx/files# ./while.tcl
input a num:
10
45
for语句:
先执行,再incr i !!!先执行,再incr i !!!先执行,再incr i !!!
root@qx-IdeaPad-U430p:/home/qx/files# cat fortest.tcl
#!/usr/bin/tclsh8.5
puts "input a num: "
flush stdout;
set x [gets stdin]
set j 0
for {set i 0} {$i<$x} {incr i} {
set j [expr $j+$i]
}
puts "output \"j\" is $j"
root@qx-IdeaPad-U430p:/home/qx/files# chmod +x fortest.tcl
root@qx-IdeaPad-U430p:/home/qx/files# ./fortest.tcl
input a num:
5
output "j" is 10
foreach语句:
root@qx-IdeaPad-U430p:/home/qx/files# cat foreachtest.tcl
#!/usr/bin/tclsh8.5
foreach value {1 2 3 4 5 6 7 8 9} {
puts $value
}
root@qx-IdeaPad-U430p:/home/qx/files# chmod +x foreachtest.tcl
root@qx-IdeaPad-U430p:/home/qx/files# ./foreachtest.tcl
1
2
3
4
5
6
7
8
9
break和continue语句同C语言
(7)输入输出
输出:puts
% set var 12
12
% puts $var
12
% puts "$var"
12
% puts {$var}
$var
使用""和{}作用是不同的
puts默认输出后换行,可以使用-nonewline不换行
读入:
flush stdout;
set x [gets stdin]
(8)过程
root@qx-IdeaPad-U430p:/home/qx/files# cat proctest.tcl
#!/usr/bin/tclsh8.5
puts -nonewline "input the first num: "
flush stdout;
set x [gets stdin]
puts -nonewline "input the second num: "
flush stdout;
set y [gets stdin]
proc calvalue {var1 var2} {
set result 1
for {set i 0} {$i < $var2} {incr i} {
set result [expr $result*$var1]
}
return $result
}
puts [calvalue $x $y]
root@qx-IdeaPad-U430p:/home/qx/files# chmod +x proctest.tcl
root@qx-IdeaPad-U430p:/home/qx/files# ./proctest.tcl
input the first num: 2
input the second num: 3
8
过程中亦可以使用global var1将var1设置为全局变量,无须使用return
(9)数组
使用set定义数组,每次定义一个元素,数组元素可以无上限。
% for {set i 0} {$i < 10} {incr i} {
set a($i) $i
}
% for {set i 0} {$i < 10} {incr i} {
puts $a($i)
}
0
1
2
3
4
5
6
7
8
9
可以使用unset删除数组内某个元素
% puts $a(0)
0
% unset a(0)
% puts $a(0)
can't read "a(0)": no such element in array
也可以用unset删除整个数组
% unset a
% puts $a(2)
can't read "a(2)": no such variable
(10)列表
% set b [list 0 1 2 3 4 5 6 7 8 9]
0 1 2 3 4 5 6 7 8 9
% puts [lindex $b 9]
9
% puts [lrange $b 3 7]
3 4 5 6 7
% puts [llength $b]
10
% lappend b a
0 1 2 3 4 5 6 7 8 9 a
% set b [linsert $b 5 d]
0 1 2 3 4 d 5 6 7 8 9 a
% set b [lreplace $b 1 3 a b c]
0 a b c 4 d 5 6 7 8 9 a
% set b [lsort $b]
0 4 5 6 7 8 9 a a b c d
(11)OTcl以及类和对象(注意,OTcl需要在ns环境下,而不是前面的tclsh环境)
采用Class定义类,可以使用类名定义对象。info来查询类和对象的从属关系。
root@qx-IdeaPad-U430p:/home/qx/files# ns
% Class food
food
% food banana
banana
% food fish
fish
% food beef
beef
% banana info class
food
% food info instances
beef banana fish
类的方法定义与C++不同,可以随时增加成员函数instproc和成员变量instvar,关键字很直白嘛。
举个小例子
beef banana fish
% food instproc IS {input} { ;#整个food类来定义成员函数,使用food的对象来使用IS
$self instvar var ;#$self代表类food本身,var为类food的成员变量
set var $input ;#可以在函数里对变量进行各种操作,这里是直接赋值
puts "$self is $var" ;#函数的其他操作
}
% banana IS fruit ;#调用时 对象+成员函数+参数
banana is fruit
% beef IS meat
beef is meat
类的继承
OTcl成员函数和成员变量只有public属性,即可以由子类继承。
% Class food2 -superclass food ;#food2继承food,为food的子类。
food2
% food2 apple ;同样的,food2继承了food的方法。
apple
% apple IS fruit
apple is fruit
% food2 info heritage ;#也很直白,food2是food的继承人
food Object
多继承
food2继承food,food3继承food2,且继承fish
Class food3 -superclass {food2 fish}
则调用同名成员函数时,应按照从左到右,先子后父的顺序
构造函数
food2 instproc init {args} {
puts "class food2 initialize"
eval $self next $args ;#next表示父类中的同名函数,这里指food的init函数
}
呼,经过一整天的学习,到这里tcl语法应该基本上够用了,一些细节可以和其他高级用法可以在实践中一边学习一边使用。
4. 第一个入门例程(网上找的)
咳咳咳,简单有线网络模型模拟,,,,,,怎么看都不简单,不过不慌,毕竟才开始使用ns第二天嘛。
先粘代码,让我分析一下。
############以下是代码######################################################
root@qx-IdeaPad-U430p:/home/qx/files/wired# cat wired.tcl
#!/usr/bin/tclsh8.5
###################################################################
######################简单有线网络模拟---六节点杠铃拓扑结构########
###################################################################
#NS 仿真模拟必须简历一个模拟对象(Simulator 类的对象)
set ns [new Simulator]
#定义不同数据流的颜色(NAM显示使用)
$ns color 1 Blue ;#1为蓝色
$ns color 2 Red ;#2 为红色
#开启Trace跟踪文件,记录分组传送的过程
set tracefd [open wired.tr w]
$ns trace-all $tracefd
#开启NAM显示文件
set nf [open wired.nam w]
$ns namtrace-all $nf
#定义结束过程,关闭Trace文件和NAM显示文件,模拟结束时会进行调用
proc finish {} {
global ns tracefd nf
$ns flush-trace
close $tracefd
close $nf
exit 0
}
#定义节点n0~n5
set n0 [$ns node]
set n1 [$ns node]
set n2 [$ns node]
set n3 [$ns node]
set n4 [$ns node]
set n5 [$ns node]
#定义节点间的双向链路(包括带宽、时延和队列类型)
$ns duplex-link $n0 $n1 2Mb 10ms DropTail
$ns duplex-link $n1 $n2 2Mb 10ms DropTail
$ns duplex-link $n1 $n4 2Mb 20ms DropTail
$ns duplex-link $n3 $n4 2Mb 10ms DropTail
$ns duplex-link $n4 $n5 2Mb 10ms DropTail
#定义关键链路(节点1和节点4之间的链路) 的队列长度
$ns queue-limit $n1 $n4 10
#指定节点间的相互位置(节点的布局,NAM动画显示时使用)
$ns duplex-link-op $n0 $n1 orient right-down ;#定义节点1在节点0右下方
$ns duplex-link-op $n2 $n1 orient right-up ;#定义节点1在节点2右上方
$ns duplex-link-op $n1 $n4 orient right; #定义节点4在节点1正右方
$ns duplex-link-op $n3 $n4 orient left-down; #定义节点4在节点3左下方
$ns duplex-link-op $n5 $n4 orient left-up; #定义节点4在节点5左上方
#监视关键链路的队列情况,方便NAM显示时观察
$ns duplex-link-op $n1 $n4 queuePos 0.5
#建立一个TCP链接
set tcp [new Agent/TCP] ; #建立一个TCP发送代理
$tcp set calss_ 2
$ns attach-agent $n0 $tcp ;#绑定TCP发送代理到节点0
set sink [new Agent/TCPSink] ;#建立一个TCP接受代理
$ns attach-agent $n5 $sink ;# 绑定TCP接收代理到节点5
$ns connect $tcp $sink ;#链接TCP发送代理和接收代理
$tcp set fid_ 1 ;#设置TCP分组的颜色为蓝色(NAM显示时客观查)
#在TCP链接上建立FTP流
set ftp [new Application/FTP] ;#建立一个FTP应用
$ftp attach-agent $tcp ;#将FTP应用绑定到TCP发送代理
$ftp set type_ FTP
#建立一个UDP链接
set udp [new Agent/UDP] ;#建立一个UDP发送代理
$ns attach-agent $n2 $udp ;#绑定UDP发送代理到节点2
set null [new Agent/Null] ;#建立一个UDP接收代理
$ns attach-agent $n3 $null ;#绑定UDP接收代理到节点3
$ns connect $udp $null ;#链接UDP发送代理和接收代理
$udp set fid_ 2 ;#设置UDP分组的颜色为红色 (NAM显示时客观查)
#在UDP链接上建立CBR流
set cbr [new Application/Traffic/CBR] ; #建立一个CBR流应用
$cbr attach-agent $udp ;#将CBR流应用绑定到UDP发送代理
$cbr set type_ CBR
$cbr set packet_size_ 1000 ;#设置分组大小
$cbr set rate_ 1mb ;#设置数据速率
$cbr set random_ false
#设置代理的启动和停止时间
$ns at 0.5 "$cbr start" ;# 设定cbr流在0.5s开始
$ns at 1.0 "$ftp start" ;#设定ftp流在。0s开始
$ns at 9.0 "$ftp stop" ;#设定ftp流在0.5s结束
$ns at 9.5 "$cbr stop" ;#设定cbr流在9.5s结束
$ns at 9.5 "$ns detach-agent $n0 $tcp; $ns detach-agent $n5 $sink"
#在模拟结束时结束过程
$ns at 10.0 "finish"
#打印CBR数据分组大小和间隔
puts "CBR packet_size_= [$cbr set packet_size_]"
puts "CBR interval = [$cbr set interval_]"
#执行模拟
$ns run
##############以上是代码#########################################
执行:
root@qx-IdeaPad-U430p:/home/qx/files/wired# ns wired.tcl
CBR packet_size_= 1000
CBR interval = 0.0080000000000000002
root@qx-IdeaPad-U430p:/home/qx/files/wired# nam wired.nam
首先,我把这个代码原原本本抄了一遍,然后运行失败了。找了很久bug,一直到了晚上才发现。
attach-agent打成了attatch-agent了,细节决定成败阿。
运行效果图如下:
trace文件的内容:
+ 1 0 1 tcp 40 ------- 1 0.0 5.0 0 63
- 1 0 1 tcp 40 ------- 1 0.0 5.0 0 63
r 1 4 3 cbr 1000 ------- 2 2.0 3.0 56 56
r 1.002 1 4 cbr 1000 ------- 2 2.0 3.0 58 58
+ 1.002 4 3 cbr 1000 ------- 2 2.0 3.0 58 58
- 1.002 4 3 cbr 1000 ------- 2 2.0 3.0 58 58
r 1.002 2 1 cbr 1000 ------- 2 2.0 3.0 61 61
+ 1.002 1 4 cbr 1000 ------- 2 2.0 3.0 61 61
这里我用more来展示,不然满屏的数据,要翻阅很久。
nam用于仿真结果可视化,trace应该是节点流量跟踪数据。