esrf

Beamline Instrument Software Support
SPEC Macro documentation: [ Macro Index | BCU Home ]

#
#  @(#)server.mac       5.2  01/10/02 CSS
#
#  "Spec" Release 5
#
#  Copyright (c) 2002
#  by Certified Scientific Software.
#  All rights reserved.
#  Copyrighted as an unpublished work.
#
#########################################################################
#
# Spec "server" macros
#
# Macros for simple communication between two instances of spec,
# with one instance acting as a remote server, the other as
# a client sending commands.
#
# The server and the client need to use the same port number.
#
# For example, on the server system (named TheServer) execute the command:
#
#       server 6666
#
# From the other system first execute the following to connect to the
# host with the name TheServer:
#
#       remote_setup TheServer 6666
#
# Then you can run commands from on TheServer with:
#
#       r wa
#       r umvr tth 1
#
# To receive a reply from the server, send the command using the
# remote_send() function directly, as in
#
#       print remote_send("2 * PI")
#       S[det] = remote_send("S[det")
#
# Note, there is presently no way to abort a command running on the
# server from the remote client.
#
# Note, also, turning on simulate mode on the server from the client
# will stop the server from responding to commands, so don't do that.
#
# Only one client at a time can connect to the server.  However, it
# is possible for multiple clients to access the server in a round-
# robin fashion.
#
# If the global variable SERVER_SHARE is zero (the most efficient
# for a single client), the connection will be maintained over multiple
# commands to the server, locking out other clients.  If SERVER_SHARE
# is nonzero, each client will disconnect from the server after sending
# a command, allowing another client to connect.

# Start the server at the specified port number
def server '{
        global  SERVER_PORT

        if ($#) {
                SERVER_PORT = $1
        } else if (SERVER_PORT == 0) {
                eprint "Usage:  server port_number"
                exit
        }
        if (set_sim(-1)) {
                eprint "Can\'t run server in simulate mode."
                exit
        }
        server_func()
}'
# close twice to remove the listen socket and the connection socket
def server_cleanup '{
        local s

        cdef("cleanup_once", "", "_server_clean_", "delete")
        s = "localhost:" SERVER_PORT
        sock_par(s, "close")
        sock_par(s, "close")
}'
def server_func() '{
        local s cmd ret

        cdef("cleanup_once", "server_cleanup\n", "_server_clean_")

        s = "localhost:" SERVER_PORT
        sock_par(s, "listen")
        sock_par(s, "timeout", 0)

        print "Entering server loop.  Type ^C to quit."
        while (1) {
                cmd = sock_get(s, 0)
                if (cmd == 0 || cmd == "")
                        continue
                printf("** %s", cmd)
                ret = eval(cmd)
                printf("== %s\n", ret)
                sock_put(s, sprintf("%s\n", ret))
        }
}'

# Enter server host and port info
def remote_setup '{
        global SERVER_ID, SERVER_SHARE

        if ($# != 2) {
                eprint "Usage:  remote_setup hostname port_number"
                exit
        } else
                SERVER_ID = "$1" ":" "$2"
}'

def r \'remote\'
def remote '{
        remote_send("$*")
}'

# close the connection to the server, allowing other clients to connect
def remote_cleanup() '{
        cdef("cleanup_once", "", "_remote_clean_", "delete")
        sock_par(SERVER_ID, "close")
}'
# sent the command and receive the reply
def remote_send(cmd) '{
        local   r

        if (!SERVER_ID) {
                eprint "Call \"remote_setup\" first."
                exit
        }
        if (!sock_par(SERVER_ID, "connect")) {
                eprintf("\
Can\'t connect to \"%s\".\n\
Have you started \"server\" on the remote system?\n", SERVER_ID)
                exit
        }
        cdef("cleanup_once", "remote_cleanup()\n", "_remote_clean_")
        sock_par(SERVER_ID, "timeout", 0)
        sock_put(SERVER_ID, sprintf("%s\n", cmd))
        ote_clean_", "delete")
        sock_par(SERVER_ID, "close")
}'
# sent the command and receive the reply
def remote_send(cmd) '{
        local   r

        if (!SERVER_ID) {
                eprint "Call \"remote_setup\" first."
                exit
        }
        if (!sock_par(SERVER_ID, "connect")) {
                eprintf("\
Can\'t connect to \"%s\".\n\
Have you started \"server\" on the remote system?\n", SERVER_ID)
                exit
        }
        cdef("cleanup_once", "remote_cleanup()\n", "_remote_clean_")
        sock_par(SERVER_ID, "timeout", 0)
        sock_put(SERVER_ID, sprintf("%s\n", cmd))
        r = sock_get(SERVER_ID, 0)
        if (SERVER_SHARE)
                remote_cleanup()
        return(r)
}'