tclmsgque
The
TCL Application-Server Project
package require TclMsgque
OBJECT CREATION AND DELETION
OBJECT CONFIGURATION
LINK CREATION AND DELETION
ADDING SERVICES
SEND DATA
READ DATA
SLAVE OBJECT
BUFFER OBJECT
EXCEPTION OBJECT
CONTEXT LOCAL STORAGE
The msgque project is an infrastructure to link software together to act like a single software. To link mean distributing work from one software to an other software an wait or not wait for an answer. The linking is done using unix or inet domain sockets and is based on packages send from one software to an other software and back. The msgque project is used to handle all the different aspects for setup and maintain the link and is responsible for:
- starting and stopping the server application
- starting and stopping the communication interface
- sending and receiving package data
- reading and writing data from or into a package
- setup and maintain the event-handling for an asynchronous transfer
- propagate the error messages from the server to the client
The
object is the user visible part of a tclmsgque application link.
Create an object ready to be used with
$ctx LinkCreate ... to setup an application link. Use the
isConnected to check if a link is already available.
Delete the entire object including the application link using
$ctx LinkDelete. The object can
not be reused.
The configuration of an object is done using the functions starting with
MqConfig... or by using command-line arguments.
Initialize the process startup argument prefix. The startup-prefix have to be the name of the executable found in the
PATH and additional arguments like a script name or required startup options. The startup-prefix is used for two different purpose:
- To start a new entity using the --spawn command-line option
- To replace the SELF argument after the "@" command-line argument
The startup-prefix is initially set by tclmsgque during package loading.
type: int,
get: ConfigGetBuffersize ,
set: ConfigSetBuffersize
The send and receive buffersize in bytes (default: 4KB)
type: int,
get: ConfigGetDebug ,
set: ConfigSetDebug
Debug a message-queue application. Valid values are 0 <= NUM <= 9 using 0 for "no debugging" and 9 for "maximum debugging". (default: 0)
type: int,
get: ConfigGetTimeout ,
set: ConfigSetTimeout
User defined timeout used for connection setup and data sending (default: 90 seconds)
type: string,
get: ConfigGetName ,
set: ConfigSetName
Use STRING as basename of the new message-queue object. The name shows up in the debugging output and is used as prefix for the new created command. (default: the name of the executable)
type: string,
get: ConfigGetSrvName ,
set: ConfigSetSrvName
Use STRING as a client specific prefix in the server debugging output. This is used to link debugging and error messages on the server to a specific client connection. (default: empty)
type: boolean,
get: ConfigGetIsSilent ,
set: ConfigSetIsSilent
Write (no) or don't write (yes) any output to stdout or stderr. (default: write to stdout or stderr)
type: boolean,
get: ConfigGetIsString ,
set: ConfigSetIsString
Use (yes), as much as possible, strings in the data-package. Convert any native data-type, like integer or double, into a string (sending) and back to native (receiving). (default: use binary)
type: integer,
get: ConfigGetStartAs ,
set: ConfigSetStartAs startAs
Start a new server as thread or spawn a new process or fork a new process. This arguments are used with:
- a server-context to start a new instance after a client connection request
- on a server to create a worker with: $ctx SlaveWorker id ...
- on a client/server together with the "SELF" command-line argument: $ctx LinkCreate ...
- Parameters:
-
| [in] | startAs | 0=default, 1=fork, 2=thread and 3=spawn |
type: string,
get: ConfigGetStartAs ,
set: ConfigSetStartAs pidfile
Close all default IO (e.g stdout, stdin, stderr) and fork the server into the background. (default: no daemon)
- Attention:
- this option require the fork system-call and is not compatible with threads.
- Parameters:
-
| [in] | pidfile | the name of the file to write the PID into |
type: string,
get: ConfigGetIoTcpHost/Port/MyHost/MyPort ,
set: ConfigSetIoTcp host port myhost myport
Configure a tcp socket link.
- Parameters:
-
| host | client: name of the remote host (default: localhost)
server: name of the local interface (default: listen on all interfaces) |
| port | client: name of the remote port
server: name of the local port |
| myhost | client: name of the local interface |
| myport | client: name of the local port |
- Attention:
- named ports are supported as well
type: string,
get: ConfigGetIoUds ,
set: ConfigSetIoUds pidfile
Use a uds (http://en.wikipedia.org/wiki/Unix_domain_socket) socket link. The uds communication is usually 50% faster than a local tcp communication but only available on UNIX.
- Parameters:
-
| [in] | file | the name of the uds file |
type: integer,
get: ConfigGetIoPipe ,
set: ConfigSetIoPipe socket
Start a pipe server to listen on socket. This is the default mode to start a server. The socket option is special because it is used for internal purpose to submit the socket from the client to the server started as pipe by the client.
- Parameters:
-
| [in] | socket | the file-descriptor number. The only public usage for this option is to serve as interface for an existing tool like (x)inetd. The (x)inetd tool is a UNIX service to listen on a tcp/ip port and start for every connection the proper entry from the file /etc/(x)inetd.conf with the file-descriptor 0 as send/recv socket handle. |
type: Command-Object,
get: ConfigGetMaster ,
set: SLAVE OBJECT
return the master if ctx is a slave-context or NULL if ctx is not a slave-context. !Only a SLAVE has a master!
type: int,
get: ConfigGetCtxId ,
set: NO
return an identifier as integer and is unique per parent-context. The parent-context is always 0 and every new child-context get a new identifier by adding 1.
type: string,
get: ConfigGetToken ,
set: NO
return the current TOKEN IDENTIFIER and is only useful in a service callback. This command is needed on the server to implement a generic service (A $ctx ServiceCreate token service with different TOKEN IDENTIFIER but with the same service callback).
type: boolean,
get: ConfigGetIsConnected ,
set: NO
Is the tclmsgque context connected ? A context is connected if the $ctx LinkCreate ... command was successful and a context is NOT connected if a) the object has just been created or b) the link was deleted with $ctx LinkDelete
type: boolean,
get: ConfigGetIsServer ,
set: IServerSetup or IServerCleanup
True if object is a server object (default: no, be a client)
type: boolean,
get: ConfigGetIsParent ,
set: NO
True if object is a parent object (default: yes, be a parent)
type: boolean,
get: ConfigGetIsSlave ,
set: NO
True if object is a slave object (default: no, not be a slave)
type: Interface,
get: NO ,
set: $ctx ConfigSetServerSetup callback
Interface to define a server tclmsgque object. This Interface define the ServerSetup callback called at $ctx LinkCreate ... to define the services or to initialize context specific variables. This interface set the isServer configuration value to yes.
type: Interface,
get: NO ,
set: $ctx ConfigSetServerCleanup callback
Interface to define a server tclmsgque object. This Interface define the ServerCleanup callback called at $ctx LinkDelete to free context specific variables. This interface set the isServer configuration value to yes.
type: Interface,
get: NO ,
set: $ctx ConfigSetFilterFTR callback
Interface required to define a filter data stream object. This Interface define the IFilterFTR callback. The callback is used to act on filter data rows. Every filter input data is a list of filter data rows and every row is a list of filter data columns. Every row is send from one filter-command to the following filter-command as FTR service request. This interface set the isServer configuration value to yes. (read more at: FILTER MODE)
type: Interface,
get: NO ,
set: $ctx ConfigSetFilterEOF callback
Interface required to define a filter data stream object. This Interface define the IFilterEOF callback. The callback is used to act on End-Of-Filter data and is called after all IFilterFTR data was send. Sometimes the filter data can not be served as IFilterFTR data (example: sorting of the input rows need to read all rows before the data can be send to the next filter command) and the IFilterEOF callback is used to continue send IFilterFTR data rows. This interface set the isServer configuration value to yes. (read more at: FILTER MODE)
type: Interface,
get: NO ,
set: $ctx ConfigSetFactory
The factory pattern is used to create a new application object (read more at: MqSetupS::Factory) Without the Factory pattern only the initial startup context is available to serve incoming requests. In general every server need to provide a Factory pattern.
type: Interface,
get: NO ,
set: $ctx ConfigSetBgError callback
Define an asyncrone error handler. This handler is used for handle errors send with $ctx SendERROR. Use [lindex $errorCode 1] or $ctx ErrorGetNum and [lindex $errorCode 3] or $ctx ErrorGetText to access the error.
To create and to destroy a link is the main purpose of the tclmsgque library. A link is a client/server connection used to perform various tasks.
Create a
parent-context using the
OBJECT CONFIGURATION. A parent-context is responsible to setup the client/server link:
- the client-parent-context create the server-parent-context
- the server-parent-context wait for a client-parent-context connection request
- Parameters:
-
- Attention:
- if the first argument after the "@" item is the string "SELF" an independent server of the current server is started. This is not a SLAVE OBJECT. The "SELF" argument is replaced by an application default setting (if available) or by arguments set with static: tclmsgque Init ...args.
Create a
child-context from a tclmsgque
parent-context and command-line arguments. A child is using the same process or thread as the parent but a different namespace. With a different namespace a child is able to act on different services on the shared server.
- Parameters:
-
| [in] | ctx | the object from OBJECT CREATION AND DELETION |
| [in] | parent | the parent object |
| [in] | args | all command-line arguments including the "@" token |
Close the client/server link and delete the underlying communication object. All depending objects will be deleted as well like depending
child-context and
slave-context local and on the remote site of the link.
Shutdown the entire communication and exit the current process or thread.
To provide a
service is the main purpose of a server. The
$ctx ServiceCreate token service method is usually added in the
ServerSetup method of the
IServerSetup.
proc ServerSetup {ctx} {
$ctx ServiceCreate "SRV1" serviceF
}
The
token is a 4 byte string and identifies the service. The
token is used in:
A service is using a callback to act on an incoming service request. The callback is used on a
server using
$ctx ServiceCreate token service or on a
client using
$ctx SendEND_AND_CALLBACK token callback.
The callback is implemented as TCL procedure using Service {ctx}
Create a new service listen on
TOKEN IDENTIFIER and start for every incoming request a
service. (on error return an
EXCEPTION OBJECT)
Delete a new service listen on
TOKEN IDENTIFIER . (on error return an
EXCEPTION OBJECT)
Start the Event-Loop and check for the next event. In
client mode this command is usually used together with
$ctx SendEND_AND_CALLBACK token callback to process the results.
- Parameters:
-
| [in] | timeout | don't wait more than TIMEOUT seconds to get an answer from the server. If no answer is available an error is raised. (default: command-line: --timeout) |
| [in] | MqC.WAIT | use flag value to define the action (default: NO)
- NO, don't wait for an event do just the check
- ONCE, use timeout seconds to wait for exact one event
- FOREVER, wait forever and only come back on error or on exit
|
The
Send style methods are used to build and send data using the tclmsgque send data package. The data is typed using the
TYPE IDENTIFIER and the methods can wait or not for an answer. During waiting the the application is still able to work on events like other tclmsgque client/server links.
$ctx SendSTART
$ctx SendI $num
$ctx SendL_START
$ctx SendD $balance
$ctx SendC "name of the owner"
$ctx SendB $signature
$ctx SendL_END
$ctx SendEND_AND_WAIT "SRV1"
Initialize a tclmsgque send data package. This method is required.
Send the package using
TOKEN IDENTIFIER without expecting an answer (FireAndForget). (on error return an
EXCEPTION OBJECT)
- Attention:
- if an error is raised on the server during service-processing the error is send back as asynchronous event and can be raised sometime in the future. To be sure to get the error immediately use $ctx SendEND_AND_WAIT token ?timeout=MQ_TIMEOUT_USER?
Send the package using
TOKEN IDENTIFIER and wait
timeout seconds for an answer. (on error return an
EXCEPTION OBJECT)
Send the package using
TOKEN IDENTIFIER and
don't wait for an answer. The answer will be handled by the
SERVICE CALLBACK. (on error return an
EXCEPTION OBJECT)
Answer an incoming service-call started with
$ctx SendEND_AND_WAIT token ?timeout=MQ_TIMEOUT_USER? or
$ctx SendEND_AND_CALLBACK token callback. The return package is build-up like the previous service call package but with a $ctx SendRETURN as final command. (on error return an
EXCEPTION OBJECT)
Send an asyncrone error to the link target. (on error return an
EXCEPTION OBJECT)
Send a filter stream data package using
FILTER MODE. (on error return an
EXCEPTION OBJECT)
Send a filter end-of-file data package using
FILTER MODE. (on error return an
EXCEPTION OBJECT)
Add an item using
TYPE IDENTIFIER to the tclmsgque send data package. (example:
SendY)
Start to send an embedded list item.
Finish to send an embedded list item.
Read data from an incoming tclmsgque read data package:
- on a server to serve an incoming service-call from the client
- on a client to process the return-data from a previous service-call
Reading data is a passive task in opposite to sending data which is an active task. Passive mean that the read is triggered by an incoming data-package and not by the software-workflow.
set num [$ctx ReadI]
$ctx ReadL_START
set balance [$ctx ReadD]
set owner [$ctx ReadC]
set signature [$ctx ReadB]
$ctx ReadL_END
return an item using the
TYPE IDENTIFIER from the tclmsgque read data package. (on error return an
EXCEPTION OBJECT)
return a temporary
BUFFER OBJECT. (on error return an
EXCEPTION OBJECT)
- Attention:
- The object is only valid until a new tclmsgque read data package has arrived.
Link two tclmsgque objects to direct pass a data item from one object to the other. (on error return an
EXCEPTION OBJECT)
return the number of items left in the tclmsgque read data package.
Check if are still items in the tclmsgque read data package.
Undo the
last read operation. This is useful if an error was raised or if a buffer object (returned from
$ctx ReadU) has not the expected type. (on error return an
EXCEPTION OBJECT)
Start to read an embedded list item. Use the current read package (
buffer = NULL) or a
buffer object. (on error return an
EXCEPTION OBJECT)
Finish to read an embedded list item.
The master/slave link is used to create a mesh of nodes by linking different PARENT context objects together.
The master control the slave.
The link is used to perform the following tasks:
- report error messages from the slave to the master
- to create a slave-child-context if a master-child-context is created
- to delete a slave-context if a master-context is deleted
In difference to the client/server link the master/slave link connect two independent msgque-context in the same process or thread (e.g. node). This leads to the restriction that only the master-msgque-context can be a server because only one server per node is possible.
Create a worker as
slave of the
ctx object using the image of the
ctx object self and started as an independent process or thread based on the
command-line: --thread --spawn --fork argument.
- Parameters:
-
| [in] | ctx | the master tclmsgque object as SERVER-PARENT without a CHILD |
| [in] | id | an integer used as unique identifer for the master/slave link |
| [in] | args | command-line arguments passed to the worker-client or the worker-server. all arguments prior the first @ token are added to the worker-client and the other arguments to the worker-server. |
example create a worker with id 7 as thread.
$ctx SlaveWorker 7 "--thread" "--silent" "@" "WORKER" "--name" "MyWorker"
Create a master/slave link between the
ctx object and the
slave object. (on error return an
EXCEPTION OBJECT)
- Parameters:
-
| [in] | ctx | the master tclmsgque object as PARENT without a CHILD |
| [in] | id | an integer used as unique identifer for the master/slave link |
| [in] | slave | the slave tclmsgque object as CLIENT-PARENT without a CHILD |
Delete a
slave-context from a former
$ctx SlaveCreate id slave command using the same identifier
id. By default the
slave-context object will be deleted if the
master-context is deleted. In addition
only the
parent-slave-context can be deleted explicit. If
id is invalid nothing will happen. (on error return an
EXCEPTION OBJECT)
return the
slave-context from the
$ctx SlaveCreate id slave using the same identifier
id or
NULL if the
id is not valid or if
ctx is not a
master.
The
class MqBufferC object is created by
$ctx ReadU and id used to save a
typeless temporary data item from the tclmsgque data package. The lifetime of the
class MqBufferC is only the current callback up to the next read operation of the same context.
set buf [$ctx ReadU]
if {[$buf GetType] == 'C'} {
puts [$buf GetC]
}
A tclmsgque buffer data package is type safe, this mean that every item has a type prefix and every
$ctx Read[TYPE] or
$buffer Get[TYPE] have to match the previous
$ctx Send[TYPE] value with the same
TYPE. One exception, the cast from and to string (TYPE=C) is allowed. The following type identifier's are available:
Y : 1 byte signed characterO : 1 byte boolean character using yes for yes or true or no for no or wrongS : 2 byte signed shortI : 4 byte signed integerW : 8 byte signed long long integerF : 4 byte floatD : 8 byte doubleB : unsigned char array used for binary dataC : string data using a \0 at the endL : list type able to hold a list of all items from aboveU : typeless buffer able to hold a single item from above
return the data form the buffer using the
TYPE IDENTIFIER. (on error return an
EXCEPTION OBJECT)
return the type as single character of the item stored in the buffer object.
The exception object is used to transport a tclmsgque error using the
TCLMSGQUE errorCode.
if {[catch {
i = $ctx ReadI();
}]} {
$ctx ErrorSet
puts [$ctx ErrorGetText]
$ctx ErrorReset
}
return the error message from the error object.
return the error number from the error object. The number can be used as exit-code.
create a tclmsgque error object but do
not raise the
EXCEPTION OBJECT
convert a
TCLMSGQUE errorCode into a tclmsgque conform error using the
ctx object. This method is used to enable additional error processing capabilities from
$ctx LinkDelete or
$ctx Exit after the exception was caught and before the application exit or the object is deleted.
clear the tclmsgque error object.
convert and raise an tclmsgque error object into a TCL
EXCEPTION OBJECT.
print an tclmsgque error object to stderr and
clear the tclmsgque error
The CONTEXT LOCAL STORAGE is required to bind user data to the tclmsgque context
Add
data using
key into the local storage and return the
data afterwards.
return the
data associated with
key or nothing if
key does not exists.
return
yes if
key exists or
no if not.
Remove the
key and the associated
data from the local storage.
The filter mode is related to a special usage of the tclmsgque software called a command pipeline. A command pipeline is well known from the
unix shell to link different commands together to act like a single application:
command1 | command2 | command3
A command pipeline with tclmsgque queues is using the special token
@ to link the commands together:
msgcmd1 @ msgcmd2 @ msgcmd3
To create a tclmsgque filter use:
and to send data to the next filter command use:
The library was tested on Linux, FreeBSD and WindowsXP using a x86_64, ppc processor or i686 processor from the VritualBox emulator.
package require TclMsgque
proc MMUL {ctx} {
$ctx SendSTART
$ctx SendD [expr {[$ctx ReadD] * [$ctx ReadD]}]
$ctx SendRETURN
}
proc ServerConfig {ctx} {
$ctx ServiceCreate "MMUL" MMUL
}
tclmsgque Main {
set srv [tclmsgque MqS]
$srv ConfigSetName MyMulServer
$srv ConfigSetFactory
$srv ConfigSetServerSetup ServerConfig
if {[catch {
$srv LinkCreate {*}$argv
$srv ProcessEvent -wait FOREVER
}]} {
$srv ErrorSet
}
$srv Exit
}
Start
mulserver.tcl using
TCP port
7777 and create a
thread for every incoming connection
> tclsh mulserver.tcl --tcp --port 7777 --thread
package require TclMsgque
set ctx [tclmsgque MqS]
$ctx LinkCreate --name "MyMul" {*}$argv
$ctx SendSTART
$ctx SendD 3.67
$ctx SendD 22.3
$ctx SendEND_AND_WAIT "MMUL"
puts [$ctx ReadD]
$ctx Exit
Use
mulclient.tcl to connect to
mulserver.tcl using
TCP port
7777:
> tclsh mulclient.tcl --tcp --port 7777
package require TclMsgque
proc FTRcmd {ctx} {
$ctx SendSTART
while {[$ctx ReadItemExists]} {
$ctx SendC "<[$ctx ReadC]>"
}
$ctx SendFTR
}
set srv [tclmsgque MqS]
$srv ConfigSetName ManFilter
$srv ConfigSetFilterFTR FTRcmd
if {[catch {
$srv LinkCreate {*}$argv
$srv ProcessEvent -wait FOREVER
}]} {
$srv ErrorSet
}
$srv Exit
Use
manfilter.tcl in a LibMsgque command pipeline:
> echo -e "1:2:3\na:b:c" | atool split -d : @ tclsh manfilter.tcl @ atool join -d :
TCL, C: libmsgque(n), C++: ccmsgque(n), C#: csmsgque(n), JAVA: javamsgque(n), PYTHON: pymsgque(n), TCL: tclmsgque(n), PERL: perlmsgque(n)
TCL, unix, socket, message, msgque