12
Tue, Nov
5 New Articles

TCP/IP Socket Programming in RPG? Cool!

RPG
Typography
  • Smaller Small Medium Big Bigger
  • Default Helvetica Segoe Georgia Times

Build an RPG IV client/server function to remotely print a listing of library objects using TCP/IP socket functions written in C.

Prior to RPG IV, the RPG developer could not develop a TCP/IP socket program without using C or some other language that could bind to C functions. With RPG IV, you can now bind to C service program functions without having to resort to another language and licensing an additional compiler for the AS/400. This article will demonstrate the use of the C-based TCP/IP socket functions in RPG IV applications.

So, What Are TCP/IP Sockets Anyway?

The UNIX operating system was developed with a series of communication interfaces to make the operating system somewhat independent of the underlying network hardware, thus promoting interprocess communication, portability, and openness of applications. These interfaces thus promoted plug compatibility and became known as sockets. A socket is an endpoint connection for communications that can be named and addressed in a network. A socket is a unique number assigned to an interprocess connection and consists of a machine’s Internet Protocol (IP) address and the port number selected for the connection. Therefore, different machines can communicate on the same port since their IP addresses are different. Each machine in a connection has a socket number that uniquely identifies the machine at the other end of the connection. Through this socket number (also termed a socket descriptor), a machine sends data to and receives data from the other. Each function invoked after the socket function (the function that assigns the number) will use the socket descriptor to identify itself.

On the AS/400, the set of socket functions are available in the form of a service program, but on a PC they are available as a dynamic link library (DLL). The table in Figure 1 presents each socket function needed to complete a typical conversation between two processes. (For more information on how to bind C functions with RPG IV, see “Using C Functions in ILE RPG” in the November 1998 issue of MC.) As you can see in Figure 1, a server application needs to perform only a minimal set of the sockets functions: socket, set socket options (setsockopt), bind, listen, and accept. A client application needs to perform only two of the sockets functions: socket and connect.

Both the client and server can perform read and write functions for two-way communication. And both are required to close the connection to end the processes. Although the table in Figure 1 shows certain functions being invoked only by the server process, any of these functions may be invoked by the client as well, but that would indicate a role change between the two communicating processes.

Finding and Binding

To properly utilize socket functions, you need to become familiar with their arguments and return types. Most of the TCP/IP sockets function prototypes can be found in the member called SOCKET of the SYS source file in the QSYSINC library. The prototypes for the sockets read and write functions can be found in the QSYSINC library in the UNISTD member of the source file called H. The QSYSINC library is available as a free, optionally installable feature of the operating system (5769SS1: OS/400-System Openness Includes). The include headers are required to determine the number of arguments passed and their data types to be passed to the sockets functions (that are implemented in C) as well as values returned from these functions. Only when your application program has access to this information can it be successfully bound to the TCP/IP sockets functions.

Figure 2 presents a table of the function prototypes for the functions we will use for our sockets programs. With the proper C function prototypes in hand, you can map arguments passed and values returned to comparable data type definitions in RPG IV. I used the C prototypes to develop the comparable RPG D-spec prototypes (see Figure 3) for the socket functions that I will be using to implement this article’s example sockets application. The complete RPG copy code for the socket function prototypes can be downloaded from Midrange Computing’s Web site at www.midrangecomputing.com/mc/99/02. The name of that copy file is $SocketsH. It contains not only the RPG D-spec prototypes for the socket functions but also the TCP/IP constants that will be used as arguments to socket functions.

The TCP/IP Display Library (DSPLIB) Utility

To demonstrate the implementation of sockets in RPG IV, I contrived a small example application that allows users to list the objects of a library. The Display Library (DSPLIB) command would have been an easier approach, but the purpose of this simple application is as a TCP/IP tutorial. To implement this DSPLIB application, we will write a TCP/IP server application that will respond to a request by printing out the listing of a library. I’ll begin with the development of the server application, then I’ll wrap up by developing a client application.

The Server

For the server application to accomplish the task, it must be able to do the following:

• Create a socket with the application’s Start Socket Server (STRSKTSVR) command

