Version 4 of TCL interpreter through socket

Updated 2011-03-31 16:29:54 by AMG

Hi,

we have our application written in Agilent VEE. From our application we want to manage a network tester equipment. The network tester provides us with TCL API functions to control it. Agilent VEE application does not work with TCL at all. So we would like to develop a TCL interpreter that running on localhost. This TCL interpreter is supposed to load network test TCL API package and open a socket to accept API commands or even scripts from our Agilent VEE application.

Any ideas where should we start?

AMG: It's pretty easy to glue an interpreter eval loop to a Tcl TCP/IP socket, but you have to come up with a network protocol that you can use in VEE. I know nothing about VEE, so I'm no help there.

Here's some simple code:

package require Tcl 8.4
proc accept {sock peeraddr peerport} {
    fconfigure $sock -buffering line
    set slave [interp create]
    set script ""
    while {[gets $sock line] != -1} {
        append script $line\n
        if {[info complete $script]} {
            puts $sock [list [catch [list $slave eval $script] result] $result]
            set script ""
        }
    }
    interp delete $slave
    close $sock
}
set serv [socket -server accept 9999]
vwait forever

This program listens on TCP port 9999. When a connection is made, it reads a line of text and adds it to its script buffer. If the script buffer is complete (no mismatched open braces and brackets), it evaluates it in a slave interpreter, and the result is sent back to the client. Only one connection may be made at a time.

The result is formatted as a two-element Tcl list followed by a newline. The first element is 0 if the script executed without error, 1 if there was a problem. The second element is the result, which is either the normal return value or the error message. An empty result is indicated by "0 {}" followed by newline. Newline is a CR/LF pair. For more information on how Tcl lists are formatted, see the Dodekalogue.

Try it out using telnet to see how it behaves.

For more advanced ideas, you can have a look at the comm package (source: [L1 ]).

By the way, you might want a little explanation of how this line works:

puts $sock [list [catch [list $slave eval $script] result] $result]

Let's break it down, step-by-step:

  • $1 = [list $slave eval $script] - Construct a three-element list that will be the first argument to [catch].
    • $slave - Name of the slave interpreter, which is also a command.
    • eval - Interpreter subcommand that means to evaluate the concatenated arguments inside the interpreter, like [interp eval].
    • $script - Script to be executed in the slave interpreter.
  • $2 = [catch $1 result] - Execute the script denoted by $1, store the result in $result, and return 0 or 1 on success or error.
    • $1 - Script to execute.
    • result - Name of the variable into which the result will be stored.
  • $3 = [list $2 $result] - Construct a two-element list which will be sent to the client.
    • $2 - Success/error return from [catch].
    • $result - Result obtained by [catch].
  • puts $sock $3 - Send the two-element list $3 to the client.
    • $sock - Name of the TCP communication channel.
    • $3 - Text to send. A newline will be appended.