Documentation Comments
Use this form to comment on this topic. You can also provide any general observations about the Online Documentation, or request that additional information be added in a future release.
Reality V15.2 Online Documentation (MoTW) Revision 3
Program Examples using Interprocess Communication (DataBasic) (m618705+ipc_example.htm)
The SALES system has a program to take care of orders being placed for products. The order entry clerk must check the customer's credit rating from data held on the FINANCE system. The orders program on the SALES system is written as a client, which makes use of a server program running on the FINANCE system.
The SALES order processing program includes the following code:
*(near the beginning of the program) CONNECT "FINANCE":AM:"SALES-ACCOUNT":AM:... "ORDER-SERVER" TO SESS ELSE.. * This starts and establishes contact with the * server on the FINANCE system. * *(while processing an order) INFO<1>=ORDER.NO INFO<2>=CUSTOMER INFO<3>=COST * SEND INFO TO SESS ELSE.. * RECWAIT RESPONSE FROM SESS ELSE.. IF RESPONSE="OK" THEN PRINT "Credit OK, order accepted by FINANCE." END ELSE PRINT "Credit NOT OK, do not trust this one!" * Take care of bad customer END * *(near end of program) DISCONNECT SESS ELSE.. *
On the FINANCE system, the program ORDER-SERVER on the SALES-ACCOUNT includes the following code:
* near the beginning ACCEPT "ORDER-SERVER" TO SESS ELSE.. * This connects with the client process. * RECWAIT INFO FROM SESS ELSE.. * ORDER.NO=INFO<1> CUSTOMER=INFO<2> COST=INFO<3> * READ CREDIT FROM CUST.FILE,CUSTOMER ELSE.. IF CREDIT>=COST THEN SEND "OK" TO SESS ELSE.. WRITE INFO TO ACCOUNT.REC.FILE,ORDER.NO END ELSE SEND "NOT OK" TO SESS ELSE.. END *
When the ORDER program runs, the SALES system talks to the FINANCE system. The operating system on FINANCE checks to see if a program has issued an ACCEPT with the server name "ORDER-SERVER". If there is an ACCEPT outstanding, a session is established between the two programs. If not, "ORDER-SERVER" is issued as a TCL command on the "SALES-ACCOUNT". This invokes the DataBasic program titled "ORDER-SERVER". When the "ORDER-SERVER" program issues its ACCEPT statement, the connection is established.
The server program could be designed to accommodate several client programs, all programmed to make the same inquiry and obtain the same type of information from the server program.
In the following example, three client programs connect to the server program. The sessions are called SESS1, SESS2, and SESS3. The server in the CONNECT statements of the three client programs are ORD-SERV1, ORD-SERV2, and ORD-SERV3. The MD of the SALES-ACCOUNT contains items labeled ORD-SERV1, ORD-SERV2, and ORD-SERV3. Each contains the following attributes:
PQN
HRUN SALES ORDER-SERVER
P
The ORDER-SERVER program includes the following code:
ACPT1:
ACCEPT "ORD-SERV1" TO SESS1 THEN GO READ1 ELSE FLG1=0 GO READ2
ACPT2:
ACCEPT "ORD-SERV2" TO SESS2 THEN GO READ2 ELSE FLG2=0 GO READ3
ACPT3:
ACCEPT "ORD-SERV3" TO SESS3 THEN GO READ3 ELSE FLG3=0 GO READ1
*
READ1:
IF FLG1=0 THEN GO ACPT1
RECEIVE INFO FROM SESS1 THEN GOSUB ...
RUN.IT ELSE GO READ2
SEND REPLY TO SESS1 SETTING E1 ELSE ...
GO ERR.VAL
READ2:
IF FLG2=0 THEN GO ACPT2
RECEIVE INFO FROM SESS2 THEN GOSUB ...
RUN.IT ELSE GO READ3
SEND REPLY TO SESS2 SETTING E2 ELSE ...
GO ERR.VAL
READ3:
IF FLG3=0 THEN GO ACPT3
RECEIVE INFO FROM SESS3 THEN GOSUB ...
RUN.IT ELSE GO READ1
SEND REPLY TO SESS3 SETTING E3 ELSE ...
GO ERR.VAL
GOTO READ1
RUN.IT:
ORDER.NO=INFO<1>
CUSTOMER=INFO<2>
COST=INFO<3>
*
READ CREDIT FROM CUST.FILE,CUSTOMER ELSE..
IF CREDIT>=COST THEN
REPLY="OK"
WRITE INFO TO ACCOUNT.REC.FILE,ORDER.NO
END ELSE
REPLY="NOT OK"
END
RETURN
*
ERR.VAL:
* Evaluate error code, why can't send data
Notice that the RECWAIT statement of the original program is replaced with RECEIVE statements. If data is there to be read, it is read; otherwise, the program advances to the next receive operation.
The example program FPUT listed below communicates with the example program FGET that follows. These programs are executed from separate processes (usually running on different systems connected to a common network, although for testing purposes they can be run on the same system).
FPUT sets up the connection and starts FGET, then waits for input from FGET. It cycles round until the session is terminated by FGET. It then reports statistics and stops. See below.
EQUATE AM TO CHAR(254)
PRINT "REMOTE SYSTEM ":
INPUT RSYS
CRT "CONNECTING..."
CONNECT RSYS:AM:'CHRIS':AM:'FGET' TO S TIMEOUT 2 SETTING ECODE THEN
STTIME = SYSTEM(12)
BYTES = 0
CNT = 0
XCNT = 0
FAILED= 0
CRT "CONNECTED"
LOOP UNTIL FAILED DO
RECWAIT DT FROM S SETTING ECODE ELSE
PRINT "RECEIVE ERROR: ":ECODE
CRT "AVERAGE TRANSMISSION RATE = ":...
200100/(SYSTEM(12)-SSTIME):"BYTES PER SECOND."
DISCONNECT S SETTING ECODE ELSE
PRINT "DISCONNECT ERROR: ":ECODE
END
FAILED = 1
END
END ELSE
CRT "CAN'T CONNECT - ERROR: ":ECODE
END
END
The program FGET is started as a server by FPUT. (It must therefore be cataloged on the account CHRIS on remote system RSYS to which connection is made by FPUT.) It accepts the connection then transmits a series of values to FPUT before disconnecting. See below.
1 CRT 'ACCEPTING...':
ACCEPT "FGET" TO S TIMEOUT 2 SETTING ECODE ELSE
PRINT 'CONNECT ERROR : ' : ECODE
STOP
END
CRT 'ACCEPTED.'
!
DT = STR("+",2000)
FOR X = 1 TO 100
SEND CHAR(X):DT ON S SETTING ECODE ELSE
CRT "SEND ERROR = ":ECODE
100 DISCONNECT S SETTING ECODE ELSE
PRINT 'DISCONNECT ERROR : ' : ECODE
END
STOP
END
NEXT X
!
SEND "END" ON S SETTING ECODE ELSE
CRT "SEND ERROR = ":ECODE
GOTO 100
END
2 DISCONNECT S SETTING ECODE ELSE
PRINT 'DISCONNECT ERROR : ' : ECODE
STOP
END
GOTO 1
END
Note: The code for these example programs can be found in the file /SYSPROG/BP.
The program PERFORM-CLIENT connects to a system and an account selected by the user, and starts program PERFORM-SERVER on that system/account. A command entered by the user is sent to PERFORM-SERVER. The response from PERFORM-SERVER is displayed. This continues until END is entered, disconnecting the link. See below.
AM = CHAR(254)
PRINT 'SYSTEM ':
INPUT SYS
PRINT 'ACCOUNT ':
INPUT ACCN
CRT 'CONNECTING...':
CONNECT SYS : AM : ACCN : AM : "PERFORM-SERVER" TO S TIMEOUT 1...
SETTING ECODE ELSE GOTO 99
CRT 'OK.'
1 INPUT COMMAND
IF COMMAND='END' THEN GOTO 88
SEND COMMAND ON S SETTING ECODE ELSE GOTO 71
RECWAIT STUFF FROM S SETTING ECODE ELSE GOTO 72
* CRT STUFF
N = COUNT(STUFF,AM)+1
FOR I=1 TO N
CRT STUFF<I>
NEXT I
GOTO 1
71 CRT 'TX ERROR - ':ECODE
GOTO 88
72 CRT 'RX ERROR - ':ECODE
88 CRT 'DISCONNECTING...':
DISCONNECTING S SETTING ECODE ELSE GOTO 99
CRT 'OK.'
STOP
99 CRT "ERROR - ":ECODE
END
This program is started following a request from PERFORM-CLIENT. It accepts the connection, then waits to receive input from PERFORM-CLIENT.
The data from PERFORM-CLIENT should be a command. PERFORM-SERVER executes the command via a PERFORM statement and sends the result to PERFORM-CLIENT (which displays the result on the local terminal). This continues until PERFORM-CLIENT terminates the session. See below.
CRT 'ACCEPTING...': ACCEPT "PERFORM-SERVER" TO S TIMEOUT 1 SETTING ECODE ELSE GOTO 99 CRT 'OK.' 1 CRT '?': RECWAIT X FROM S SETTING ECODE ELSE GOTO 71 CRT X PERFORM X CAPTURING Y SEND Y ON S SETTING ECODE ELSE GOTO 72 GOTO 1 71 CRT 'RX ERROR - ':ECODE GOTO 88 72 CRT 'TX ERROR - ':ECODE 88 CRT 'DISCONNECTING...': DISCONNECT S SETTING ECODE ELSE GOTO 99 CRT 'OK.' STOP 99 CRT 'ERROR - ':ECODE END
The following client and server programs demonstrate how you might use TCP/IP to communicate between two Reality systems.
Note: The code for these example programs can be found in the file /SYSPROG/BP.
* RTCL - Execute remote TCL command
*
* RTCL Host|* TclCommand -- * for localhost"
*
* Connect to XTCL listening on HostName, port 52002, send TCL
* command which XTCL will PERFORM and return the response.
*
* Set environment variable RNWS_LOG_LEVEL in range 0 to 7 for
* tracing. Set environment variable RNWS_LOG_FILE to specify trace
* file.
*
EQU EDISCONN TO 4235
*
TCL = SENTENCE()
HOST = FIELD(TCL," ",2)
CMD = FIELD(TCL," ",3)
PORT = 52002
*
IF HOST = "" OR HOST = "?" THEN
PRINT "RTCL Host|* {TclCommand} -- * for localhost"
STOP
END
*
IF HOST = "*" THEN HOST = "127.0.0.1"
SYS="*TCP*":HOST:";port=":PORT
*
CONNECT SYS TO SESS SETTING ERRNO ELSE
OPN = "CONNECT"
GOTO FIN
END
*
ONEOFF = CMD # ""
LOOP
IF NOT(ONEOFF) THEN INPUT CMD
WHILE CMD # "" DO
SDAT=CMD
GOSUB SEND_SDAT
IF ERRNO THEN GOTO FIN
GOSUB RECV_RDAT
IF ERRNO THEN GOTO FIN
PRINT RDAT<1>
IF ONEOFF THEN GOTO FIN
REPEAT
*
FIN:
*
IF ERRNO THEN
IF ERRNO = EDISCONN THEN
PRINT SYS:" disconnected"
END ELSE
PRINT OPN:" (":SYS:") failed, ERRNO=":ERRNO
END
END
*
IF NOT(UNASSIGNED(SESS)) THEN
DISCONNECT SESS SETTING ERRNO ELSE
PRINT "DISCONNECT (":SYS:") failed, ERRNO=":ERRNO
END
END
*
IF NOT(UNASSIGNED(LSESS)) THEN
DISCONNECT LSESS SETTING ERRNO ELSE
PRINT "DISCONNECT(listener) (":SYS:") failed, ERRNO=":ERRNO
END
END
*
STOP
*
**
***
SEND_SDAT:
**********
MSG = "<":SDAT:">"
SEND MSG TO SESS SETTING ERRNO ELSE
OPN = "SEND"
END
RETURN
*
**
***
RECV_RDAT:
**********
RDAT = ""
LOOP
RECEIVE MSG FROM SESS SETTING ERRNO ELSE
OPN = "RECEIVE"
GOTO FIN_RECV_RDAT
END
RDAT = RDAT:MSG
AGAIN = RDAT[-1,1] # ">"
WHILE AGAIN DO REPEAT
*
RDAT[-1,1] = ""
RDAT[1,1] = ""
*
FIN_RECV_RDAT:
*
RETURN
*
**
***
END
***
* XTCL - Perform TCL command from remote client
*
* XTCL LocalHostName|* -- * for all local interfaces
*
* Listen on port 52002 for incoming connection, receive and perform
* TCL command and return response to client. Loop back for next
* command or client disconnect. 'RTCL host OFF' will log us off.
*
* Set environment variable RNWS_LOG_LEVEL in range 0 to 7 for tracing.
* Set environment variable RNWS_LOG_FILE to specify trace file.
*
EQU EDISCONN TO 4235
*
LOOPING = 0
TCL = SENTENCE()
HOST = FIELD(TCL," ",2)
PORT = 52002
*
IF HOST = "" OR HOST = "?" THEN
PRINT "XTCL LocalHostname|* -- * for all local interfaces"
STOP
END
*
IF HOST = "*" THEN
HOST = ""
END
*
SYS="*TCP*":HOST:";port=":PORT
*
* Activate listening socket
*
ACCEPT SYS:";listen=1" TO LSESS SETTING ERRNO ELSE
OPN = "ACCEPT(listen)"
GOTO FIN
END
*
* Accept incoming connection
*
LOOPING = 1
ERRNO = 0
LOOP
ACCEPT SYS TO SESS SETTING ERRNO ELSE
OPN = "ACCEPT"
GOTO FIN
END
*
LOOP
ERRNO = 0
GOSUB RECV_RDAT
IF ERRNO = 0 THEN
IF RDAT = "STOP" THEN
SDAT = "CLOSING SERVER"
LOOPING = 0
END ELSE
PERFORM RDAT CAPTURING SDAT
END
GOSUB SEND_SDAT
END
WHILE ERRNO = 0 DO REPEAT
IF ERRNO = EDISCONN THEN ERRNO=0
*
FIN:
*
IF ERRNO THEN
PRINT OPN:" (":SYS:") failed, ERRNO=":ERRNO
END
*
IF NOT(UNASSIGNED(SESS)) THEN
DISCONNECT SESS SETTING ERRNO ELSE
PRINT "DISCONNECT (":SYS:") failed, ERRNO=":ERRNO
END
END
*
WHILE ERRNO = 0 AND LOOPING DO REPEAT
*
IF NOT(UNASSIGNED(LSESS)) THEN
DISCONNECT LSESS SETTING ERRNO ELSE
PRINT "DISCONNECT(listener) (":SYS:") failed, ERRNO=":ERRNO
END
END
*
STOP
*
**
***
SEND_SDAT:
**********
MSG = "<":SDAT:">"
SEND MSG TO SESS SETTING ERRNO ELSE
OPN = "SEND"
END
RETURN
*
**
***
RECV_RDAT:
**********
RDAT = ""
LOOP
RECEIVE MSG FROM SESS SETTING ERRNO ELSE
OPN = "RECEIVE"
GOTO FIN_RECV_RDAT
END
RDAT = RDAT:MSG
AGAIN = RDAT[-1,1] # ">"
WHILE AGAIN DO REPEAT
*
RDAT[-1,1] = ""
RDAT[1,1] = ""
*
FIN_RECV_RDAT:
*
RETURN
*
**
***
END
***
Note: The code for this example program can be found in the file /SYSPROG/BP.
* PING - Reality sockets test program to send/receive to echo server
*
* PING HostName
*
* Provides similar functionality to the UNIX ping utility. A
* connection is established to a remote TCP 'echo' server specified
* by argument 1. A message is sent and echo received, five times.
*
* Set environment variable RNWS_LOG_LEVEL in range 0 to 7 for
* tracing. Set environment variable RNWS_LOG_FILE to specify trace
* file.
*
TCL = SENTENCE()
HOST = FIELD(TCL," ",2)
PORT=7
*
IF HOST = "" OR HOST = "?" THEN
PRINT "PING [HostName|IP address]"
STOP
END
*
SYS="*TCP*":HOST:";port=":PORT
*
CONNECT SYS TO SECHO TIMEOUT 1 SETTING ERRNO ELSE
PRINT "Failed to connect to ":SYS:", error=":ERRNO
GOTO L_ABORT
END
*
SMSG="Data/Basic socket call to echo port"
*
FOR I = 1 TO 5
SEND SMSG TO SECHO SETTING ERRNO ELSE
PRINT "Failed to send msg to ":SYS:", error=":ERRNO
GOTO L_ABORT
END
*
RECWAIT RMSG FROM SECHO TIMEOUT 1 SETTING ERRNO ELSE
PRINT "Failed to receive msg from ":SYS:", error=":ERRNO
GOTO L_ABORT
END
PRINT "Received:'":RMSG:"' from ":HOST
NEXT I
*
L_ABORT:
IF NOT(UNASSIGNED(SECHO)) THEN
DISCONNECT SECHO SETTING ERRNO ELSE
PRINT "Failed to disconnect from ":SYS:", error=":ERRNO
END
END
*
STOP
*
END
Note: The code for this example program can be found in the file /SYSPROG/BP.
* MAIL - send email
*
* MAIL <To:> <From:> <SmtpServer>
*
* Connect to SMTP service on specified DNS name and pass sender and
* recipient's mail path, viz email addresses, finally send the email
* body.
*
* This program was based on information found in RFC 821, it in no
* way handles every eventuality and is for example purposes only.
*
EQU EDISCONN TO 4235
EQU TRACING TO 1
CRLF = CHAR(13):CHAR(10)
EML.HOST = "mysystem.northgate-is"
*
TCL = SENTENCE()
EML.TO = FIELD(TCL," ",2)
EML.FROM = FIELD(TCL," ",3)
SMTPHOST = FIELD(TCL," ",4)
PORT = 25
*
IF SMTPHOST = "" THEN
PRINT "MAIL <To:> <From:> <SmtpServer>"
STOP
END
*
SYS="*TCP*":SMTPHOST:";port=":PORT
*
* Build email header
*
EML.HEADER = "Subject: TEST Sockets API":CRLF:"From: ":EML.FROM
EML.HEADER = EML.HEADER:CRLF:"To: ":EML.TO
*
PRINT "Enter message text:"
INPUT EML.TEXT
*
CONNECT SYS TO SESS SETTING ERRNO ELSE
OPN = "CONNECT"
GOTO FIN
END
*
SDAT = "HELO ":EML.HOST
GOSUB POST; IF ERRNO THEN GOTO FIN
IF RDAT[1,6] # "250 OK" THEN GOTO PROTOCOL.ERROR
*
SDAT = "MAIL FROM:":EML.FROM
GOSUB POST; IF ERRNO THEN GOTO FIN
IF RDAT[1,6] # "250 OK" THEN GOTO PROTOCOL.ERROR
*
SDAT = "RCPT TO:":EML.TO
GOSUB POST; IF ERRNO THEN GOTO FIN
IF RDAT[1,6] # "250 OK" THEN GOTO PROTOCOL.ERROR
*
SDAT = "DATA"
GOSUB POST; IF ERRNO THEN GOTO FIN
IF RDAT[1,3] # "354" THEN GOTO PROTOCOL.ERROR
*
* Build email body - header, blank line, text & a '.' on it's own line,
* this, with the final CRLF added by POST, terminates the message body.
*
SDAT = EML.HEADER:CRLF:CRLF:EML.TEXT:CRLF:"."
GOSUB POST; IF ERRNO THEN GOTO FIN
IF RDAT[1,6] # "250 OK" THEN GOTO PROTOCOL.ERROR
*
GOTO FIN
*
PROTOCOL.ERROR:
*
PRINT "Unexpected response from SMTP server."
PRINT "SDAT=":SDAT
PRINT "RDAT=":RDAT
*
FIN:
*
IF ERRNO THEN
IF ERRNO = EDISCONN THEN
PRINT SYS:" disconnected"
END ELSE
PRINT OPN:" (":SYS:") failed, ERRNO=":ERRNO
END
END
*
IF NOT(UNASSIGNED(SESS)) THEN
DISCONNECT SESS SETTING ERRNO ELSE
PRINT "DISCONNECT (":SYS:") failed, ERRNO=":ERRNO
END
END
*
STOP
*
**
***
POST:
*****
IF TRACING THEN PRINT "POST:":SDAT
MSG = SDAT:CRLF
SEND MSG TO SESS SETTING ERRNO THEN
GOSUB RECV
END ELSE
OPN = "SEND"
END
RETURN
*
**
***
RECV:
****
RDAT = ""
LOOP
RECEIVE MSG FROM SESS SETTING ERRNO ELSE
OPN = "RECEIVE"
GOTO FIN_RECV
END
RDAT = RDAT:MSG
AGAIN = RDAT[-2,2] # CRLF
WHILE AGAIN DO REPEAT
*
RDAT[-2,2] = ""
*
IF TRACING THEN PRINT "RECV:":RDAT
IF RDAT[1,3] = "220" THEN
* This is the greeting reply from server, is ok, go do another receive
GOTO RECV
END
FIN_RECV:
*
RETURN
*
**
***
END
***