• Set socket options
• Bind an IP address and port address for the host AS/400 to the socket
• Place the server in listening mode
• Accept connection requests
• Read data from the client socket descriptor
• Translate the library name from ASCII to EBCDIC
• Execute the DSPLIB OUTPUT(*PRINT) command
• Return the server to read new requests
• Return the server to accept new connection requests
• End the server in response to the application’s End Socket Server (ENDSKTSVR) command

The RPG D-spec prototypes for the socket functions that will be used to implement the DSPLIB server application are listed in Figure 3. The $SocketsH copy file is included in the RPG client program at compile time via the /COPY statement in Figure 4, Label A:

/COPY QRPGLESRC,$SocketsH

Figure 4, Label B presents the data structure that will contain the information necessary to bind to the socket created in Figure 4, Label E with the socket function execution. Label C of Figure 4 contains standalone field definitions for fields that will be used to support other functions in the application such as error handling, display library command execution, and data translation from ASCII to EBCDIC.

To begin the server application, it will need to create a socket to communicate to the client process, which it does at Figure 4, Label E with the following statement:

C EVAL SDID = Socket(AF_INET:SOCK_STREAM:UNUSED)

To create the socket , three arguments need to be specified:
1. The family protocol for which the socket will be created (Internet, SPX, SNA,
2. The type of data stream to be sent/received
3. The protocol for the data stream The AF_INET constant in the first argument informs the socket function that the address family of the socket is to be in the Internet domain. The SOCK_STREAM constant informs the socket function that the type of data stream is to be a byte-stream configuration. The third argument is set to zero with the constant called UNUSED, which tells the socket function to use the default protocol for data stream type specified in the second argument. In this case, since SOCK_STREAM was specified for the type, TCP is the default protocol.

In Figure 4, Label F, I will make the socket reusable for multiple client connections by setting the reuse indicator on, with the following:

C EVAL rc = SetSockOpt(SdId:SOL_SOCKET:
C SOL_REUSEADDR:%ADDR(On):%SIZE(On))

In Figure 4, Label G, I bind the IP address and the port that I have selected for the DSPLIB service to the socket ID created by the socket function at Label E:

C EVAL rc = Bind(SDID:%ADDR(serveraddr):
C svaddrlen)

Setting most of the values is a straightforward procedure of simply assigning the proper values to the proper data structure elements in the serveraddr socket structure. However, you must use another function, gethostid, to return the integer representation of the AS/400’s IP address (for example, 190.50.38.7 in this case). The prototype for this function is included in the $SocketsH member. And the following function shows how it is called:

C EVAL sin_addr = GetHostId

After the RPG server program binds to the socket, you now have a name to address the socket by, and using that socket address, your client process can request connection events. Figure 4, Label H shows how the server accepts connection requests by placing itself in listening mode:

etc.)

C EVAL rc = Listen(SdId:10)

Once this function has been executed, the RPG server program can execute the accept function as in Figure 4, Label I, to enable its services to a client program that has made a connection request:

C EVAL rc = Accept(SDID:%ADDR(serveraddr):%ADDR(
C svaddrlen))

Once a connection request by a client has been made and accepted by the server, the server can address the client through the socket descriptor of the client that was returned by the accept function execution.

In Figure 4, Label J, a call to the read function, is made using the socket descriptor of the client, which is addressable through the SdId2 variable:

C EVAL TotCharRead = Read(SdId2:%ADDR(Buffer):
C BufferLen)

That function passes a pointer to the buffer that will hold the data read-in and the length of the buffer. Completion of the read function is signaled when it has read the number of characters enumerated by the buffer length argument. The return value from the read function will be either the number of characters read (which should equal the buffer length), -1 (indicating a failed read), or zero (indicating a close socket signal from the client partner process). After a successful read, the data conversion (QDCXLATE) API will be called at Label K to convert the data from ASCII to EBCDIC so that the server application can continue to the next step of its service. In the code of Label L in Figure 4, I pass the translated library name to the command execution (QCMDEXC) API to print out the list of library objects. Then the RPG server program returns to the read function at Label J to restart the wait for another request from that client. If the client terminates the connection, the server branches to Label M of Figure 4 to close the socket for the client:

