This chapter explains how the client/server binding works and then describes how to connect your user programs to the generic client/server modules.
If you want to use the client/server binding with a Dialog System application, please see the chapter Using the Client/Server Binding in the online book, Dialog System User Guide as this includes code examples which are specific to Dialog System.
The client/server binding is a simple, light-weight, Remote Procedure Call (RPC) mechanism, for use with 25 clients or less, that enables you to implement a client/server architecture without having to worry about communications programming. The AAI (Application to Application Interface) component of the client/server binding is provided for users wanting to migrate applications that require more than 25 clients.
The client/server binding is included as part of NetExpress for use in applications which do not require an extensive, fault tolerant middleware solution. The AAI client component is included with NetExpress for migration to a more comprehensive middleware product for applications requiring fault tolerance, rollback and recovery options. You may want to consider programming directly to the AAI interface before starting your development project. More information regarding this API is available in the AAI Server component. The AAI Server components are sold separately. Please contact your Sales Representative for more information.
You should ensure that the capabilities and performance provided by the client/server binding are adequate for your business needs. For many applications, this is the case and the client/server binding offers a solution which is both easy to implement and extremely cost-effective to deploy.
The client/server binding removes the requirement for you to include communications code in your application by providing two modules called mfclient and mfserver. These are generic modules which can be used to drive any application.
Based on information contained in a configuration file, these modules manage the communications link and the transfer of data and are able to interact with user-defined programs at each end of the link. The mfclient module is called by a user-written client program (which may, for example, handle the user interface) while mfserver calls a user-written server program (which may, for example, handle data access and business logic).
The user-written client and server programs use the copyfile mfclisrv.cpy to interact with the generic client/server modules.
Supplied with NetExpress is an example application which demonstrates how the client/server binding can be used. This example application, which transfers file data between a client and a server, is installed in the sub-directory Csbind in your NetExpress \demo directory.
The client/server binding works by having a nondedicated copy of mfserver running on the server tier; this copy of mfserver communicates with any and all clients using an agreed server name. The mfserver module can be run using its built-in defaults, as its only function is to receive requests from the client to establish or terminate a connection.
The flow of information is explained below (the program files from the demonstration application Csbind are used as example client and server programs):
This read record/write record loop continues until the user-written client program (netxcli.cbl) reaches end-of-file, at which point it closes the file and sends an indication that it is about to terminate to the server. The server responds by sending the name of the directory into which the file was copied.
To use the client/server binding in your application, you need to:
Each of these steps is explained in more detail below.
The mfclient and mfserver modules pass information to each other via the parameter block, LNK-PARAM-BLOCK, defined in the copyfile mfclisrv.cpy. The modules also use this parameter block to pass information to any user programs they have been requested to call. The mfclisrv.cpy copyfile must be included in any of your COBOL programs which use the mfclient and mfserver modules.
The mfclisrv.cpy copyfile is installed in the SOURCE directory of your NetExpress base installation directory.
The client/server binding configuration file controls the behaviour of the mfclient and mfserver modules as well as the communications link.
The client/server binding configuration file is an ASCII text file which must have a .cfg extension. If you do not supply a configuration filename yourself, the default configuration filename, mfclisrv.cfg is used.
You can have separate configuration files for each application or you can supply multiple entries in a single file. If you are using multiple entries, each application must have its own tag entered in the file, followed by the list of parameters for that application. You must then specify this tag-name in your client program using the LNK-TAGNAME field in the LNK-PARAM-BLOCK parameter block. This technique can be used to reduce your command line length by specifying your multiple entries in the default configuration file, mfclisrv.cfg.
If your client/server application is incorrectly set up, any invalid entries found in the configuration file will cause the programs reading them to terminate with a message displayed on the screen detailing the invalid entries.
These errors are also logged in the mfclisrv.log file, which is created in the current directory, or in the directory indicated by the MFLOGDIR environment variable. This enables a server which is not directly connected to a terminal to log messages.
Listed below are all of the possible entries for the mfclisrv.cfg configuration file. Entries are listed in alphabetical order. Any entries which you do not specify in your configuration file assume the default values.
|aaiservice=name||PIC X(128) [default: MFCLISRV]
Name of the AAI Service to connect to. This is the logical service name entry in the AAI administration system.
|cblksize=nnnn||PIC X(4) COMP-X [default: 0]
Size of Dialog System control block. For use with Dialog System only.
|clierrprog=name||PIC X(128) [default: none]
Name of the program which will handle communication errors instead of mfclient. You can enter a name of SAME to use the calling program to handle any mfclient errors.
|commsapi=api||PIC X(4) [default: CCI]
The communications API; valid values are CCI, AAI or NONE. The special entry NONE can be used when developing two tier applications to allow testing to be undertaken on a single PC without any communications products. Data is passed directly between mfclient and the user-written server program, bypassing mfserver and the communications requirement.
Note: You cannot use this option if an existing application is being deployed as the user-written server program.
|compress=nnn||PIC 9(3) [default: 000]
The number of the compression routine to be used, for example, 001 indicates that routine CBLDC001 will be used. Setting this parameter to 0 indicates that data compression will not be used.
|dblksize=nnnn||PIC X(4) COMP-X [default: 0]
The size of the user data area used to pass data between the user-written client and server programs. For Dialog System applications this will be the size of the Dialog System datablock.
Warning: Unpredictable results can occur if this entry is less than the actual size of the data area being used.
|eblksize=nnnn||PIC X(4) COMP-X [default: 0]
The size of the optional Dialog System Event block.
The name of the machine on which the server specified in the servername entry is located. This prevents the system searching for the first match of the defined name.
|maxtrans=nn||PIC 99 [default: 0]
The maximum transfer package size in Kilobytes. Valid values are 1 - 62. If the total buffer size exceeds this amount, the system will make multiple transfers of maxtrans size until the total buffer is transferred.
|midconfig=filename||PIC X(128) [default: none]
The name of the configuration file to be used by mfclient when called by mfserver as part of a cross-tier solution. Specifying this entry causes mfserver to act as a router passing data to a local mfclient module. This mfclient module uses this configuration file to locate and communicate with another server. This allows protocols and communications APIs to be changed across the machines used.
|protocol=protocol||PIC X(8) [default: CCITC32]
The CCI protocol to be used. This entry is only applicable if commsapi is set to CCI. You can specify any of the supported CCI protocols: Novell IPX (enter CCIIX32), NetBEUI (enter CCINB32), Dynamic Data Exchange (enter CCIDE32) or TCP/IP (enter CCITC32). Note that if commsapi is set to CCI (which is the default) and you do not specify a protocol, the client/server binding defaults to TCP/IP (CCITC32).
|scrntype=type||PIC X(4) [default: none]
If, for example, the user program supports both GUI and character interfaces this entry can be used as an indicator to tell the client program which type of interface is being used. scrntype is not validated by the client/server binding modules.
|servername=server||PIC X(14) [default: MFCLISRV]
The servername to be used for communications.
|setenv=name value||PIC X(148) [default: none]
Environment variable to be set on the server before the execution of any server programs. The format is:
variable name PIC X(20)
variable value PIC X(128)
The name and value fields must be separated by at least one space character. Up to nine setenv entries can be specified.
|srvanim=x||PIC X(16) [default: N]
Y or N. Setting this parameter to Y enables animation of the user programs running on the server. This means that mfserver does not have to be stopped and restarted with COBSW=+A as this is set up dynamically.
On UNIX systems only, you can specify a value of x,filename to enable cross-session animation of your programs. See the section Animating your Applications for more details.
|srverrprog=name||PIC X(128) [default: none]
Name of the program which will handle communication errors instead of mfserver. You can enter a name of SAME to use the name set in the srvprog entry for mfserver errors.
Name of the user-written program to be called by mfserver.
|srvtier=name||PIC X(128) [default: mfserver]
The name of the server tier program. When specified, it indicates that mfserver will be called by this program.
|subserver=base-name||PIC X(14) [default: none]
The base-name to be used for communicating with sub-server processes. The default server-name is mfclisrv and sub-servers are named mfclisrv00001,mfclisrv00002 and so on. Setting this parameter to newserv results in sub-server names of newserv00001, newserv00002 and so on. This enables application-specific sub-server names to be used without changing the base server name.
|timeout=nnnn||PIC X(4) COMP-5 [default: 120 secs)
You can use this parameter to override the system timeout default. The timeout period is specified in 1/10 (tenths) of a second. Previously issued calls retain the timeout period that was in use when they were originally invoked.
|ublksize=nnnn||PIC X(4) COMP-X [default: 0]
Size of optional user data block.
|useraudit=x||PIC X [default: N]
Y or N. Setting this parameter to Y results in the logging of client connect and disconnect details. When set, the following details are logged by both client and server: date, time, connect/disconnect indicator, servername, machinename, and protocol. These details are written to the system log file, see Creating Audit Trails and System Log File below.
The minimum entries required in the configuration file varies according to:
You must always have the following entries:
|dblksize||The size of the user data area used for data transfer|
|srvprog||The name of the program that mfserver calls to perform the server-side processing. This is the user program on the server machine (that is,the COBOL program performing data access and business logic).|
When running multiple servers, you must supply the name of the server to be used via the servername entry.
If you are not using CCI, you must set the commsapi entry and if you are using CCI, but not TCP/IP, you must set the protocol entry.
Any configuration file entries which are unset assume the specified default values.
Your configuration file can be located where it best suits you. The mfclient and mfserver programs attempt to locate the configuration file as follows:
In each case a full pathname of up to 128 characters can be used to identify the location of the configuration file.
The mfclient and mfserver modules pass information to
each other via a parameter block described in the mfclisrv.cpy
copyfile. The modules use the same parameter block,
to pass information to user programs.
You must add code to your program, as in the example below, to enable it to pass parameters to mfclient.
$SET ANS85 WORKING-STORAGE SECTION. ...... *--- mfclisrv.cpy must be included in the working storage *--- section of the client program and in the linkage *--- section of the server program. COPY "MFCLISRV.CPY". LINKAGE SECTION. ...... *--- Input-Rec is the area used for transfering data *--- between the user client and the server programs. *--- The size of this data area is defined by the user *--- in the Client/Server Binding configuration file *--- which is read by the mfclient module. mfclient *--- sets up the required memory for this area and *--- returns a pointer to this area back to the user *--- client program (see below). 01 INPUT-REC PIC X(32767) PROCEDURE DIVISION. CLIENT-CONTROL SECTION. PERFORM UNTIL END-CONNECTION *--- lnk-client holds the name "mfclient". *--- The first time through we initialize mfclient and establish *--- contact with the server. CALL LNK-CLIENT USING LNK-PARAM-BLOCK EVALUATE TRUE *--- Make the user data area (Input-Rec) accessible by assigning *--- the address returned by mfclient. WHEN START-CONNECTION SET ADDRESS OF INPUT-REC TO LNK-DBLOCK-PTR WHEN END-CONNECTION EXIT PERFORM WHEN OTHER *--- Perform your application client logic. For example, display *--- and accept user interface data. ...... END-EVALUATE *--- Set a user defined flag (eg. EXIT-FLG-TRUE) to indicate *--- that client processing has terminated. For example, you *--- may have clicked on the EXIT push button on your application *--- interface. IF EXIT-FLG-TRUE SET CLIENT-ENDING TO TRUE END-IF END-PERFORM. CLIENT-CONTROL-END. STOP RUN.
If you want to control the number of clients running an application, or you choose to handle error message displays yourself, you will need to add code similar to the following to your program's initial EVALUATE statement:
WHEN TOO-MANY-CLIENTS PERFORM OVER-CLIENT-LIMIT WHEN COMMS-ERROR PERFORM SHOW-ERROR ...... OVER-CLIENT-LIMIT SECTION. DISPLAY SPACES AT 0101 WITH BACKGROUND-COLOR 7 "MAXIMUM NUMBER OF CLIENTS EXCEEDED - SESSION ENDED" AT 1012 WITH FOREGROUND-COLOR 4 SET EXIT-FLG-TRUE SET CLIENT-ENDING TO TRUE EXIT. SHOW-ERROR SECTION. DISPLAY LNK-ERROR-LOC AT 2201 DISPLAY LNK-ERROR-MSG AT 2301 WITH SIZE LNK-ERROR-MSG-LEN. EXIT.
If asynchronous requests are to be handled, you must add to the EVALUATE statement additional code similar to the following:
Note: ASYNC-REQUEST is not necessary if you are using AAI.
WHEN START-CONNECTION PERFORM GET-USER-INPUT IF MAKE-ASYNC-REQUEST <* user asynchronous option SET ASYNC-REQUEST TO TRUE END-IF WHEN ASYNC-OK SET TEST-ASYNC-RESULT TO TRUE PERFORM DELAY-LOOP WHEN ASYNC-INCOMPLETE DISPLAY "REQUEST STILL BEING PROCESSED" AT 1010 PERFORM DELAY-LOOP SET TEST-ASYNC-RESULT TO TRUE WHEN RESULT-OK DISPLAY "REQUEST-COMPLETED " AT 1010 PERFORM GET-USER-INPUT WHEN ASYNC-NOT-STARTED WHEN ASYNC-FAILED DISPLAY "ASYNCHRONOUS REQUEST FAILURE " AT 1010 PERFORM SHOW-ERROR PERFORM GET-USER-INPUT WHEN COMMS-ERROR PERFORM SHOW-ERROR
The mfclient and mfserver modules pass information to each other via a parameter block described in the mfclisrv.cpy copyfile. The modules use the same parameter block to pass information to any user programs.
Your server program must include the copyfile, mfclisrv.cpy in
the Linkage Section. You must also modify the Procedure Division header to
include the parameter block,
LNK-PARAM-BLOCK, which is used
to pass parameters from mfserver.
This is shown below in the example server code:
LINKAGE SECTION. 01 INPUT-REC PIC X(32767). COPY "MFCLISRV.CPY".*--- lnk-param-block is the record definition in mfclisrv.cpy PROCEDURE DIVISION USING LNK-PARAM-BLOCK. CONTROLLING SECTION. *---------------------------------------------------------------* * associate the user data area with the pointer in * lnk-parm-block. *---------------------------------------------------------------* SET ADDRESS OF INPUT-AREA TO LNK-DBLOCK-PTR. EVALUATE TRUE WHEN START-CONNECTION PERFORM PROGRAM-INITIALIZE WHEN OTHER PERFORM PROGRAM-BODY END-EVALUATE. EXIT PROGRAM. PROGRAM-INITIALIZE SECTION. *--- This code would include the initialization code *--- for your server program eg. opening your application *--- data files. ...... PROGRAM-BODY SECTION. *--- This section would include your application *--- processing code eg. read and writing of data *--- files. ......
If you choose to handle error message displays yourself, you will need to add code similar to the following to your program's initial EVALUATE statement:
WHEN COMMS-ERROR PERFORM SHOW-ERROR ...... SHOW-ERROR SECTION. DISPLAY LNK-ERROR-LOC AT 2201 DISPLAY LNK-ERROR-MSG AT 2301 WITH SIZE LNK-ERROR-MSG-LEN. EXIT.
The mfserver module is provided in .int code format so that it can be run as it is or generated into .gnt code.
If you have a UNIX system running Micro Focus COBOL 3.2 or later, you can move the .int module to your UNIX system and link it with other programs to create an executable module.
The mfclient and mfserver modules are run as standard COBOL programs, with both the client and server components started manually.
To run the client/server binding:
The command line to start the server program on UNIX is:
cobrun mfserver [-b] [-p protocol] [-s server-name] [-v]
and on Windows:
run mfserver [-b] [-p protocol] [-s server-name] [-v]
|-b||Allows you to run the server as a background process. On UNIX systems, the command line should be terminated with the '&' character. Any error messages produced by the server will be stored in the log file (mfclisrv.log).|
|-p protocol||Specifies the communications protocol.|
|-s server-name||Indicates a server-name other than the default (mfclisrv).|
|-v||Displays the mfserver version number.|
The command line to start the client program is:
run program-name [config-filename]
|program-name||Specifies the name of the user interface program.|
|config-filename||Specifies the name of the configuration file to be used.|
You can animate your client program using the standard animation facilities of NetExpress.
You can animate your server program by setting a configuration file parameter, srvanim=y (see Configuration File Parameters).
On PC servers, the Animator is started automatically when a client connects to the server if srvanim=y is set.
On UNIX servers, the Animator is run on the terminal from which mfserver was started and so requires mfserver to be running in foreground mode. This can cause problems as it is preferable to run mfserver as a background process. A further restriction is that only one user can animate through mfserver at any one time. These problems can be avoided by setting srvanim=x,filename where filename is a file created using the touch command. On the terminal that you want to use to display Animator output, set COBANIM_2=animator and then run the command anim filename. On the terminal that you want to use for your standard input and output, run your application in the normal way, having added srvanim=x,filename to your configuration file.
If you are using the CCI communications API, the behaviour of the server can be altered by running the program mfcsmgr and passing it the required parameters and values. These parameters can be divided into two groups: location and action. The parameters in the location group allow you to locate the target server, and can have settings m, p, and s. The action parameters control how the target server will be affected and can have settings a, c, o, r and t. Certain action parameters cannot be specified in combination with any other, these are o, r and t.
If you are using the AAI communications API, the behaviour of the server is controlled via the AAI administration system. The mfcsmgr program has no effect on applications running under AAI control.
The spawned servers are terminated by the client program when the client makes a normal exit. If you are using the CCI communications API, the initial server program does not terminate when its clients terminate, so if you want to shut down this server you must do so manually. If you are using the AAI communications API, the initial server program is terminated automatically following termination of the client.
To prevent accidental shutdown of an active server when you are using the CCI communications API, it is possible to assign a password to each server. This password must be supplied before the server can be stopped or its parameters changed.
The default number of clients the server can support using the CCI communications API is 25, but you can set a lower limit using one of the mfcsmgr functions. The number you select is stored in the password file and will be used each time the server is started.
The server can support override options for the server-name, protocol, and machine-name. As the server does not use a configuration file the override parameters are supplied using the mfcsmgr program. This generates a short exchange between the client and the server which processes the selected function. This override capability is provided for the CCI communications API only. Applications using the AAI communications API use the AAI administration system to control server options.
The command line syntax for mfcsmgr is:
run mfcsmgr [-a] [-c nnnnn] [-d] [-i filename][- m machine-name] [-p protocol] [-s server-name] [-o m, machine-name] [-o p, protocol] [-o r] [-o s, server-name] [-t] [-v]
cobrun mfcsmgr [-a] [-c nnnnn] [-d] [-i filename] [- m machine-name] [-p protocol] [-s server-name] [-o m, machine-name] [-o p, protocol] [-o r] [-o s, server-name] [-t] [-v]
|-a||Changes the authorisation password associated with the target server.|
|-c,nnnnn||Sets the number of clients the server can support.|
|-d||Deletes the local overide file (mfcsovrd.cfg) when the client exits.|
|-i filename||Installs the specified file in the client's local directory when the client exits.|
|-m machine-name||Specifies the name of the machine on which the target server is running. This is required if the same server-name is used on more than one platform.|
|-p protocol||Specifies the communications protocol being used: TCP/IP (CCITC32), NetBEUI (CCINB32), Novell IPX (CCIIX32) or Dynamic Data Exchange (CCIDE32).|
|-s server-name||Indicates a server-name other than the default (mfclisrv).|
|-o m,machine-name||Specifies the machine-name on which the overriding is running.|
|-o p,protocol||Uses this protocol to access the overriding server.|
|-o r||Resets active override. Reverts to original settings.|
|-o s,server-name||Overrides connections to the target server by directing them to this server.|
|-t||Terminates the server|
|-v||Displays the mfclient version number.|
All the above flags can be specified with a - or /, and are not case-sensitive.
Both mfclient and mfserver maintain a log of errors and messages. All entries are date- and time-stamped and are kept in a file called mfclisrv.log which is stored in the directory in which the programs were started or in the directory named in the MFLOGDIR environment variable. Check this log from time to time to ensure that your system is performing correctly.
You can create an audit trail of dates and times that clients connected to servers. To enable this feature, simply set useraudit=y in your configuration file.
This information is created in the system log file described above.
During the start-up process for each client, once the configuration file has been read, the client/server binding searches for a file called mfcsovrd.cfg. It searches for this file in the system log file directory. If the file is found, its contents are used to override any parameters previously set up using the configuration file. The format of the override file is identical to that of the standard configuration file with the exception of a single additional entry, override-cntrl. This entry is used to indicate the subject of the override which may be a server-name or a tag-name. If a server-name is specified, any clients using that server have their parameters modified by the contents of the override file. If a tag-name is specified, only those clients using the specified tag-name have their parameters altered.
The client override facility can be used, for example, if a server is unavailable and applications need to be run on another machine. You could of course change the individual configuration files, but a single override file can be used to re-route any number of applications.
The override facility can also be used on the server, but in this case the server machine needs to be up and running. As before, either server-names or tag-names can be overridden.
An entry is added to the log file whenever an override file is detected, and all parameters which are subject to the override process are logged.
The following example shows how the override facility can be used to re-route clients to another server:
[override-cntrl] override=servername [oldserver] servername=newserver
In this example the [override-cntrl] section specifies that the subject of the override is a server-name (override=servername) and then, under the the old server-name ([oldserver]), the new server-name (servername=newserver) is specified. This would result in the following log file entries:
20/04/1998 11:01:02 Using Local File: mfcsovrd.cfg Overriding Entries for Servername:OLDSERVER servername=newserver 20/04/1998 11:01:02 Override Completed:
The following example shows how the override facility can be used to override the server being used by all those clients which are using a specified tag:
[override-cntrl] override=tagname [mf-clisrv] servername=newserv
In this example the [override-cntrl] section specifies that the subject of the override is a tag-name (override=tagname) and then, under the tag-name ([mf-clisrv]), the parameter to be overridden (in this case the server-name) is specified (servername=newserv). This would result in the following log file entries:
20/04/1998 11:04:02 Using Local File: mfcsovrd.cfg Overriding Entries for Tagname:MF-CLISRV servername=newserv 20/04/1998 11:04:02 Override Completed:
If you wish to use the callout facility of Dialog System with the Client/Server Binding, you have to make a small change to your user client program, and create programs to service the callout request at either end of the connection. You need to add two lines and a directive to your user client program, as follows-:
At the start of the program:
$set ans85 linkcount(128)
01 lnk-param-block-addr POINTER EXTERNAL.
In the PROCEDURE DIVISION:
SET lnk-param-block-addr TO ADDRESS OF lnk-param-block
The reason for this is so that the program called by dialog to handle the callout request has access to the same parameter entries as your user client program. This is achieved by use of an external data pointer. The callout program needs to have code similar to that in the example below-:
$set ans85 WORKING-STORAGE SECTION. 01 lnk-param-block-addr POINTER EXTERNAL. LINKAGE SECTION. COPY "mfclisrv.cpy". 01 user-data-block PIC X(30). PROCEDURE DIVISION. Controlling SECTION. SET ADDRESS OF lnk-param-block TO lnk-param-block-addr SET ADDRESS OF user-data-block TO lnk-ublock-ptr SET ds-callout TO TRUE MOVE "callosrv" TO user-data-block CALL lnk-client USING lnk-param-block EXIT PROGRAM.
The name of the program which will receive the callout request on the server is setup in the user-data-block. If the name of this program can only be determined from data in any of the control blocks used by Dialog System, you will have to make these accessible using coding similar to that in the following program-:
$set ans85 linkcount(128) WORKING-STORAGE SECTION. 01 lnk-param-block-addr POINTER EXTERNAL. LINKAGE SECTION. COPY "mfclisrv.cpy". 01 user-data-block PIC X(30). COPY "DS-CNTRL.MF". COPY "CUSTOMER.CPB". PROCEDURE DIVISION USING ds-control-block customer-data-block. Controlling SECTION. SET ADDRESS OF lnk-param-block TO lnk-param-block-addr SET ADDRESS OF user-data-block TO lnk-ublock-ptr SET ds-callout TO TRUE EVALUATE cust-callout-flg WHEN 1 MOVE "callprog1" TO user-data-block WHEN 2 MOVE "callprog2" TO user-data-block END-EVALUATE CALL lnk-client USING lnk-param-block EXIT PROGRAM.
The callout program on the server side will look something like this-:
$set ans85 LINKAGE SECTION. COPY "DS-CNTRL.MF". COPY "CUSTOMER.CPB". PROCEDURE DIVISION USING ds-control-block customer-data-block. Controlling SECTION. ............ Code to ........... process callout ............ request.... EXIT PROGRAM.
The Client/Server Binding has the ability to use an existing Dialog
System program as the user server module. It does this when
program> (for details, see Configuration File
In this instance, mfserver expects to be called with a set of parameters which conform to the Dialog System API. When used in this way, the user program makes calls to mfserver to transfer data to the client and so becomes the controlling element on the server. It is possible to have other programs perform the same function, as long as they conform to the API used by Dialog System.
The Client/Server Binding normally checks certain items within the first parameter of the API, and performs particular functions based on the value found. This behaviour can be prevented by setting these items to HIGH-VALUES. You need to call mfserver with two parameters:
The size of both these items needs to be defined in the configuration file used to run the application. A pair of demo programs and the necessary configuration file have been provided here as an example, they are:
o nodscli.cbl - The client module $set ans85 WORKING-STORAGE SECTION. 01 w-prog-id pic x(30) value '"@(#) nodscli.cbl 1.1.1"'. copy "mfclisrv.cpy". 01 ws-scrn-pos. 03 ws-line pic 99 value 07. 03 ws-col pic 99 value 1. LINKAGE SECTION. 01 ds-control-block pic x(6). 01 NODS-DATA-BLOCK. 03 NODS-PARAM PIC 99. 03 NODS-DATA PIC X(120). procedure division. 000-control section. * Make initial contact with the server call lnk-client using lnk-param-block if start-connection set address of ds-control-block to lnk-cblock-ptr set address of nods-data-block to lnk-dblock-ptr end-if display spaces at 0101 "Starting Test Session" at 0510 perform 010-run-test until nods-param = 10 * Send disconnect request set client-ending to true call lnk-client using lnk-param-block display "Test Session Completed" at 2010 stop run. 010-run-test section. * Get data from server call lnk-client using lnk-param-block add 1 to ws-line display nods-data(1:80) at ws-scrn-pos exit. o nodssrv.cbl - The server module $set ans85 working-storage section. 01 w-prog-id pic x(30) value '"@(#) nodssrv.cbl 1.1.1"'. 01 dummy-cntrl-block pic x(6) value high-values. 01 NODS-DATA-BLOCK. 03 NODS-PARAM PIC 99. 03 NODS-DATA PIC X(120). copy "mfclisrv.cpy". 01 ws-sub pic 99. 01 ws-table. 03 ws-letts pic x occurs 10. procedure division. controlling section. move "ABCDEFGHIJ" to ws-table move 0 to nods-param * * Establish contact with the client. * This needs to be done as early as possible to stop the * Client timing out and 'polling' the network looking for * the server. * call "mfserver" using dummy-cntrl-block nods-data-block * * You must ensure that you don't call 'mfserver' after the * client has issued a shutdown request. In this system * nods-param = 10 causes to client to issue the shutdown * request and ends the driving loop in this program. * perform varying nods-param from 1 by 1 until nods-param > 10 perform varying ws-sub from 1 by 1 until ws-sub > 80 move ws-letts(nods-param) to nods-data(ws-sub:1) end-perform call "mfserver" using dummy-cntrl-block nods-data-block end-perform stop run. o nods.cfg - The configuration file ******************************************************************************** * Micro Focus - Client Server Module Configuration File * ******************************************************************************** [mf-clisrv] srvtier=nodssrv cblksize=6 dblksize=122 servername=nods
When compiled and run, the server program passes data to the client without losing its position which would occur if it was a called program and had to use an 'EXIT PROGRAM' each time data needed to be passed to the client. If your existing program is unable to conform to the required Dialog System API, you can still use the above method by introducing a small bridge program as decribed below.
WORKING-STORAGE SECTION. 01 dummy-control-block PIC X(6) VALUE HIGH-VALUES. 01 grouped-data-block. 03 ws-param-1 PIC X(50). 03 ws-param-2 PIC X(120). 03 ws-param-3 PIC X(18). 03 ws-param-4 PIC X(48). LINKAGE SECTION. 01 lnk-param-1 PIC X(50). 01 lnk-param-2 PIC X(120). 01 lnk-param-3 PIC X(18). 01 lnk-param-4 PIC X(48). PROCEDURE DIVISION USING lnk-param-1 lnk-param-2 lnk-param-3 lnk-param-4. MOVE lnk-param-1 TO ws-param-1 MOVE lnk-param-2 TO ws-param-2 MOVE lnk-param-3 TO ws-param-3 MOVE lnk-param-4 TO ws-param-4 CALL "mfserver" USING dummy-control-block grouped-data-block MOVE ws-param-1 TO lnk-param-1 MOVE ws-param-2 TO lnk-param-2 MOVE ws-param-3 TO lnk-param-3 MOVE ws-param-4 TO lnk-param-4 EXIT PROGRAM.
One of the most powerful features of the client/server binding is the ability to control the communications requirements from configuration files. This does mean, however, that end-users can affect the way an application runs by changing entries in these files, and this may not be desirable.
It is possible, therefore, to provide all the configuration parameters within the client program. This means that the end-user cannot alter the way an application behaves because it no longer uses a configuration file. There is still no need to write complex communications code, you simply supply the required parameters within your client program. The process is started by setting load-inline-cfg and completed by setting end-inline-cfg. Each parameter entry is loaded into the lnk-error-msg field and mfclient is called to process it. The parameters have to be supplied before the main processing loop is entered. An example is given below.
WORKING-STORAGE SECTION. COPY "mfclisrv.cpy". LINKAGE SECTION. 01 INPUT-REC PIC X(32767) PROCEDURE DIVISION. Client-Control SECTION. SET load-inline-cfg TO TRUE MOVE "clierrprog=same" TO lnk-error-msg CALL lnk-client USING lnk-param-block MOVE "srverrprog=same" TO lnk-error-msg CALL lnk-client USING lnk-param-block MOVE "servername=mainserv" TO lnk-error-msg CALL lnk-client USING lnk-param-block SET end-inline-cfg TO TRUE * The main loop is repeated until the connection with * the server ends PERFORM UNTIL End-Connection * 'lnk-client' holds the name 'mfclient' * The first time through we initialize the system and establish * contact with the server. CALL lnk-client USING lnk-param-block EVALUATE TRUE WHEN start-connection ........ The rest of the program is standard from this ........... point onwards ............
It is also possible to combine an external configuration file with the in-line configuration facility. This provides the best of both worlds in that the end-user can modify the system to their own requirements, but ultimate control remains within the client program. The configuration file is processed first followed by the in-line entries. This means that any unwanted parameters supplied in the configuration file can be overwritten by the in-line entry. In this case the process is started by setting use-combined-cfg and completed as before by setting end-inline-cfg.
WORKING-STORAGE SECTION. COPY "mfclisrv.cpy". LINKAGE SECTION. 01 INPUT-REC PIC X(32767) PROCEDURE DIVISION. Client-Control SECTION. SET use-combined-cfg TO TRUE CALL lnk-client USING lnk-param-block SET load-inline-cfg TO TRUE MOVE "servername=mainserv" TO lnk-error-msg CALL lnk-client USING lnk-param-block SET end-inline-cfg TO TRUE * The main loop is repeated until the connection with * the server ends PERFORM UNTIL End-Connection * 'lnk-client' holds the name 'mfclient' * The first time through we initialize the system and establish * contact with the server. CALL lnk-client USING lnk-param-block EVALUATE TRUE WHEN start-connection ........ The rest of the program is standard from this ........... point onwards ............
The client/server binding assigns a buffer large enough to hold the data blocks defined in the configuration file. This buffer is transferred back and forth whenever control is shifted between the client and server programs. This can impose a load on the network which some users may find unacceptable. Imagine you have a buffer of 24K which contains a 22K record area. If the file which holds these records has a 10-byte key, sending the key from client to server uses 24K when only 10 bytes are actually required. In reality, you do need one or two bytes more than the size of the data, but much less than the size of the entire buffer. This is what Reduced Data Transfer (RDT) provides, a way for you to control the amount of data being passed across the network and for you to limit this data to the absolute minimum required. This facility is only available if you are using the CCI communications API. It is not required if you are using the AAI communications API because the AAI API includes the facility to compress data automatically. Using the RDT facility with the AAI communications API may cause unpredictable results.
Reduced Data Transfer requires a contol flag (use-rdt) and three parameters:
|lnk-usr-fcode||The user function indicator. This indicates to the receiver what to do with the data that has just arrived.|
|lnk-usr-retcode||The buffer start point. This indicates which of the four data areas will be used as the start point for the transfer. Valid values are: 1=cblock, 2=dblock, 3=eblk, and 4=ublk. The numbers 11 through 14 can also be used to indicate the same address areas but using data compression. Data compression must have been enabled via a configuration file entry or the base (un-compressed) option will be used. A value of zero results in nothing being transferred. This allows you to have a NULL operation without changing the flow of your code by adding various IF statements. This is useful if you choose to process certain functions locally in order to further reduce network traffic.|
|lnk-data-length||The length of data to be transferred.|
Consider an application which allows you to add, delete, and load customer details to/from an index file. The record key for the customer details file is a customer code. The application also has an option to clear all customer information from the interface. The code extract below is based on this example application and uses the user-data-block area to hold the record key which is six bytes long. The data block area (dblksize) used by the application to pass the customer record details between the client and the server is called customer-data-block. The data item customer-c-code is a 6-byte data item within customer-data-block and is used to store the record key.
On the client, the code would be similar to:
EVALUATE TRUE WHEN customer-load-flg-true *--- User has entered customer code and selected the "LOAD" *--- option on the interface to read and display the customer *--- details relating to that code. MOVE customer-c-code TO user-data-block SET use-rdt TO TRUE MOVE 1 TO lnk-usr-fcode MOVE 4 TO lnk-usr-retcode MOVE 6 TO lnk-data-length WHEN customer-del-flg-true *--- User has entered a customer code selected the DELETE *--- option to delete the customer record from the file. MOVE customer-c-code TO user-data-block SET use-rdt TO TRUE MOVE 2 TO lnk-usr-fcode MOVE 4 TO lnk-usr-retcode MOVE 6 TO lnk-data-length initialize customer-data-block WHEN customer-clr-flg-true *--- User has selected the CLEAR option to clear the current *--- customer details from the screen. SET use-rdt TO TRUE MOVE 0 TO lnk-usr-retcode initialize customer-data-block PERFORM Set-Up-For-Refresh-Screen END-EVALUATE
The clear option uses a NULL operation because clearing the record is done locally so there is no need to contact the server. Below is an extract from the server program showing the code required to process Reduced Data Transfer. The client/server binding sets the flag send-via-rdt so that you can check the values of lnk-usr-fcode. On the server, the code would be similar to:
WHEN send-via-rdt EVALUATE lnk-usr-fcode WHEN 1 *--- For the LOAD function the server program reads the customer *--- details from the data file and sends the data back to the *--- client using the data area customer-data-block rather using *--- the RDT faclity. Unless the RDT flag is set the client/server *--- bindings will always pass the complete data area (defined by *--- dblksize in the configuration file) between the client and the *--- server. MOVE user-data-block TO customer-c-code SET customer-load-flg-true TO TRUE PERFORM ....... rest of program....... WHEN 2 MOVE user-data-block TO customer-c-code SET customer-del-flg-true TO TRUE PERFORM ....... rest of program....... END-EVALUATE
The Csbind demonstration application uses the Reduced Data Transfer facility.
One of the problems that accompanies any client/server solution, especially as the number of clients increases, is the management of client program updates and other changes.
The override facility (see Overriding Configuration File Entries) enables you to re-route client applications while server maintenance is carried out without having to change each client's configuration file entries. The override can be either local or remote but installing and removing a local override file on each client can be time-consuming.
The mfcsmgr program enables you to install and delete override files on the client using the -i and -d options respectively (see Managing the Server). The installation/deletion is carried out as the client program exits.
In fact, the -i option of the mfcsmgr program enables you to install any type of file on the client system (in the client's local directory). This means that you can use it to install new screensets or program files, enabling updates to be distributed from a central point. For security reasons, the delete option has not been similarly enhanced, it will only delete an override file, that is, a file called mfcsovrd.cfg.
Files to be installed using the -i option must be located on the server. If the file is in the directory that mfserver was started from, you need only specify the filename. If it is anywere else, you must supply a full pathname in such a way that the filename can be extracted from the path, for example, /u/live/update/newprog.int, d:\testprog.int and $LIVE/newtest.int are all valid but $newfile is not.
No programming changes are required to use these functions, a message is displayed informing the client that a file is being transferred and the details are recorded in the system log file.
The client/server binding imposes very few limitations, but you should be aware of the following issues.