这是一个模拟MM1队列服务器的代码(实际上不是一个重要的事实)。我试图获得每次运行队列中数据包数的平均值。鉴于我从文件中读取lambda的值,修改它,再次将其修改后的新值保存在文件中,然后使用当前值lambda运行模拟:
#Create a simulator object
set ns [new Simulator]
global ns tracefile namf Qsize Qbw Qlost Qmon Avgvals InterArrivalTime lambda
proc readfile {filename} {
set f [open $filename]
set data [read $f]
close $f
return $data
}
proc writefile {filename data} {
set f [open $filename w]
puts -nonewline $f $data
close $f
}
#Define different colors for data flow (for NAM)
$ns color 1 Blue
#Open the NAM trace file
set namf [open QMM1.nam w]
$ns namtrace-all $namf
set Qsize [open Qsize.tr w]
set Qbw [open Qbw.tr w]
set Qlost [open Qlost.tr w]
set Avgvals [open Avgvals.tr a+]
set tracefile [open out.tr w]
$ns trace-all $tracefile
#set lambda and Mu
set mu 1100.0
catch {set lambda [readfile LamdaValue.tr]}
set lambda [expr {$lambda + 100.0}]
writefile LamdaValue.tr $lambda
#Create the Node to generate the traffic Queue and Server
set n1 [$ns node]
set n2 [$ns node]
# Since packet sizes will be rounded to an integer
# number of bytes, we should have large packets and
# to have small rounding errors, and so we take large bandwidth
#Create link between the two nodes
set link [$ns simplex-link $n1 $n2 100kb 0ms DropTail]
#Monitor the queue for link (n1-n2) for nam
$ns simplex-link-op $n1 $n2 queuePos 0.5
#set up a large Queue capacity (n1-n2)
$ns queue-limit $n1 $n2 100000
# generate random interarrival times and packet sizes
#Set arrivals to be exponential
set InterArrivalTime [new RandomVariable/Exponential]
#Avg=1/lambda
#$InterArrivalTime set avg_ [expr 1/$lambda]
set pktSize [new RandomVariable/Exponential]
$pktSize set avg_ [expr 100000.0/(8*$mu)]
#Set src to use UDP
set src [new Agent/UDP]
$src set fid_ 1
$ns attach-agent $n1 $src
# queue monitoring, write statistics to queueStat
set Qmon [$ns monitor-queue $n1 $n2 [open queueStat.out w] 0.1]
$link queue-sample-timeout
proc record {} {
global ns Qmon Qsize Qbw Qlost n1 n2 Avgvals lambda
set time 0.05
set now [$ns now]
# print in the file $Qsize the current queue size
# print in the file $Qbw the current used bandwidth
# print in the file $Qlost the loss rate
$Qmon instvar parrivals_ pdepartures_ bdrops_ bdepartures_ pdrops_
puts $Qsize "[expr $parrivals_-$pdepartures_-$pdrops_]"
puts $Qbw "$now [expr $bdepartures_*8/1024/$time]"
set bdepartures_ 0
puts $Qlost "$now [expr $pdrops_/$time]"
$ns at [expr $now+$time] "record"
}
proc finish {} {
global ns tracefile namf Qsize Qbw Qlost Qmon
$ns flush-trace
#Close the NAM trace file
close $namf
close $Qsize
close $Qbw
close $Qlost
close $tracefile
#Execute NAM on the trace file
#exec ./nam QMM1.nam &
exit 0
}
proc sendpacket {} {
global ns src InterArrivalTime pktSize
set time [$ns now]
$ns at [expr $time + [$InterArrivalTime value]] "sendpacket"
set bytes [expr round ([$pktSize value])]
$src send $bytes
}
proc Avg {} {
global ns Qmon Qsize Qbw Qlost n1 n2 Avgvals lambda
set sum 0.0
set c 1
set fid [open Qsize.tr r]
set txt [read $fid]
close $fid
foreach {x} $txt {
set sum [expr {$sum + $x}]
incr c 1
}
set avg [expr $sum/$c]
puts $Avgvals "$lambda $avg"
}
set sink [new Agent/Null]
$ns attach-agent $n2 $sink
$ns connect $src $sink
proc repeatSim {} {
global lambda
if {$lambda < 1002} {
exec ./ns QMM1.tcl &
}
}
#Avg=1/lambda
$InterArrivalTime set avg_ [expr 1/$lambda]
puts "Lambda = $lambda"
puts "Mu = $mu"
$ns at 0.0 "record"
$ns at 0.0001 "sendpacket"
$ns at 1000.0 "Avg"
$ns at 1000.0 "repeatSim"
#Run the simulation
$ns run
问题在于它执行前三个自我调用:
proc repeatSim {} {
global lambda
if {$lambda < 1002} {
exec ./ns QMM1.tcl &
}
}
然后它在标题中给出错误。 完整的错误声明是:
ns: Avg: can't use non-numeric string as operand of "+"
while executing
"expr {$sum + $x}"
(procedure "Avg" line 12)
invoked from within
"Avg"
我在代码中尝试了几次操作,但错误仍然以相同的方式显示。 你能说出问题所在吗?
答案 0 :(得分:2)
让我们更仔细地查看该错误消息。
ns: Avg: can't use non-numeric string as operand of "+" while executing "expr {$sum + $x}" (procedure "Avg" line 12) invoked from within "Avg"
它表示+
运算符的其中一个参数不是数字,而是在expr {$sum + $x}
的过程的第12行调用Avg
。 / p>
可能是哪个论点?什么可能真的错了?让我们看一下您的代码(为了清晰起见,重新缩进)。
proc Avg {} {
global ns Qmon Qsize Qbw Qlost n1 n2 Avgvals lambda
set sum 0.0
set c 1
set fid [open Qsize.tr r]
set txt [read $fid]
close $fid
foreach {x} $txt {
set sum [expr {$sum + $x}]
incr c 1
}
set avg [expr $sum/$c]
puts $Avgvals "$lambda $avg"
}
好的,有问题的行在foreach
中,并且它用于添加$txt
的字词(即从文件中读取)浮点数(因为sum
初始化为0.0
)。好吧,因为sum
将继续保持浮点数,前提是要添加的所有值都是数字,我们必须有问题,文件中的一个单词不是数字。它不能成为别的因为表达本身就是括号,保证了在Tcl级别的可靠解释。 (expr $sum/$c
不太好,但是在Tcl 8.5和8.6中可以预见,我们使用自定义高可靠性浮点到字符串转换器而不是标准C库中有点不稳定的那个。)
我们无法从提供的信息中了解违规的价值;错误跟踪没有记录它(它没有所有或者它太笨重)并且你没有提供失败的样本。如果您要进行调试,可以尝试将代码更改为:
proc Avg {} {
global ns Qmon Qsize Qbw Qlost n1 n2 Avgvals lambda
set sum 0.0
set c 1
set fid [open Qsize.tr r]
set txt [read $fid]
close $fid
foreach {x} $txt {
if {[catch {
set sum [expr {$sum + $x}]
incr c 1
}] {
puts "The value at index #$c ('$x') is not numeric"
}
}
set avg [expr $sum/$c]
puts $Avgvals "$lambda $avg"
}
如果事实证明问题在于您正在阅读的文件中有额外的metasyntax,则需要在将值加起来之前处理该问题。
你的代码也有一个错误:“平均值”会有点低,因为c
会导致一个太大。