C Eval rc = Close(SdId2)

The code then loops back to the accept function at Label I, where it waits for a connection request from another client.

The only way the server process will end is through a client request to stop the server using the application’s End Socket Server (ENDSKTSVR) command. When such a request is made, all loops will be exited, and the socket close function for the server process will be executed, as shown at Label N of Figure 4, along with termination of the process.

The RPG IV Client

As stated earlier, a TCP/IP client/server application does not need to be on separate machines. TCP/IP enables communication between two processes on the same machine. Figure 5 illustrates the source code for a client process running on the AS/400 that is activated by the user submitting a request for a library to be printed with the command Send Socket Request (SNDSKTRQS) command (also available at MC’s Web site, at www.midrangecomputing.com/mc/99/02).

As with the server application, the client includes the $SocketsH copy file at Label A of Figure 5. At Label B of Figure 5, again we create a unique socket identifier with the Socket function:

C EVAL SdId = Socket(AF_INET:SOCK_STREAM:UNUSED)

Since this client will be running on the same AS/400, the socket address data structure is established with identical values that I set for the server application (i.e., same port, same IP address). There I used the gethostid function to retrieve the server’s IP address. If my client existed on a different AS/400 than the server application, I would need to set that address manually (because the gethostid function would retrieve the IP address for the client AS/400 not the server AS/400). In that case, you must overlay the field sin_addr, the unsigned integer field that is to contain the IP address with a 4-byte alphabetic field sin_addrA, to assign the hexadecimal equivalent of the 32-bit (or 4-byte octal values) of the IP address. For example, you cannot simply assign 190.50.38.7 to the sin_addr field because it is not a valid assignment. You need to convert each octet (190, 50, 38, 7) to its hexadecimal equivalent and assign it on that basis. The sin_addrA variable is set to the value X’BE322607’ in the commented code at Figure 4, Label G for the IP address of 190.50.38.7. Next, at Label C, of Figure 5, rather than doing a bind, as I did with the server application, I will use the Connect function to request a connection from the server application, which at this point will be waiting at the call to the sockets accept function:

C EVAL rc = Connect(SdId:%ADDR(serveraddr):
C svaddrlen)

Next, at Label D, I will translate the library name to its ASCII equivalent using a call to QDCXLATE, because the server application is expecting the name to be encoded as an ASCII value. Then, I will submit the request to the server with the Write, as shown at Label E:

C EVAL rc = Write(SdId:%ADDR(Buffer):BufferLen)

Finally, at Label F, after the request has been submitted, I will close the connection:

C Eval rc = Close(SdId)

In this section, we have dealt only with an AS/400 client process. There are some special considerations that you need to be aware of when interfacing the AS/400 server application with a PC client application. Those considerations are addressed in the Web companion to this article (see “TCP/IP Socket Programming in RGP? Cool!” at www.midrange computing.com/mc/99/02). You will also want to pay close attention to the “Gotchas and Miscellaneous!” sidebar to this article.

Compiling the TCP/IP Server and RPG IV Client To compile the TCP/IP Server and RPG IV client, use the following commands:

CRTBNDRPG PGM(YourLib/SKTSERVER) DFTACTGRP(*NO) +

ACTGRP(QILE) BNDDIR(QC2LE QUSAPIBD)

CRTBNDRPG PGM(YourLib/SKTCLIENT) DFTACTGRP(*NO) +

ACTGRP(QILE) BNDDIR(QC2LE QUSAPIBD)

The QC2LE binding directory contains all the service programs that makeup the standard C function library, and contains the __errno and strerror functions needed to retrieve the error information described in this article. These functions are located specifically in the QC2UTIL1 service program. The QUSAPIBD binding directory contains the service programs that comprise the socket functions demonstrated in this article. You will find most of the functions we have discussed in the QSOSRV1 service program in QSYS. The read, write, and close socket descriptor functions can be found in the QP0LLIB1 service program, also in the QUSAPIBD binding directory. Compile

instructions for the programs demonstrated in this application and commands used to start, stop, and send requests to the socket server application are detailed in the downloadable code on the Web.

Makes You Think...

