Because mainframe data is stored as EBCDIC and most other platforms store data as ASCII, it is normally the function of the mainframe program to handle the EBCDIC/ASCII conversions. IBM provides two routines to handle this function: EZACIC04 and EZACIC05. Lines 52 through 55 of Figure 3 show how these routines are called.
Closing the Connection
Once all data transfer has been performed, the program must close the socket using the CLOSE call. This will release all the storage acquired during the SOCKET call. Other than the socket number, there are no options with the CLOSE call that would normally be used. Lines 56 through 61 of Figure 3 show this type of call.
The programmer should be aware that a successful return from a CLOSE call does not indicate that all data transfer has completed. The IP stack will continue to transfer all data that may be queued for transmission to the other end of the conversation until the transfer is successful or fails. If it fails, there is no indication to the program that a failure occurred.
Finally, the program must disconnect from the IP software system using the TERMAPI call. Lines 62 through 64 of Figure 3 show this type of call. There are no options for this call. This is also the one call that does not have a retcode or errno field, as there are no errors possible with this type of call. Failure to perform the CLOSE or TERMAPI calls as needed will result in “partition GETVIS creep,” where excess partition storage continually decreases until no storage remains. Figure 11 shows the basic calls needed to create a client program.
Making It Better
The code I have discussed has one built-in problem. What happens if the server quits sending before the full receive is finished? The program will appear to “hang” forever during the RECV call. There are a couple of ways you can handle this. One option is to set the socket to “non-blocking” mode. In this mode, the receive will fail immediately if no data is available. The program is required to recognize a “would block” condition and perform another receive. This can use a lot of CPU time. Because of this, there is a better method you can use — the SELECT call. This call places the program in a wait condition until data is actually available, just like a RECV call, but with one exception. The SELECT call allows the programmer to pass a timeout value, that once exceeded, will cancel the wait and return an error to the program. Although a slight delay is still encountered, the length of the delay is controllable and will allow the program to terminate gracefully when the server fails to respond. Unfortunately, this call is more complicated than any of the other examples shown. Although the learning curve for a SELECT call may be steep, the rewards of using the call are well worth the effort. This call also allows the program to wait for multiple conditions on multiple sockets with one single socket call. Lines 65 through 96 of Figure 4 show an example of a SELECT call. Figure 12 shows the actual code that would be inserted into Figure 11 just prior to line 26.