You're probably already familiar with the concept of using TCP/IP sockets to communicate between a client and a server application. You may even have a socket server application on your iSeries now that communicates with client apps running on another iSeries or PC. In this article, I'll explain what it takes to create a client/server socket-based application that allows an Active Server Page .NET (ASP.NET) application to communicate with the iSeries.
Socket to Me
I'll start by taking a look at what TCP/IP sockets are
and how they work. All applications running over TCP/IP communicate through the
use of sockets. Sockets allow you to identify individual server applications at
a specific IP address. Think of it this way: If you were comparing TCP/IP
applications to a standard telephone call, the server's IP address would be the
phone number, and the socket (or port number) would be the telephone extension.
When people call your office, they probably dial a main number that gets them to
a receptionist or automated attendant that can transfer them to your phone by
identifying an extension. A TCP/IP server application simply waits in "listen"
mode for a client application to try to connect to it. Once a connection is
made, the server application will send data back and forth to the client until
the socket is closed. On the client side, the socket is defined using the
server's IP address and port number. The client application will then connect to
the server and send data back and forth until the connection is closed. Figure
1 shows a graphic example of how typical client and server socket applications
interact with each other.
Figure 1: This illustration shows how socket applications communicate. (Click images to enlarge.)
As I mentioned, all TCP/IP applications communicate using
sockets. When you connect to a Web server on the Internet, your browser acts as
the client and connects to port 80 on the server. When you connect to an FTP
server running on the iSeries, your PC's FTP command is the client and is able
to communicate with the iSeries FTP server through port 21. When you use iSeries
Access to start a terminal session on the iSeries, PC5250 acts as the client and
communicates with the iSeries server over port 23. There are many ports like
these that are used for standard applications. The table in figure 2 contains a
list of ports used by TCP/IP applications.
Port Number
|
Description
|
13
|
Network Time Protocol (NTP)
|
21
|
File Transfer Protocol (FTP)
|
23
|
Telnet Protocol
|
25
|
Simple Mail Transfer Protocol (SMTP)
|
53
|
Domain Name Service (DNS)
|
80
|
Hypertext Transfer Protocol (HTTP)
|
119
|
Network News Transfer Protocol (NNTP)
|
161
|
Simple Network Management Protocol (SNMP)
|
443
|
Hypertext Transfer Protocol over SSL (HTTPS)
|
563
|
Network News Transfer Protocol over SSL
(NNTPS)
|
Figure 2: This table lists some commonly used TCP/IP
ports.
When you are creating a custom socket application, it's best
to avoid using any of these "well-known" port numbers to prevent conflicts with
any of these applications.
ASPX to iSeries
The big draw to creating socket-based applications is
that they allow applications written in different languages and running on
different platforms to communicate with one another. This means that a socket
server that is running on a Linux box can accept connections from and
communicate with a client application running on Windows or even on the iSeries.
To illustrate this, I've created a sample socket server application running on
the iSeries that will interact with an ASP.NET client application.
First, take a look at the iSeries server application. This sample
application will accept an iSeries user ID and return the TEXT value from the
corresponding user profile. Figure 3 contains the ILE RPG source code for the
socket server application.
|
Figure 3: This is the ILE RPG socket server application.
This
application uses the copy file source member RPGSOCKCPY, which is included with
this article's source code.
This member defines the prototypes for the functions used within the program as
well as the constants used here. The functions defined here are contained within
the QC2LE binding directory, which gives you access to C functions from within
an ILE application. Figure 4 contains a list of the functions used here along
with a description of their use.
Function
|
Returns
|
Description
|
Socket()
|
Socket Identifier
|
Creates a new socket
|
SetSockOpt()
|
Status Code
|
Sets options for the defined socket
|
Bind()
|
Status Code
|
Binds to the specified socket (port)
|
Listen()
|
Status Code
|
Waits for a connection request on the defined
socket
|
Accept()
|
Incoming Socket ID
|
Accepts an incoming connection attempt
|
Read()
|
Characters Read
|
Reads in characters from the specified
socket
|
Write()
|
Status Code
|
Writes data back to the client
|
Close()
|
Status Code
|
Ends the client connection
|
Figure 4: The functions listed here are used to create the socket server
application.
As the table above explains, the socket() function
creates a new socket. The socket identifier value returned when the function is
called is used to identify the socket in the functions that follow. The first
parameter supplied here is used to define the address family. AF_INET identifies
that the address specified uses Internet Protocol (IP). The second parameter
identifies the type of socket being defined. The SOCK_STREAM constant identifies
that type to be socket streaming (TCP) protocol. The final option defines the
protocol to be used with the socket. Since the other two parameters have defined
that, set this option to UNUSED to cause the default for this value to be used.
The SetSockOpt() function defines options related to the socket. The
first parameter on this function is socket ID of the socket created with the
socket() function. The second parameter identifies the level at which the
option is being set. Data communications using TCP/IP are processed on multiple
levels or layers. The IP layer handles the lower-level network communications.
This application uses the TCP layer to send data back and forth. In this case,
the constant SOL_SOCKET identifies that the option being defined is at the
socket level. The next parameter identifies the option being changed. In this
case, the constant identifies that the socket definition is to be reusable. The
next two parameters define the option data and the length of that
data.
The bind() function binds the socket identifier defined on the
first parameter to the IP address and port identified through the
serveraddr variable. In this example, the IP address will be the IP
address of your iSeries as returned by the GetHostId function. The port number
is defined as 2834. The third parameter for the bind function is used to
identify the length of the values stored in the serveraddr variable.
The listen() function instructs the program to wait for a connection
attempt on the socket defined by the socket identifier on the first parameter.
The second parameter defines the number of connections to be accepted at one
time. Program execution will stall at this statement until a client application
attempts to make a connection to this socket.
The accept() function is
executed once a connection attempt is made. This function accepts the same three
parameters used for the bind() function: the socket ID, the server address, and
the length of the server address value. The value returned by this function
uniquely identifies each of the possible incoming connections for future
statements.
The read() function reads data coming in through the socket.
The first parameter is the socket identifier returned by the accept() function.
The second parameter is the pointer to the BufferIn variable, which will contain
the incoming data. This function returns a value that contains the number of
characters read into the BufferIn variable. The sample application then uses the
QDCXLATE API to convert the incoming data from ASCII to EBCDIC. The value from
BufferIn, which should contain an iSeries user ID, is then sent to the CL
program GetUserName. This program uses RTVUSRPRF to retrieve the TEXT value
related to the user profile. This value is sent back to the client socket
application. The QDCXLATE API is again used to translate the EBCDIC data back to
ASCII.
The write() function returns data to the client application. The
first parameter used with this function is the socket ID created by the accept()
function. The second parameter is the pointer to the BufferOut variable,
which contains the outgoing data. The third parameter defines the length of the
outgoing data. The sample application continues this process until there is no
more data to be read in. At that point, the remote socket is closed.
The
close() function ends the socket. The single parameter on this function is the
socket identifier for the socket to be closed. In this sample application, both
the primary socket identifier and the secondary identifiers that relate to each
client connection are used along with this function.
The server
application will remain active until it receives a value of *END from the
client. At that point, the server application will close the socket and end. Use
the CRTBNDRPG program to create this program, as shown here:
You'll also need to create the CL Program GETUSRNAME, which can be found
with this article's companion code.
Now that the socket server
application is in place, I'll explain what you need to do on the client side.
ASP.NET Socket Client
If you're unfamiliar with ASP.NET, let me explain:
This extension to Microsoft's Internet Information Server (IIS) is part of the
.NET (that's "dot net") framework, which can be downloaded from Microsoft's web
site here.
ASP.NET extends Microsoft's Active Server Pages (ASP) by extending the language
options available. Within ASP, you have the option of using Visual Basic
Scripting (VBScript) language or JavaScript. ASP.NET supports any language that
is compliant with the .NET framework. This currently includes Visual Basic.NET,
Visual C#, Visual C++, and Visual J#. Once you have downloaded the .NET
framework from the link above, install the framework on a machine running
Microsoft IIS. This sample client application allows the user to key in an
iSeries user ID and receive back the corresponding user's name. Figure 5
contains the source for the Web page that contains the client
application.
|