Given what this article has presented, it makes you think what can now be accomplished by mixing languages in the ILE. Why re-create the wheel when another language, such as C or Java, already has the needed functionality built right in? It can no longer be taken for granted that RPG IV applications in the immediate and near future will naturally be purely RPG. This situation, in turn, will raise the expectations for RPG applications and the base requirement of skills and capabilities for the RPG IV developer. I think this is a good thing. And given a reported increased interest in certification programs for RPG/400 (“up 25 percent,” according to the June 29, 1998, issue of InfoWorld), apparently so do others.

Perhaps this will also give RPG developers more credibility in the eyes of IBM, a company that reportedly does not have a good opinion of typical RPG programmers and doesn’t think much of their skills and capabilities. According to sources inside IBM, the company feels that only a small segment of legacy AS/400 applications programmers will make the transition to fully object-oriented Java development. Additionally, the source stated that the company holds the opinion that legacy AS/400 programmers are strong business applications programmers, but poor computer scientists; conversely, UNIX programmers are strong computer scientists, but poor applications programmers. What do you think?

References

AS/400 System API Reference V4R2 (SC41-5801-01, CD-ROM QB3AMA01)

ILE C/400 Programmer’s Reference (V3R7 - SC09-2070-01, CD-ROM QBJAQY01; V4R2 - SC09-2514-00, CD-ROM QB3AG100)

OS/400 Sockets Programming V4R2 (SC41-5422-01, CD-ROM QB3ANN01)

OS/400 UNIX-Type APIs V4R2 (SC41-5875-01, CD-ROM QB3AM401)

Sockets Programming V4R1 (SC41-5422-00, CD-ROM QB3ANN00)

Gotchas and Miscellaneous!

If you experience a problem when your server application attempts to bind to your selected port on the AS/400, check the port restrictions for the port in question to determine if that port is restricted to a particular user profile. If it is, select another port (and don’t forget to change it in your applications) that does not have any restrictions. Avoid port numbers below 255, as these are typically reserved for various TCP/IP functions (23 for Telnet, 80 for HTTP, 20 for FTP...). You can review your AS/400 port restrictions by entering GO CFGTCP at the command line and selecting option 4 (Work with TCP/IP port restrictions).

Adding a port restriction is as simple as entering the Add TCP/IP Port Restriction (ADDTCPPORT) command, prompting with F4, and completing the parameters. You can review ports allocated by particular services by selecting option 21 (Configure related tables) at that same menu, then option 1 (Work with service table entries) at the subsequently presented menu.

You can add a service table entry for the server program developed in this article by entering the Add Service Table Entry (ADDSRVTBLE) command, prompting with F4, and completing the required parameters. While your server application is running, you can review TCP/IP connection status of the job by entering the Display the Work with TCP/IP Connection Status List (NETSTAT *CNN) command or by entering the Work with TCP/IP Network Status (WRKTCPSTS) command and selecting option 3 (Work with TCP/IP connection status). Either method presents the same information and can yield valuable information concerning your server application.

Socket Function Description Invoked By

socket() Creates a unique socket descriptor number Client & Server

setsockopt() Sets socket options Server

bind() Binds a socket to a particular IP address and port number Server

listen() Places a listener on the port specified by the bind function Server

accept() Accepts a connection request from another process Server

connect() Connects a client to the server endpoint specified in the socket address structure Client

read() Reads data using the socket descriptor returned by the accept function Client & Server

write() Writes data using the socket descriptor Client & Server

close() Closes the socket descriptor preventing further connection requests Client & Server

Figure 1: Socket functions

Function Function Prototype in C

socket() int socket_descriptor = socket(int address_family, int type, int protocol)

setsockopt() int return_code = setsockopt(int socket_descriptor, int level, int option_name, char *option_value, int option_length)

bind() int return_code = bind(int socket_descriptor, struct sockaddr *local_address, int address_length)

connect() int return_code = connect(int socket_descriptor, struct sockaddr *destination_address, int address_length)

listen() int return_code = listen(int socket_descriptor, int back_log)

accept() int return_code = accept(int socket_descriptor, struct sockaddr *address, int *address_length)

read() int #of_bytes_read = read(int socket_descriptor, void *buffer, int #of_bytes_to_read)

