NS2仿真实验
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

实验二 TCL语言简介

实验目的

学习TCL语言的基本语法。

背景知识

TCL(Tool Command Language)在NS2中主要是用来描述脚本,简单地说就是用来描述要仿真的网络环境和参数设置等。

实验步骤

【安装文书编辑软件PSPad [1]

在开始学习编写脚本之前,选择一个好用的文字编辑器非常重要。在此推荐一个免费的文字编辑器(PSPad,http://www.pspad.com/en/download.php)给大家。

(1)请切换目录到ns-allinone-2.29/ns-2.29/book/lab2的目录下,执行PSPad的安装文件pspad432inst_en.exe,如图2.1所示。

图2.1 执行PSPad的安装文件

(2)请单击“Next”按钮,如图2.2所示。

图2.2 单击“Next”按钮

(3)请选择“I accept the agreement”单选按钮。

(4)请单击“Next”按钮,则如图2.3所示。此图为PSPad的安装路径,可以选择喜欢安装的位置,不过我们在这里使用内定的路径即可。

图2.3 选择安装位置

(5)请单击“Next”按钮,则如图2.4所示。

图2.4 选择选项

(6)请单击“Next”按钮,则如图2.5所示。

图2.5 开始安装

(7)请单击“Install”按钮,开始进行安装。

(8)安装完成后,则如图2.6所示。

图2.6 安装完成

(9)请单击“Finish”按钮,完成安装,并且开始执行PSPad editor,如图2.7所示。

图2.7 开始执行PSPad editor

【TCL语法练习】

这部分的数据主要是参考文献[2],有兴趣的读者可以到此网站寻找更详细的数据。

1. 变量(Variable)和变量替换(Variable Substituion)

正如其他的程序语言一样,变量可以被想成是用来存储各种类型数据的盒子(Boxes)。这些盒子(或者说是变量),都有各自的名称,而这些名称在我们需要取用或者是变更变量的值(Value)时将会被用到。

在C语言中使用变量时,需要事先的声明,而TCL则不需要事先声明,TCL变量是在第一次使用set的指令来指派变量的值时所产生的。当我们不再需要某个变量时,可以使用unset来取消这个变量。但一般而言,可以不用去做这个动作。

当我们要取用或者是改变变量内的值时,只要在变量名称前加上一个“$”,就可以去取用或者是改变变量内的值,这就是所谓的“变量替换”。

练习1.1:请把下面的程序代码使用文字编辑软件存到2_1_1.tcl。

set foo “john”
puts“my name is $foo”

执行方法:($为提示符号)

$ns 2_1_1.tcl

执行结果:

my name is john

说明:

程序的第一行把“john”这个字符串指派给变量foo。程序的第二行使用puts这个指令把后面的字符串表示出来,在表示出来之前,会先把“$foo”先取代成“john”,真正显示出来的字符串是“my name is john”。

练习1.2:请把下面的程序代码使用文字编辑软件存到2_1_2.tcl。

set month 2
set day 3
set year 97
set date "$month:$day:$year"
puts $date

执行方法:

$ns 2_1_2.tcl

执行结果:

2:3:97

说明:

在这个练习中,第四行“set date "$month:$day:$year"的$month”会被2所替代;同理,“$day”为3,“$year”为97,这三个变量替代完后会组成一个新的字符串,并通过set指令把新字符串指派给变量date。

练习1.3:(请把下面的程序代码使用文字编辑软件存到2_1_3.tcl)

set foo "puts hi"
eval $foo

执行方法:

$ns 2_1_3.tcl

执行结果:

hi

说明:

在这个练习中,foo这个变量包含了一个tcl script,接着,第二行程序中“$foo”会替换成“puts hi”,并且当做eval的参数。eval这个指令主要用于去执行一个tcp script,所以最后“hi”会被表示出来。

2. 表达式(Expressions)

TCL包含许多种类的表达式,如数学表达式、关系表达式等。通常这些表达式都会使用“expr”指令去判断表达式的真假或者去求得表达式的值。

练习2.1:请把下面的程序代码使用文字编辑软件保存到2_2_1.tcl文件中。

set value [expr 0==1]
puts $value

执行方法:

$ns 2_2_1.tcl

执行结果:

0

说明:

使用了expr去判断0是否等于1,结果是假,把0存到value变量中,并把结果表示出来。

练习2.2:请把下面的程序代码使用文字编辑软件保存到2_2_2.tcl文件中。

set value [expr 2>=1]
puts $value

执行方法:

$ns 2_2_2.tcl

执行结果:

1

说明:

使用expr去判断2是否大于等于1,结果是真,把1存到value这个变量中,并把结果表示出来。

练习2.3:请把下面的程序代码使用文字编辑软件存到2_2_3.tcl文件中。

set value [expr 2+3]
puts $value

执行方法:

$ns 2_2_3.tcl

执行结果:

5

说明:

使用了expr去求2+3的结果,并把所得到的5存到value这个变量中,最后把结果表示出来。

3. 指令替换(Command Substitution)

如同变量替换,指令替换可以把“原tcl script执行结果”取代“原tcl script”。

练习3.1:请把下面的程序代码使用文字编辑软件存到2_3_1.tcl文件中。

puts "I am [expr 10 * 2] years old, and my I.Q. is [expr 100 - 25]"

执行方法:

$ns 2_3_1.tcl

执行结果:

I am 20 years old, and my I.Q. is 75

说明:

这个练习中,“[ ]”可以用来达成指令替换,在执行此行“tcl script”时,会先执行“[expr 10*2]”和“[expr 100-25]”,并把结果“20”和“75”取代原本tcl script中“[expr 10*2]”和“[expr 100-25]”的位置,最后再使用puts把此字符串表示出来。

练习3.2:请把下面的程序代码使用文字编辑软件保存到2_3_2.tcl文件中。

set my_height 6.0
puts"If I was 2 inches taller,I would be[expr$my_height+ (2.0/12.0)]feet tall"

执行方法:

$ns 2_3_2.tcl

执行结果:

If I was 2 inches taller, I would be 6.166666666666667 feet tall

说明:

在练习中的第二行,[ ]的内容会先被执行,也就是“$my_height”会被6.0替换,“(2.0/12.0)”的结果会先被计算出来,再和6.0相加,然后用两数相加的结果去替换字符串中的“[expr $my_height +(2.0 / 12.0)]”这个位置,最后才把字符串表示出来。

4. 流程控制(Control Flow)

与其他的程序相同,TCL也提供了一些可以用来控制程序运作流程的方法,包含了if-else、switch、while、for、foreach等指令,这些指令用法请参考下面的实例。

练习4.1:请把下面的程序代码使用文字编辑软件存到2_4_1.tcl文件中。

set my_planet "earth"
if {$my_planet == "earth"} {
puts "I feel right at home."
} elseif {$my_planet == "venus"} {
    puts "This is not my home."
} else {
    puts "I am neither from Earth, nor from Venus."
}

set temp 95
if {$temp < 80} {
    puts "It's a little chilly."
} else {
    puts "Warm enough for me."
}

执行方法:

$ns 2_4_1.tcl

执行结果:

I feel right at home.
Warm enough for me.

练习4.2:请把下面的程序代码使用文字编辑软件存到2_4_2.tcl文件中。

set num_legs 4
switch $num_legs {
2 {puts "It could be a human."}
    4 {puts "It could be a cow."}
    6 {puts "It could be an ant."}
    8 {puts "It could be a spider."}
    default {puts "It could be anything."}
}

执行方法:

$ns 2_4_2.tcl

执行结果:

It could be a cow.

练习4.3:请把下面的程序代码使用文字编辑软件存到2_4_3.tcl文件中。

for {set i 0} {$i < 5} {incr i 1} {
            puts "In the for loop, and i == $i"
}

执行方法:

$ns 2_4_3.tcl

执行结果:

In the for loop, and i == 0
In the for loop, and i == 1
In the for loop, and i == 2
In the for loop, and i == 3
In the for loop, and i == 4

练习4.4:请把下面的程序代码使用文字编辑软件存到2_4_4.tcl文件中。

set i 0
while {$i < 5} {
puts "In the while loop, and i == $i"
    incr i 1
}

执行方法:

$ns 2_4_4.tcl

执行结果:

In the while loop, and i == 0
In the while loop, and i == 1
In the while loop, and i == 2
In the while loop, and i == 3
In the while loop, and i == 4

练习4.5:请把下面的程序代码使用文字编辑软件存到2_4_5.tcl文件中。

foreach vowel {a e i o u} {
puts "$vowel is a vowel"
}

执行方法:

$ns 2_4_5.tcl

执行结果:

a is a vowel
e is a vowel
i is a vowel
o is a vowel
u is a vowel

5. 程序(Procedures)

在TCL中,也允许用户去自定程序,定义程序基本的语法为proc name params body。其中,name为程序的名称,params是参数列表,body则是程序的主体。定义完程序后就可以像其他任何的tcl指令一样执行了。

练习5.1:请把下面的程序代码使用文字编辑软件存到2_5_1.tcl文件中。

proc sum_proc {a b} {
return [expr $a + $b]
}

proc magnitude {num} {
if {$num > 0} {
return $num
}

set num[expr$num* (-1)]
return $num
}

set num1 12
set num2 14
set sum [sum_proc $num1 $num2]

puts "The sum is $sum"
puts "The magnitude of 3 is [magnitude 3]"
puts "The magnitude of -2 is [magnitude -2]"

执行方法:

$ns 2_5_1.tcl

执行结果:

The sum is 26
The magnitude of 3 is 3
The magnitude of -2 is 2

说明:

在程序中定义了两个程序:“sum_proc”和“magnitude”,sum_proc有两个输入参数:a和b,这个程序最主要的工作就是把a和b相加,并把结果返回;另外一个程序magnitude只有一个参数num,这个程序最主要就是去判断num是正数或负数,若是正数则直接返回,若是负数就先与-1相乘再返回。简单地说,magnitude就是在求绝对值。

练习5.2:请把下面的程序代码使用文字编辑软件存到2_5_2.tcl文件中。

proc dumb_proc {} {
set myvar 4
    puts "The value of the local variable is $myvar"
    global myglobalvar
    puts "The value of the global variable is $myglobalvar"
}

set myglobalvar 79
dumb_proc

执行方法:

$ns 2_5_2.tcl

执行结果:

The value of the local variable is 4
The value of the global variable is 79

说明:

这个练习主要在说明局部变量(local variable)和全局变量(global variable)的观念。要特别说明的是,当程序中需要用到程序外已经定义好的变量前,必须先使用global这个保留字做声明,才能存取程序外已经定义好的变量。

6. 数组(Arrays)

练习6.1:请把下面的程序代码使用文字编辑软件存到2_6_1.tcl文件中。

set myarray(0) "Zero"
set myarray(1) "One"
set myarray(2) "Two"

for {set i 0} {$i < 3} {incr i 1} {
puts $myarray($i)
}

执行方法:

$ns 2_6_1.tcl

执行结果:

Zero
One
Two

说明:

程序一开始定义了一个名称为myarray的数组,共有三个元素(element),第一个元素是“Zero”,存放在数组中0的位置;第二个是“One”,存放在数组中1的位置;第三个是“Two”,存放在数组中2的位置。程序最后会把数组的每个元素都表示出来。

练习6.2:请把下面的程序代码使用文字编辑软件存到2_6_2.tcl文件中。

set person_info(name) "Fred Smith"
set person_info(age) "25"
set person_info(occupation) "Plumber"

foreach thing {name age occupation} {
puts "$thing == $person_info($thing)"
}

执行方法:

$ns 2_6_2.tcl

执行结果:

name == Fred Smith
age == 25
occupation == Plumber

说明:

这个练习主要说明存放在数组中的元素不一定非要是数字。在TCL中的数组可以存放数字或者字符串,并且存放的位置不一定要用0,1,2,…这样的编号。

练习6.3:请把下面的程序代码使用文字编辑软件存到2_6_3.tcl文件中。

set person_info(name) "Fred Smith"
set person_info(age) "25"
set person_info(occupation) "Plumber"

foreach thing [array names person_info] {
puts "$thing == $person_info($thing)"
}

执行方法:

$ns 2_6_3.tcl

执行结果:

occupation == Plumber
age == 25
name == Fred Smith

说明:

这个练习与练习6.2最大的不同在于foreach这个循环,在练习6.2中,数组中每个元素存放的位置必须一一列出来,才能表示出数组中每个元素的值。但在这个实例中,使用了array names person_info,这样就可以列出person_info中的name,age,occupation,这在元素很多的时候特别好用。

7. 字符串(Strings)

练习7.1:请把下面的程序代码使用文字编辑软件存到2_7_1.tcl文件中。

set str "This is a string"
puts "The string is: $str"
puts "The length of the string is: [string length $str]"
puts "The character at index 3 is: [string index $str 3]"
puts "The characters from index 4 through 8 are: [string range $str 4 8]"
puts "The index of the first occurrence of letter \"i\" is: [string first i $str]"

执行方法:

$ns 2_7_1.tcl

执行结果:

The string is: This is a string
The length of the string is: 16
The character at index 3 is: s
The characters from index 4 through 8 are:  is a
The index of the first occurrence of letter "i" is: 2

说明:

练习中的“[string length $str]”可以用来显示字符串长度,“[string index $str 3]”可以用来显示字符串中的第四个字母为何(第一个字母的index为0),“[string range $str 4 8]”可以用显示从字符串中第五个到第九个的字母,“[string first i $str]”可以用来显示字母i在字符串中第一次出现时的index值,也就是第一次出现时在第(index+1)个位置。

8. 输出(Output)

练习8.1:请把下面的程序代码使用文字编辑软件存到2_8_1.tcl文件中。

set f [open "/tmp/myfile" "w"]
puts $f "We live in Texas. It's already 110 degrees out here."
puts $f "456"
close $f

执行方法:

$ns 2_8_1.tcl

执行结果:

请使用文字编辑器打开/tmp/myfile,其内容为:

We live in Texas. It's already 110 degrees out here.
456

说明:

一般来说,puts若是没有指定输出装置的话,内定的输出装置是屏幕,但此实例中指定了输出的装置为文件,会把要显示的字符串写入文件内。

【参考文献】

[1] http://www.pspad.com/en/download.php.

[2] http://hegel.ittc.ku.edu/topics/tcltk/tutorial-noplugin.html.