Interapplication Communication Using the Socket OPI
The PV‑WAVE Socket OPI greatly simplifies the programming required to write PV‑WAVE client and server programs that communicate through sockets. Using the Socket OPI routines, you can write client and server applications entirely in PV‑WAVE.
Sockets allow programmers to treat network connections as a stream of bytes that can be read from or written to. Sockets handle the low-level tasks of data transmission and network addresses, thereby freeing network programmers to concentrate primarily on network applications.
The PV‑WAVE Socket routines allow PV‑WAVE applications to:
listen for connections (server)
initiate connections (client)
read and write data through connections (client and server)
terminate connections (client and server)
Socket OPI Routines lists the Socket OPI routines and indicates whether a specific routine is typically used in client applications, server applications, or both.
Overview of a Client-Server Model Using Sockets
Client-Server Model shows a typical client-server model using the PV‑WAVE Socket OPI.
On the server, socket port 1800 is intialized with the SOCKET_INIT function. The SOCKET_ACCEPT function waits for a connection. The client initializes a connection with the SOCKET_CONNECTION function. This function specifies a host address (for example, www.vni.com) and a port number.
The SOCKET_READ and SOCKET_WRITE routines allow data to be sent between the client and server, through the socket connection. SOCKET_WRITE sends a byte array through an established socket connection. SOCKET_READ retrieves the byte array.
note | The SOCKET_READ Function is blocking and will not return until the byte array passed to it is full or a problem occurs with the connection. |
Loading the Socket OPI
Before you can use the PV‑WAVE socket routines, the Socket OPI (Optional Programming Interface) must be loaded on the server and the client.
To load the Socket OPI execute the program file (batch file) SOCKET_STARTUP at the PV‑WAVE command line. For example:
WAVE> @SOCKET_STARTUP
Initializing a Socket
The SOCKET_INIT function allows you to specify which socket port on the server machine will be used to “listen” for incoming client connections. This function returns a handle for the socket. This handle is used by other Socket OPI functions to refer to the socket.
In the following lines, socket port 1800 is initialized with SOCKET_INIT, and then the resulting socket descriptor is passed to the SOCKET_ACCEPT function, which listens for client connections.
socketID=SOCKET_INIT(1800)
connection=SOCKET_ACCEPT(socketID)
Listening for a Socket Connection
After a socket is initialized, call the
SOCKET_ACCEPT Function to wait for client connections. SOCKET_ACCEPT blocks further execution of the current application until a connection is received or the
Timeout value is reached. When a connection is received, the SOCKET_ACCEPT function returns a handle for the connection. This handle is then used to identify the connection in other socket routines, like SOCKET_READ and SOCKET_WRITE.
In the following lines, SOCKET_READ reads data from a socket connection on the server.
socketID=SOCKET_INIT(1800)
myconnection=SOCKET_ACCEPT(socketID)
mydata=BYTARR(100)
nbytes=SOCKET_READ(myconnection, mydata)
Connecting to a Socket
Client applications use SOCKET_CONNECT to connect to a server listening for a connection (that is, SOCKET_ACCEPT must be running on the server). SOCKET_CONNECT specifies a host address (host name or IP address) and a port number. It returns a connection handle, which is used in SOCKET_READ and SOCKET_WRITE to identify the connection.
note | The SOCKET_READ Function is blocking and will not return until the byte array passed to it is full or a problem occurs with the connection. |
The following call to SOCKET_CONNECT attempts to make a connection to port 80 on the Rogue Wave’s Web server. Then, SOCKET_WRITE sends data to the remote sever using the established connection.
myconnection=SOCKET_CONNECT('www.vni.com', 80)
mydata=BYTE('GET / HTTP/1.0\015\012\015\012')
SOCKET_WRITE, myconnection, mydata
Reading and Writing Data Between Client and Server
After a socket connection is established between a client and server, the routines SOCKET_WRITE and SOCKET_READ are the mechanisms by which data is sent and retrieved.
SOCKET_WRITE is a procedure that sends a byte array through the socket connection. SOCKET_READ retrieves a byte array on the other side of the connection.
note | The SOCKET_READ Function is blocking and will not return until the byte array passed to it is full or a problem occurs with the connection. |
It is up to the client and server software developers to decide how to encode and decode the data that is sent and received by SOCKET_WRITE and SOCKET_READ. The only requirement is that the data be a byte array.
note | Use data extraction functions (BYTE, FLOAT, FIX, and so on) and BYTEORDER with the Htons and Htonl keywords to format data for network transmission. |
Closing a Socket Connection
To close a socket connection, call SOCKET_CLOSE. This procedure takes one argument, the connection handle (the result returned from SOCKET_CONNECT).
myconnection=SOCKET_CONNECT('www.vni.com', 80)
SOCKET_WRITE, myconnection, mydata
SOCKET_CLOSE, myconnection
Example
This example demonstrates a simple series of transactions between a client and a server program. The client sends a string to the server, and the server prints the string. The server then returns a string, which the client prints. A FOR loop repeats this sending and receiving pattern a total of three times.
note | All data transmitted through PV‑WAVE socket connections must be in the form of a byte array. |
The Server
This server program reads data sent from the client, prints the data, and sends data back to the client.
PRO SERVER
port = 1500
socket = SOCKET_INIT(port)
connection = SOCKET_ACCEPT(socket)
FOR i = 0,2 DO BEGIN
data = BYTARR(15)
nbytes = SOCKET_READ(connection,data)
PRINT, 'SERVER received: ', STRING(data)
data = BYTE('Server String ' + STRTRIM(STRING(i),2))
SOCKET_WRITE, connection, data
PRINT, 'SERVER sent: ', data
ENDFOR
SOCKET_CLOSE, connection
SOCKET_CLOSE, socket
END
The Client Program
This client program sends data to the server, then reads and prints data returned from the server.
PRO CLIENT
host = 'localhost'
port = 1500
socket = SOCKET_CONNECT(host,port)
IF socket EQ -1 OR socket EQ -2 THEN BEGIN
PRINT, 'SOCKET_CONNECT failed with return code: ', socket
RETURN
ENDIF
FOR i = 0,2 DO BEGIN
data = BYTE('Client String ' + STRTRIM(STRING(i),2))
PRINT, 'CLIENT sending: ', data
SOCKET_WRITE, socket, data
data = BYTARR(15)
nbytes = SOCKET_READ(socket,data)
PRINT, 'CLIENT received: ', STRING(data)
WAIT, 1
ENDFOR
SOCKET_CLOSE, socket
END
Running the Example
To run this example, do the following:
1. Copy the server program into a file called server.pro.
2. Copy the client program into a file called client.pro.
3. Start PV‑WAVE and enter the following command:
WAVE> .RUN server.pro
4. Start another PV‑WAVE session and enter the following command:
WAVE> .RUN client.pro
5. Start the server program in the server session window by typing server at the WAVE> prompt.
6. Start the client program in the client session window by typing client at the WAVE> prompt.
Client Program Output
In the client window, the following output appears:
CLIENT sending: 67 108 105 101 110 116 32 83 116 114 105 110 103 32 48
CLIENT received: Server String 0
CLIENT sending: 67 108 105 101 110 116 32 83 116 114 105 110 103 32 49
CLIENT received: Server String 1
CLIENT sending: 67 108 105 101 110 116 32 83 116 114 105 110 103 32 50
CLIENT received: Server String 2
Server Program Output
In the server window, the following output appears:
SERVER received: Client String 0
SERVER sent: 83 101 114 118 101 114 32 83 116 114 105 110 103 32 48
SERVER received: Client String 1
SERVER sent: 83 101 114 118 101 114 32 83 116 114 105 110 103 32 49
SERVER received: Client String 2
SERVER sent: 83 101 114 118 101 114 32 83 116 114 105 110 103 32 50
Writing a Continuously Running Server
In the previous example, the server program stops running after the client closes its socket connection. In some cases, you may want the server to continue running and to wait for new client connections.
The key to writing a continuously running server is to enclose the SOCKET_ACCEPT function and subsequent socket functions in an infinite loop.
In the following example, the previously discussed program server.pro is modified so that it does not exit after the client connection is closed. Instead, the program loops back to the SOCKET_ACCEPT statement and waits for another client connection.
PRO SERVER
port = 1500
socket = SOCKET_INIT(port)
WHILE 1 DO BEGIN
connection = SOCKET_ACCEPT(socket)
FOR i = 0,2 DO BEGIN
data = BYTARR(15)
nbytes = 0
nbytes = SOCKET_READ(connection,data)
IF nbytes GE 0 THEN BEGIN
PRINT, 'SERVER received: ', STRING(data)
data = BYTE('Server String ' + STRTRIM(STRING(i),2))
SOCKET_WRITE, connection, data
PRINT, 'SERVER sent: ', data
ENDIF ELSE BEGIN
PRINT,'SOCKET_READ returned an error: ', !ERR_STRING
PRINT,'Closing connection.'
GOTO, reconnect
ENDELSE
ENDFOR
reconnect:
SOCKET_CLOSE, connection
ENDWHILE
SOCKET_CLOSE, socket
END
Version 2017.0
Copyright © 2017, Rogue Wave Software, Inc. All Rights Reserved.