write() int #of_bytes_written = write(int socket_descriptor, const void* buffer, #of_bytes_to_write)

Figure 2: Socket function prototypes in C

D Socket PR 10i 0 ExtProc('socket')

D AF_INET 10i 0 Value

D SOCK_STREAM 10i 0 Value

D UNUSED 10i 0 Value

D SetSockOpt PR 10i 0 ExtProc('setsockopt')

D SocketDId 10i 0 Value

D SOL_SOCKET 10i 0 Value

D SOL_REUSEADDR 10i 0 Value

D PtrToOn * Value

D SizeOfOn 10u 0 Value

D Bind PR 10i 0 ExtProc('bind')

D SocketDId 10i 0 Value

D PtrToSAddr * Value

D AddrLen 10u 0 Value

D Listen PR 10i 0 ExtProc('listen')

D SocketDId 10i 0 Value

D NbrOfClients 10i 0 Value

D Accept PR 10i 0 ExtProc('accept')

D SocketDId 10i 0 Value

D PtrToSAddr * Value

D PtrToAddrSz * Value

D Read PR 10i 0 ExtProc('read')

D SocketDId 10i 0 Value

D PtrToBuffer * Value

D SizeToRead 10i 0 Value

D Write PR 10i 0 ExtProc('write')

D SocketDId 10i 0 Value

D PtrToBuffer * Value

D SizeToRead 10i 0 Value

D Connect PR 10i 0 ExtProc('connect')

D SocketDId 10i 0 Value

D PtrToSAddr * Value

D SizeOfAddr 10u 0 Value

D Close PR 10i 0 ExtProc('close')

D SocketDId 10i 0 Value

D GetHostId PR 10u 0 ExtProc('gethostid')

D $$Errno PR * ExtProc('__errno')

D StrError PR * ExtProc('strerror')

D Errno 10i 0 Value

** C MACROS (CONSTANTS)

*D AF_INET C Const(2)

D SOCK_STREAM C Const(1)

D UNUSED C Const(0)

D SOL_SOCKET C Const(-1)

D SOL_REUSEADDR C Const(55)

* Error numbers from QSYSINC/SYS/ERRNO

* 3401 Permission denied.

D EACCES C Const(3401)

* 3422 The type of socket is not supported in this protocol family.

D EAFNOSUPPORT C Const(3422)

* complete code available on www.midrangecomputing.com

Figure 3: Socket function prototypes in RPG IV

/COPY QRPGLESRC,$SocketsH
* SOCKET ADDRESS STRUCTURE (TCP AND UDP)
D serveraddr DS
D sin_family 5i 0
D sin_port 5u 0
D sin_addr 10u 0
D sin_addrA 4a OVERLAY(sin_addr)
D sin_zero 8a
D Miscellaneous DS
D DspError 4S 0 INZ
D DspErrorA 4A OVERLAY(DspError)

* Miscellaneous Standalone fields.
D Message S 80a Based(pMessage)
D MsgToDsply S 52a INZ
D Errno S 10i 0 Based(perrno)
D Command S 80a INZ
D CommandLen S 15p 5 INZ(80)
D svaddrlen S 10u 0 INZ
D On S 10u 0 INZ(1)
D SDID S 10i 0 INZ
D SDID2 S 10i 0 INZ
D TotCharRead S 10i 0 INZ
D rc S 10i 0 INZ(0)
D SockError S 40A INZ('**Error on Socket create')
D SetSError S 40A INZ('**Error on Socket set')
D BindError S 40A INZ('**Error on binding to socket')
D ListenError S 40A INZ('**Error on listening')
D AcceptError S 40A INZ('**Error on accepting requests')
D Buffer S 10A INZ
D DataLen S 5P 0 INZ
D XLateTable S 10A INZ
D XLateTblLib S 10A INZ
* CONSTANTS A

B

C

D Dsplib C Const('DSPLIB LIB(')
D OutPut C Const(') OUTPUT(*PRINT)')
D BufferLen C Const(10)
* Create a socket descriptor for the server process to bind.
C EVAL SDID = Socket(AF_INET:SOCK_STREAM:UNUSED)
C IF (SDID < 0 )
C EVAL perrno = $$Errno
*

