I have a template program pasted further below, mostely taken from the
web. It seems to *almost* work. The communication part works, but
the code never gets to the real working code. Though simulated by a
simple loop, in actual practice the real working code is over a
hundred thousand lines spread accross many .tcl files.
How do I get the working code to work as normal and yet have the
communications set up? I have tried all sorts of arrangements, with
and without the vwait.
# ---------------------paste example
# Run this in one window, say, on the_host,
# In another window,
# telnet the_host 9900
# The result will show
# Connection from the_host registered
# every time 'telnet the_host 9900' is done.
#
global do_the_action
set do_the_action 0
proc Server {channel clientaddr clientport} {
puts "Connection from $clientaddr registered"
puts $channel [clock format [clock seconds]]
close $channel
set do_the_action 1
}
socket -server Server 9900
vwait forever
# And here is the corresponding client to talk to the server:
set server localhost
set sockChan [socket $server -myaddr 9900]
gets $sockChan line
close $sockChan
puts "The time on $server is $line"
# Unfortuantely, the code execution never gets past here. This
# simulates the real, working section of the code, and is in reality
# well over a hundred thousand lines long.
for {set x 0} {$x<10} {incr x} {
puts "x is $x"
after 1000
if { $do_the_action } { break; }
}
#--------------------- end paste example
This is mostly OK. The global declaration needs to be moved inside the
Server proc, as the way the program is written "set do_the_action 0" is
setting a global variable and "set do_the_action 1" is setting a
different local variable.
> # And here is the corresponding client to talk to the server:
>
> set server localhost
> set sockChan [socket $server -myaddr 9900]
>
> gets $sockChan line
> close $sockChan
> puts "The time on $server is $line"
>
> # Unfortuantely, the code execution never gets past here. This
> # simulates the real, working section of the code, and is in reality
> # well over a hundred thousand lines long.
>
> for {set x 0} {$x<10} {incr x} {
> puts "x is $x"
> after 1000
> if { $do_the_action } { break; }
> }
The syntax for [socket $server -myaddr 9900] should be [socket $server
9900]. If I make that change, then execution *does* get to your sample
code, but it errors out because there's no such variable as
do_the_action on the client end... it can't magically tunnel through the
socket to see the one on the server end (which is always 0 anyway).
Are you seeing the printouts for the values of x?
# ---------------------paste example
# Run this in one window, say, on the_host,
# In another window,
#
# The result will show
# Connection from the_host registered
# every time 'telnet the_host 9900' is done.
#
global do_the_action
set do_the_action 0
proc Server {channel clientaddr clientport} {
global do_the_action
puts "Connection from $clientaddr registered"
puts "10: do_the_action is $do_the_action"
close $channel
set do_the_action 1
}
socket -server Server 9900
vwait do_the_action
puts "20: do_the_action is $do_the_action"
# Unfortnately, the code execution never gets past here. This
# simulates the real, working section of the code, and is in reality
# well over a hundred thousand lines long.
for {set x 0} {$x<10} {incr x} {
puts "x is $x"
after 1000
if { $do_the_action } { break; }
}
#--------------------- end paste example
The vwait line above means "stop here until the variable do_the_action
is written to". Hence the following for loop is not executed UNLESS
$do_the_action is modified.
To get the effect you want I'd suggest using the event loop by
exploiting [after]:
# global do_the_action <-- this is meaningless
set do_the_action 0
proc Server {channel clientaddr clientport} {
global do_the_action
puts "Connection from $clientaddr registered"
puts "10: do_the_action is $do_the_action"
close $channel
set do_the_action 1
}
socket -server Server 9900
puts "20: do_the_action is $do_the_action"
proc loop {x} {
global do_the_action
puts "x is $x"
incr x
if { $do_the_action } { break; }
after 1000 "loop $x"
}
loop
vwait do_the_action
# for event driven code, vwait should
# always be the last line.
It's rewarding to know that this was successful. Thanks for
taking the trouble to confirm explicitly your satisfaction.
I think this problem deserves a summary I don't know how to put
into words. Fine-grained programmatic remote control of hundreds
of distributed hosts--well, it's a challenge I've seen stump
practitioners with many other languages. The Tcl solution worked
out here is, in contrast, so readable that a beginner can under-
stand it, in my judgment. I wish I knew better how to advertise
such achievements.