From: Justin Gullingsrud (justin_at_ks.uiuc.edu)
Date: Wed Feb 12 2003 - 16:43:19 CST

Oliver,

I think all you have you do is replace "eval $line" in your script
with the following:

set rc [catch $line result]
if { $rc } {
  puts $sock "Error executing comand '$line': \n$result"
} else {
  puts $sock $result
}
This should also fix the problem with erroneous commands causing the server
to fail. What's probably happening is that Tcl is shutting down the socket
when an uncaught error occurs during execution of the read handler.

Cheers,
Justin

On Wed, Feb 12, 2003 at 10:10:04PM +0000, Oliver Beckstein wrote:
> Hello,
>
> I am looking for help with a tcl script (based on vmdcollab) that
> turns vmd into a remote-controlled display server. remote_ctl.tcl is
> appended at the end. (I am sorry if this is too much clutter for the
> list).
>
> At the moment connecting works (telnet localhost 5555) and so does
> sending commands (eg 'draw sphere {1 0 0} radius .3 resolution
> 24'). My main problem is that I don't know how to tell tcl that I want
> VMD's stdout redirected to the socket so that my remote application
> (telnet in this case) can read it. I have tried a fileevent handler on
> stdout but this did not work (it is called perpetually and I still
> cannot access the actual VMD output).
>
> A minor problem is that a wrong command seems to block the connection,
> that is, no commands after the first wrong one will have any effect.
>
> And (as is probably obvious from the code): I am a complete newbie at
> tcl so any help or comments are very much appreciated.
>
> Thanks,
> Oliver
>
> #------------------------------------------------------------------
> # $Id: remote_ctl.tcl,v 1.6 2003/02/12 21:33:11 oliver Exp $
> # based on bounce.tcl and vmdcollab.tcl
> # from http://www.ks.uiuc.edu/Research/vmd/script_library/scripts/vmdcollab/
> #
> # start this in VMD and send commands to the listening port to have VMD
> # execute them remotely
> # (also see http://www.tcl.tk/scripting/netserver.html)
> #
> # Usage: vmd -e remote_ctl.tcl
> # or vmd> source remote_ctl.tcl
> #
> # Security: we only allow connections from localhost (see acpt)
> #
> # Bugs:
> # * once a wrong command was sent, the connection appears
> # to 'block' and does not accept correct commands later
> # * does not write result back to socket (one way connection...) so
> # there is no way to inquire objects in vmd
>
> namespace eval remote_ctl {
> variable main
> variable clients
> variable default_vmd_port
>
> set default_vmd_port 5555
>
> # I am too dumb to set the default value for port from
> # $default_vmd_port so I put 5555 in there literally
> proc start { {port 5555} } {
> variable main
> set main [socket -server remote_ctl::acpt $port]
> putlog "Listening on port $port"
> }
>
> proc acpt { sock addr port } {
> variable clients
> if {[string compare $addr "127.0.0.1"] != 0} {
> putlog "Unauthorized connection attempt from $addr port $port"
> close $sock
> return
> }
> putlog "Accept $sock from $addr port $port"
> set clients($sock) 1
> fconfigure $sock -buffering line
> fileevent $sock readable [list remote_ctl::recv $sock]
> }
>
> proc recv { sock } {
> variable main
> variable clients
> if { [eof $sock] || [catch {gets $sock line}]} {
> # end of file or abnormal connection drop:
> # shut down this connection
> close $sock
> putlog "Closing $sock"
> unset clients($sock)
> } else {
> if {[string compare $line "quit"] == 0} {
> # prevent new connections
> # existing connections stay open
> # No -- Bug(?): 'quit' closes VMD...
> putlog "Disallowing incoming connections by request of $sock"
> close $main
> }
> # execute the received commands
> # should check for runtime errors which otherwise leave the connection
> # in an unusable state
> eval $line
> }
> }
>
>
> ###### would like the last line from stdout in line ###########
> # (or any working solution....)
> proc send { sock line} {
> variable clients
> # send reply to connecting client
> putlog "send '$line' to $sock"
> puts $sock $line
> }
>
>
> proc putlog { text } {
> puts $text
> return
> }
> }
>
>
> # assuming that loading this file means that we actually want to run
> # the server, we just start it:
> remote_ctl::putlog "Starting remote_ctl server in vmd: connect with something like"
> remote_ctl::putlog "telnet localhost 5555"
>
> remote_ctl::start
>
> #-------------------------------------------------------------
>
> --
> Oliver Beckstein * oliver_at_bioch.ox.ac.uk
> http://indigo1.biop.ox.ac.uk/oliver/

-- 
  Justin Gullingsrud        3111 Beckman Institute        217-244-8946
  I been dropping the new science, and I be kicking the new knowledge,
  and I'm seeing to a degree that you can't get in college.  -- b.boys