C SELECT
C WHEN Errno = EACCES
C Error3401 DSPLY

{ Do some special processing here}
C WHEN Errno = EAFNOSUPPORT
C Error3422 DSPLY

{ Do some special processing here}
C OTHER
C EVAL DspError = Errno
C EVAL pMessage = StrError(Errno)
C EVAL MsgToDsply = DspErrorA + ' ' + Message
C MsgToDsply DSPLY
C ENDSL
C SockError DSPLY
*

C EVAL *INLR = *ON
C RETURN
C ENDIF

*--------- Set socket descriptor to be reuseable.
C EVAL rc = SetSockOpt(SdId:SOL_SOCKET:
C SOL_REUSEADDR:%ADDR(On):%SIZE(On))
C IF (rc < 0 )
C EVAL perrno = $$Errno
C EVAL DspError = Errno
C EVAL pMessage = StrError(Errno)
C EVAL MsgToDsply = DspErrorA + ' ' + Message
C MsgToDsply DSPLY
C SetSError DSPLY
C EVAL *INLR = *ON
C RETURN
C ENDIF

*

*--------- Bind server IP & port to socket descriptor.
*

C EVAL sin_family = AF_INET
C EVAL sin_port = 3005

* replace X'be322607' with your as/400's ip or use gethostid function if client is
* on the same as400 as the server.
C******* OR EVAL sin_addrA = X'BE322607'
C EVAL sin_addr = GetHostId
C EVAL sin_zero = X'0000000000000000'
C EVAL svaddrlen = %SIZE(serveraddr)
C EVAL rc = Bind(SDID:%ADDR(serveraddr):
C svaddrlen)
C IF (rc < 0 )
C EVAL perrno = $$Errno
C EVAL DspError = Errno
C EVAL pMessage = StrError(Errno)
C EVAL MsgToDsply = DspErrorA + ' ' + Message
C MsgToDsply DSPLY
C BindError DSPLY
C EVAL *INLR = *ON
C RETURN
C ENDIF
*--------- willingness to accept connection requests.
C EVAL rc = Listen(SdId:10)

C IF (rc < 0 )
C EVAL perrno = $$Errno
C EVAL DspError = Errno
C EVAL pMessage = StrError(Errno)
C EVAL MsgToDsply = DspErrorA + ' ' + Message
C MsgToDsply DSPLY
C ListenError DSPLY
C EVAL *INLR = *ON
C RETURN
C ENDIF
*--------- Accept new connection requests. If rc is greater than zero,
*--------- the returned value is the socket descriptor identifier for
*--------- the client partner that requested the current connection.
C DOW ( Buffer <> '*STOPSVR' )
C EVAL rc = Accept(SDID:%ADDR(serveraddr):%ADDR(
C svaddrlen))
C IF ( rc < 0 )
C EVAL perrno = $$Errno
C EVAL DspError = Errno
C EVAL pMessage = StrError(Errno)
C EVAL MsgToDsply = DspErrorA + ' ' + Message
C MsgToDsply DSPLY
C AcceptError DSPLY
C EVAL *INLR = *ON
C RETURN
C ELSE
C EVAL SdId2 = rc
C ENDIF

C DOW ( rc > 0 )

*--------- Read from socket descriptor of accepted connection request
*--------- above.
C EVAL TotCharRead = *ZERO
C EVAL TotCharRead = Read(SdId2:%ADDR(Buffer):
C BufferLen)
*--------- Convert buffer data to EBCDIC to simulate source as a
*--------- PC client (ASCII Data).
C IF ( TotCharRead > *ZERO )
C CALL 'QDCXLATE' 68
C PARM BufferLen DataLen
C PARM Buffer
C PARM 'QEBCDIC' XLateTable
C PARM 'QSYS' XLateTblLib

C IF ( *IN68 = *OFF AND Buffer <> '*STOPSVR')
C EVAL Command = Dsplib + Buffer + OutPut
C CALL 'QCMDEXC' 68
C PARM Command
C PARM CommandLen
C ELSE
C Eval rc = Close(SdId2)
C LEAVE
C ENDIF

