A Caché of Tips: Sockets

13 views
Skip to first unread message

Steve C. (ISC)

unread,
Apr 30, 2012, 5:19:56 PM4/30/12
to InterSy...@googlegroups.com
In this MV Tip we will discuss and demonstrate the %IO.Socket and %IO.ServerSocket classes.

If your application could benefit from the use of sockets, Cache provides these classes which can be easily integrated with your current MV codebase.  Using sockets provide a standardized communication protocol that will not only work between different process but also different applications.  Sockets are created at lower level of communication but saves the application designer from working with TCP to create a communication channel. The most simple use of sockets is to send communication to another processes but much more complex uses are possible when developing your application.

We will be using objects in this demonstration.  Information on how to use objects in MVBasic please review this previous MV Tip: https://sites.google.com/site/intersystemsmv/home/a-cache-of-tips/classesandmvbasic

Also, we do error checking when setting up our sockets and working with our data.   We described some ways to use %Status in another previous MV Tip: https://sites.google.com/site/intersystemsmv/home/a-cache-of-tips/usingstatus

In the example below we will demonstrate a process that acts as a listening server and another process that acts as client sending text to the listening server:

    ~Client~
0001 EQU ENDMESSAGE TO "#END#"
0002 EQU ADDRESS TO "LOCALHOST"
0003 EQU PORT TO "54321"
0004 EQU TIMEOUT TO 5
0005
0006 MYSOCKET = "%IO.Socket"->%New()
0007    !Create a new %IO.Socket and assign it to the MYSOCKET object
0008
0009 IF MYSOCKET->Open(ADDRESS,PORT,TIMEOUT,OSTATUS)
0010    !Use the MYSOCKET object and OPEN a connection
0011 THEN
0012    LINE = "HELLO WORLD"
0013    MYSOCKET->WriteLine(LINE,1,WSTATUS)
0014        !Using the WriteLine method in %IO.Socket we send the
0015        !text "HELLO WORLD".  The second value of "1" ensures
0016        !that the characters are sent to the stream otherwise
0017        !we return an error.  Finally the WSTATUS value records
0018        !the status result of this command.
0019
0020    IF $SYSTEM.Status->IsOK(WSTATUS)
0021    !Check to see that WSTATUS did not return an error
0022    THEN
0023            LINE = ENDMESSAGE
0024            MYSOCKET->WriteLine(LINE,1,WSTATUS)
0025                !Here we send the line that we designated to finish
0026                !our communication folling the same principals as
0027                !the previous WriteLine.
0028            SLEEP 5
0029    END
0030    MYSOCKET->Close(CSTATUS,1)
0031        !Close the socket connection used by the MYSOCKET object
0032
0033    IF $SYSTEM.Status->IsError(CSTATUS)
0034        !Check "Close" for error
0035    THEN
0036            CRT "SOCKET CLOSE ERROR"
0037            CRT $SYSTEM.Status->GetErrorText(CSTATUS)
0038                !If we had a socket close error we would send the error
0039                !message to the terminal.
0040    END
0041 END
0042 ELSE
0043    CRT "SOCKET OPEN ERROR"
0044    CRT $SYSTEM.Status->GetErrorText(OSTATUS)
0045        !If we had a socket open error we would send the error
0046        !message to the terminal.
0047 END

We use the %IO.Socket class for the client.
http://docs.intersystems.com/cache20121/csp/documatic/%25CSP.Documatic.cls?PAGE=CLASS&LIBRARY=%25SYS&CLASSNAME=%25IO.Socket

For the client we need to specify a hostname and port number to connect to the "remote" process.  We also provide a timeout value.  The text we are sending is "HELLO WORLD" and to end the communication we send the text "#END#".  The Listening Server knows that the communication is finished when it receives that text.


    ~Listening Server~
0001 EQU ENDMESSAGE TO "#END#"
0002 EQU HOST TO "LOCALHOST"
0003 EQU PORT TO "54321"
0004 EQU TIMEOUT TO 15
0005
0006 MYSOCKET = "%IO.ServerSocket"->%New()
0007    !Create a new %IO.ServerSocket and assign it to the MYSOCKET object
0008
0009 IF MYSOCKET->Open(PORT,TIMEOUT,OSTATUS)
0010 THEN
0011    IF MYSOCKET->Listen(TIMEOUT,LSTATUS)
0012            !Use the MYSOCKET object tha has opened a connection on the PORT
0013            !and use the Listen method to start listening for text.
0014    THEN
0015            LINE = ""
0016            LOOP UNTIL LINE = ENDMESSAGE
0017                    !Continue listening until ENDMESSAGE text received
0018                    !when we break out of the loop
0019                    LINE = MYSOCKET->ReadLine(4096,-1,RSTATUS)
0020                            !Use the ReadLine method to retrieve the text from the
0021                            !client communcation.  The end of a line is determined
0022                            !by either a termination character or the max character
0023                            !lentgh
0024                    IF "%SYSTEM.Status"->IsOK(RSTATUS)
0025                            !Check status of the ReadLine
0026                    THEN
0027                            CRT "Received Message: " :LINE
0028                                    !Print the text from the clent we received
0029                    END
0030            REPEAT
0031
0032            IF "%SYSTEM.Status"->IsOK(RSTATUS)
0033            THEN
0034                    IF LINE = ENDMESSAGE
0035                    THEN
0036                            CRT "END MESSAGE RECEIVED"
0037                            MYSOCKET->Close(CSTATUS)
0038                            SLEEP 5
0039                                    !We received the End Message and will
0040                                    !close our socket
0041                    END
0042                    ELSE
0043                            CRT "ERROR"
0044                    END
0045            END
0046            ELSE
0047                    CRT "LISTEN FAILED"
0048                    CRT $SYSTEM.Status->GetErrorText(LSTATUS)
0049                    !If we had a socket listen error we would send the error
0050                    !message to the terminal.
0051            END
0052    END
0053    ELSE
0054            CRT "OPEN FAILED"
0055            CRT $SYSTEM.Status->GetErrorText(OSTATUS)
0056            !If we had a socket open error we would send the error
0057            !message to the terminal.
0058    END
0059 END

We use the %IO.ServerSocket class for the Listening Server.
http://docs.intersystems.com/cache20121/csp/documatic/%25CSP.Documatic.cls?PAGE=CLASS&LIBRARY=%25SYS&CLASSNAME=%25IO.ServerSocket

For the Listening Server we provide the port number and timeout values.  The communication from the client process is parsed in the ReadLine method.  We read the socket communication until the follow criteria are met: Read until MaxReadLen chars are gotten, Timeout expires, or a LineTerminator character is encountered.  Also, we are checking to see if #END# has been sent indicating the end of the communication.  When communication is finished we close our socket connection.

Output from client and listening server:

    ~Client Process~
MV1:
MV1:RunClient
MV1:

    ~Listening Server Process~
MV2:
MV2:RunListeningServer
Received Message: HELLO WORLD
Received Message: #END#
END MESSAGE RECEIVED
MV2:

This is a small example of how to use sockets.   I hope this MV Tip gave a good introduction to sockets and I encourage you to build on these samples to increase your understanding of this topic.
Reply all
Reply to author
Forward
0 new messages