Using Socket Devices

SOCKET devices are used to access and manipulate sockets. A SOCKET device can have unlimited associated sockets. The default limit is 64. Set the environment variable gtm_max_sockets to the number of maximum associated sockets sockets that you wish to set for a GT.M process. $VIEW("MAX_SOCKETS") returns the current value of the maximum number of associated sockets.

At any time, only one socket from the collection can be the current socket. If there is no current socket, an attempt to READ from, or WRITE to the device, generates an error.

Sockets can be attached and detached from the collection of sockets associated with a device. Detached sockets belong to a pseudo-device called the "socketpool". A process can detach a socket from a device and later attach it to the same device or another device.

[Caution] Caution

Currently, GT.M does not produce an error if a socket is attached to a device having a different CHSET.

[Note] Note

The GT.M socket device interface does not have the ability to pass sockets between related or unrelated processes. Currently error trapping operates on a device, rather than on a socket.

Message Management

From an application perspective, the transport layers used by a socket device are stream-oriented, with no provisions for implicit application messages. Therefore, the following are two common protocols used to segment application messages.

  1. One method is to use a, typically small, fixed length message containing the length of the next, variable length, message. In GT.M a simplistic writer might be:

    Write $Justify($Length(x),4),x

    A corresponding simplistic reader might be:

    read len#4,x#len

    The advantage of this approach is that the message content (the value of x in the code fragments above) can contain any character. The disadvantage is that detecting that the protocol has become desynchronized is a problem.

  2. The other common method is to place a delimiter between each application message. The protocol breaks if a message ever includes a delimiter as part of its content.

The SOCKET device provides a facility for recognizing delimiters because parsing messages for delimiters is cumbersome.

Socket Read Operation

TCP/IP is a stream-based protocol that guarantees that bytes arrive in the order in which they were sent. However, it does not guarantee that they will be grouped in the same packets.

If packets arrive infrequently, or at varying rates that are sometimes slow, a short interval can waste CPU cycles checking for an unlikely event. On the other hand, if the handling of packets is time critical, a long interval can introduce an undesirable latency. If packets arrive in a rapid and constant flow (an unusual situation), the interval doesn't matter as much, as there is always something in the buffer for the READ to work with. If you do not specify MOREREADTIME, SOCKET READ implements a dynamic approach of using a longer first interval of 200 ms when it finds no data, then shortening the interval to 10 ms when data starts to arrive. If you specify an interval, the SOCKET device always uses the specified interval and does not adjust dynamically. For more information on MOREREADTIME, refer to “MOREREADTIME”.

Most SOCKET READ operations terminate as a result of the first condition detected from (a) receipt of delimiters, (b) receipt of the maximum number of characters, or (c) expiration of a timeout. Note that all of these conditions are optional, and a specific READ may specify zero or more of them. This section refers to these three conditions as "defined terminating conditions". If a SOCKET READ is not subject to any of the defined terminating conditions, it terminates after it has received at least one character followed by an interval with no new characters. An error can also terminate a READ. While none of the terminating conditions is satisfied, the READ continues.

The following flowchart represents the logic of a SOCKET READ.

Socket Read Termination Conditions

A SOCKET READ operation terminates if any of the following conditions are met:

Terminating Conditions

Argument Contains

$Device

$Key

$Test

Error

Empty String

Error String

Empty String

1

Timeout*

Data received before timeout

Empty String

Empty String

0

Delimiter*

Data up to, but not including the delimiter

Empty String

Delimiter String

1

Fixed Length Met*

String of Fixed Length

Empty String

Empty String

1

Width

Full width String

Empty String

Empty String

1

Buffer Emptied

One (1) to as many characters as provided by the transport interface before waiting for an interval (in milliseconds) specified by MOREREADTIME with no additional input. If MOREREADTIME is not specified, buffer is checked every 200 milliseconds for its first input and then every 10 milliseconds until no new input arrives and no other terminating conditions are met.

IF MOREREADTIME is specified, READ uses that value exclusively for buffer checks.

Empty String

Empty String

1

* denotes Defined Terminating Conditions