C ELSE
C Eval rc = Close(SdId2)
C LEAVE
C ENDIF
C ENDDO
C ENDDO

C Eval rc = Close(SdId)
C EVAL *INLR = *ON
C RETURN

D

E

F

G

I

J

K

L

M

N

H

Figure 4: Socket server source

A

B

C D

E

F

/COPY SYSINC,$SocketsH

C *Entry PList

C Parm Request

C EVAL Buffer = Request

*--------- Create a socket descriptor for the client process to

*--------- make a connection with.

C EVAL SdId = Socket(AF_INET:SOCK_STREAM:UNUSED)

C IF (SdId < 0 )

C EVAL perrno = $$Errno

C EVAL DspError = Errno

C EVAL pMessage = StrError(Errno)

C EVAL MsgToDsply = DspErrorA + ' ' + Message

C MsgToDsply DSPLY

C SockError DSPLY

C EVAL *INLR = *ON

C RETURN

C ENDIF

*--------- Connect to server process with client socket descriptor.

C EVAL sin_family = AF_INET

C EVAL sin_port = 3005

C EVAL sin_addrA = X'BE322607'

C EVAL sin_zero = X'0000000000000000'

C EVAL svaddrlen = %SIZE(serveraddr)

C EVAL rc = Connect(SdId:%ADDR(serveraddr):

C svaddrlen)

C IF (rc < 0 )

C EVAL perrno = $$Errno

C EVAL DspError = Errno

C EVAL pMessage = StrError(Errno)

C EVAL MsgToDsply = DspErrorA + ' ' + Message

C MsgToDsply DSPLY

C ConnectError DSPLY

C EVAL *INLR = *ON

C RETURN

C ENDIF

*--------- Convert buffer data to ASCII to simulate source as a

*--------- PC client. The server will convert it to EBCDIC before

*--------- executing DSPLIB OUTPUT(*PRINT) command.

C CALL 'QDCXLATE' 68

C PARM BufferLen DataLen

C PARM Buffer

C PARM 'QASCII' XLateTable

C PARM 'QSYS' XLateTblLib

*--------- Write library name to buffer.

C IF *IN68 = *OFF

C EVAL rc = Write(SdId:%ADDR(Buffer):BufferLen)

C ENDIF

*--------- Close the socket descriptor.

C Eval rc = Close(SdId)

C RETURN

Figure 5: Socket client source

BLOG COMMENTS POWERED BY DISQUS

LATEST COMMENTS

Support MC Press Online

$

Book Reviews