A non-fixed-length read, with no timeout and no delimiters (the sixth row in the above table) requires a complex implementation of sequence of READs to ensure a predictable result. This is because the transport layer stream fragments delivered to the reader has only accidental correspondence with the operations performed by the writer. For example, the following:

Write "Message 1","Message 2" is presented to the reader as the stream "Message1Message2" but it can take from one (1) to 18 READ commands to retrieve the entire stream.

Messaging protocol should implement READ in any of the following ways:

  1. Use a delimiter to separate messages (generic READ and possibly a larger value for MOREREADTIME).

  2. Specify messages as <length, value> pairs (a pair of fixed-length READs (READ # ) and possibly a larger value for MOREREADTIME).

  3. Parse the bytes or characters as they come in (possibly a smaller value for MOREADTIME)

Message Delimiters

Each device can have from zero (0) to 64 delimiters associated with it. Each delimiter can be from one (1) to 64 characters. All the delimiters declared for a device are valid for any READ from any associated socket, which means, any of the defined delimiters terminate the READ. The actual terminating delimiter is available in $KEY. A WRITE to a socket associated with a device with one or more delimiters inserts the first of the delimiters for any WRITE ! format.

Read Command

The READ command may be used to obtain data from a socket. A READ operation terminates if any of the following are detected, in the order specified below:

Terminating
Condition

Argument Contains

$Device

$Key (Continued)

Error

Empty string

Error string

Empty string

Timeout

Data received before timeout

Empty string

Empty string

Delimiter

Data up to, but not including the delimiter

Empty string

Delimiter string

Fixed length met

String of fixed length

Empty string

Empty string

Buffer emptied

One (1) to as many characters as happen to be provided by the transport interface

Empty string

Empty string

A non-fixed-length read, with no timeout and no delimiters requires a complex implementation of sequence of READs to ensure a predictable result. This is because the transport layer stream fragments delivered to the reader has only accidental correspondence with the operations performed by the writer. For example, the following

Write "Message 1","Message 2"

is presented to the reader as the stream "Message1Message2" but it can take from one (1) to 18 READ commands to retrieve the entire stream.

WRITE Command

The WRITE command sends data to a socket.

The WRITE command for SOCKET devices accepts the following controlmnemonics:

/L[ISTEN][(numexpr)]

where numexpr is in the range 1-5 and specifies the listen queue depth for a listening socket. By default, an OPEN or USE with LISTEN immediately sets the listen queue size to 1.

/W[AIT][(timeout)]

where timeout is a "numexpr" that specifies how long in seconds a server waits for a connection or data to become available on one of the sockets in the current Socket Device.

"WRITE !" inserts the character(s) of the first I/O delimiter (if any) to the sending buffer. If "ZFF=expr" has been specified, "WRITE #" inserts the characters of expr . Otherwise WRITE # has no effect. WRITE ! and WRITE # always maintain $X and $Y in a fashion that emulates a terminal cursor position except when the device is OPENed with a UTF CHSET because the units for $X and $Y for terminals are in display columns while for sockets they are in codepoints.

Socket Device Operation

Each socket may be in one of the following states:Each socket may be in one of the following states (observable through $KEY):

  • CREATE–indicates that the socket exists.

  • ESTABLISHED–After a successful OPEN or USE with the CONNECT device parameter or when GT.M was started with a socket as the $PRINCIPAL device.

  • LISTENING–indicates that the OPEN or USE with the LISTEN deviceparameter was successful and a listen queue was established.

A listening socket used for accepting new connections goes through these three states in one step with a single OPEN or USE. When a server does a WRITE /WAIT, a client can establish a connection which creates a new server socket. $KEY includes information about this new socket in the form of CONNECT|handle|<address> where <address> is the IP address for TCP sockets and path for LOCAL sockets.

Each socket may have one or more sockets waiting for either an incoming connection or data available to READ (observable through $ZKEY). $ZKEY contains semi-colon (";") separated list of entries detailing any waiting sockets for a current SOCKET device.

For more information on $KEY and $ZKEY, refer to Chapter 8: “Intrinsic Special Variables.

Socket Deviceparameter Summary

The following table provides a brief summary of deviceparameters for socket devices. For more information, refer to “Open”, “Use”, and “Close”.

Error Processing Deviceparameters

DEVICEPARAMETER

COMMAND

COMMENT

EXCEPTION=expr

O/U/C

Controls device-specific error handling.

IOERROR=expr

O/U

If $LENGTH(expr)&("Tt"[$EXTRACT(expr)) then Error Trapping is enabled; otherwise the application must check $DEVICE for errors.

Format Deviceparameters

DEVICEPARAMETER

COMMAND

COMMENT

[NO]DELIMITER=expr

O/U

Specifies socket delimiter(s).

[NO]FILTER=expr

U

Specifies character filtering for socket output.

LENGTH=expr, or

ZLENGTH=expr

U

Sets virtual page length for socket device.

ICHSET=expr

O/U/C

Specifies input character set

OCHSET=expr

O/U/C

Specifies output character set

[Z][NO]WRAP

O/U

Controls handling of records longer than the device width.

[Z]WIDTH=expr

U

Controls the maximum length of an output message.

Z[NO]FF=expr

O/U

Controls whether and what characters to send in response to a WRITE #.

Socket Establishment/Disconnect Deviceparameters

DEVICEPARAMETER

COMMAND

COMMENT

CONNECT=expr

O/U

expr specifies protocol, and protocol specific information

LISTEN=expr

O/U

Similar to CONNECT but binds the socket for subsequent /LISTEN and /WAIT

Socket Device Examples

sockexamplemulti3.m demonstrates a use of $KEY and $ZKEY in a basic socket I/O setup. It launches two jobs: a server process which opens a listening socket and a client process which makes five connections to the server. The server sends a message to each connection socket. Even-numbered client sockets read the message partially but do not send a response back to the server. Odd-numbered client sockets receive the full message and respond to the server with the message "Ok.". The server reads two characters (but the client sends three) and $ZKEY shows sockets with unread characters.Please click Download sockexamplemulti3.m to download the sockexamplemulti3.m program and follow instructions in the comments near the top of the program file. You can also download sockexamplemulti3.m from http://tinco.pair.com/bhaskar/gtm/doc/books/pg/UNIX_manual/sockexamplemulti3.m.

You can start a GT.M process in response to a connection request made using inetd/xinetd. The following example uses inetd/xinetd to implement a listener which responds to connections and messages just as the prior example.

In the configuration file for xinetd, define a new service called gtmserver. Set socket_type to "stream" and wait should be "no" as in the following snippet:

service gtmserver 
{ 
disable = no 
type = UNLISTED 
port = 7777 
socket_type = stream 
wait = no 
user = gtmuser 
server = /path/to/startgtm 
} 

If you define the server in /etc/services, the type and port options are not needed. For more information, the xinetd.conf man page for more details.

If you are using inetd, a line should be added to /etc/inetd.conf with the sockettype "stream", protocol "tcp", and the "nowait" flag should be specified as in the example below, which assumes a gtmserver service is defined in /etc/services:

gtmserver stream tcp nowait gtmuser /path/to/startgtm 

In both of the above examples, "gtmuser" is the name of the user the service gtmserver should be run as, and "/path/to/startgtm" is the name of a script which defines some environment variables needed by GT.M before starting it. Please check the man page for inetd.conf on your system since the details may be slightly different.

The minimum variables are $gtm_dist which should specify the directory containing the GT.M distribution and $gtmroutines. As an example:

#!/bin/bash 
cd /path/to/workarea 
export gtm_dist=/usr/local/gtm 
export gtmroutines="/var/myApp/o(/var/myApp/r) $gtm_dist" 
export gtmgbldir=/var/myApp/g/mumps.dat 
$gtm_dist/mumps -r start^server 

When start^server begins, the $PRINCIPAL device will already be connected and $KEY will contain "ESTABLISHED|socket_handle|remote_ip_address". In most cases, a USE should be executed to set various device parameters such as delimiters.

The ZSHOW "D" command provides both the local and remote addresses and ports:

0 OPEN SOCKET TOTAL=1 CURRENT=0 
SOCKET[0]=h11135182870 DESC=0 CONNECTED ACTIVE NOTRAP 
REMOTE=10.1.2.3@53731 LOCAL=10.2.3.4@7777 
ZDELAY ZIBFSIZE=1024 ZIBFSIZE=0