Resource Center

  • SB Profound WC 5536 Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application. You can find Part 1 here. In Part 2 of our free Node.js Webinar Series, Brian May teaches you the different tooling options available for writing code, debugging, and using Git for version control. Brian will briefly discuss the different tools available, and demonstrate his preferred setup for Node development on IBM i or any platform. Attend this webinar to learn:

  • SB Profound WP 5539More than ever, there is a demand for IT to deliver innovation. Your IBM i has been an essential part of your business operations for years. However, your organization may struggle to maintain the current system and implement new projects. The thousands of customers we've worked with and surveyed state that expectations regarding the digital footprint and vision of the company are not aligned with the current IT environment.

  • SB HelpSystems ROBOT Generic IBM announced the E1080 servers using the latest Power10 processor in September 2021. The most powerful processor from IBM to date, Power10 is designed to handle the demands of doing business in today’s high-tech atmosphere, including running cloud applications, supporting big data, and managing AI workloads. But what does Power10 mean for your data center? In this recorded webinar, IBMers Dan Sundt and Dylan Boday join IBM Power Champion Tom Huntington for a discussion on why Power10 technology is the right strategic investment if you run IBM i, AIX, or Linux. In this action-packed hour, Tom will share trends from the IBM i and AIX user communities while Dan and Dylan dive into the tech specs for key hardware, including:

  • Magic MarkTRY the one package that solves all your document design and printing challenges on all your platforms. Produce bar code labels, electronic forms, ad hoc reports, and RFID tags – without programming! MarkMagic is the only document design and print solution that combines report writing, WYSIWYG label and forms design, and conditional printing in one integrated product. Make sure your data survives when catastrophe hits. Request your trial now!  Request Now.

  • SB HelpSystems ROBOT GenericForms of ransomware has been around for over 30 years, and with more and more organizations suffering attacks each year, it continues to endure. What has made ransomware such a durable threat and what is the best way to combat it? In order to prevent ransomware, organizations must first understand how it works.

  • SB HelpSystems ROBOT GenericIT security is a top priority for businesses around the world, but most IBM i pros don’t know where to begin—and most cybersecurity experts don’t know IBM i. In this session, Robin Tatam explores the business impact of lax IBM i security, the top vulnerabilities putting IBM i at risk, and the steps you can take to protect your organization. If you’re looking to avoid unexpected downtime or corrupted data, you don’t want to miss this session.

  • SB HelpSystems ROBOT GenericCan you trust all of your users all of the time? A typical end user receives 16 malicious emails each month, but only 17 percent of these phishing campaigns are reported to IT. Once an attack is underway, most organizations won’t discover the breach until six months later. A staggering amount of damage can occur in that time. Despite these risks, 93 percent of organizations are leaving their IBM i systems vulnerable to cybercrime. In this on-demand webinar, IBM i security experts Robin Tatam and Sandi Moore will reveal:

  • FORTRA Disaster protection is vital to every business. Yet, it often consists of patched together procedures that are prone to error. From automatic backups to data encryption to media management, Robot automates the routine (yet often complex) tasks of iSeries backup and recovery, saving you time and money and making the process safer and more reliable. Automate your backups with the Robot Backup and Recovery Solution. Key features include:

  • FORTRAManaging messages on your IBM i can be more than a full-time job if you have to do it manually. Messages need a response and resources must be monitored—often over multiple systems and across platforms. How can you be sure you won’t miss important system events? Automate your message center with the Robot Message Management Solution. Key features include:

  • FORTRAThe thought of printing, distributing, and storing iSeries reports manually may reduce you to tears. Paper and labor costs associated with report generation can spiral out of control. Mountains of paper threaten to swamp your files. Robot automates report bursting, distribution, bundling, and archiving, and offers secure, selective online report viewing. Manage your reports with the Robot Report Management Solution. Key features include:

  • FORTRAFor over 30 years, Robot has been a leader in systems management for IBM i. With batch job creation and scheduling at its core, the Robot Job Scheduling Solution reduces the opportunity for human error and helps you maintain service levels, automating even the biggest, most complex runbooks. Manage your job schedule with the Robot Job Scheduling Solution. Key features include:

  • LANSA Business users want new applications now. Market and regulatory pressures require faster application updates and delivery into production. Your IBM i developers may be approaching retirement, and you see no sure way to fill their positions with experienced developers. In addition, you may be caught between maintaining your existing applications and the uncertainty of moving to something new.

  • LANSAWhen it comes to creating your business applications, there are hundreds of coding platforms and programming languages to choose from. These options range from very complex traditional programming languages to Low-Code platforms where sometimes no traditional coding experience is needed. Download our whitepaper, The Power of Writing Code in a Low-Code Solution, and:

  • LANSASupply Chain is becoming increasingly complex and unpredictable. From raw materials for manufacturing to food supply chains, the journey from source to production to delivery to consumers is marred with inefficiencies, manual processes, shortages, recalls, counterfeits, and scandals. In this webinar, we discuss how:

  • The MC Resource Centers bring you the widest selection of white papers, trial software, and on-demand webcasts for you to choose from. >> Review the list of White Papers, Trial Software or On-Demand Webcast at the MC Press Resource Center. >> Add the items to yru Cart and complet he checkout process and submit

  • Profound Logic Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application.

  • SB Profound WC 5536Join us for this hour-long webcast that will explore:

  • Fortra IT managers hoping to find new IBM i talent are discovering that the pool of experienced RPG programmers and operators or administrators with intimate knowledge of the operating system and the applications that run on it is small. This begs the question: How will you manage the platform that supports such a big part of your business? This guide offers strategies and software suggestions to help you plan IT staffing and resources and smooth the transition after your AS/400 talent retires. Read on to learn: