z/OS Communications Server: IP Sockets Application Programming Interface Guide and Reference
Previous topic | Next topic | Contents | Contact z/OS | Library | PDF


Selecting requests in a concurrent server program

z/OS Communications Server: IP Sockets Application Programming Interface Guide and Reference
SC27-3660-00

At this point in the process, the server is ready to handle requests on this port from any client on a network from which the server is accepting connections. Until this point however, it had been assumed that the server was handling one socket only. Now, an application is not limited to one socket. Typically, a server listens for clients on a particular socket, but it allocates a new socket for each client it handles. For maximum performance, a server should operate only on those sockets ready for communication. The select() call allows an application to test for activity on a group of sockets.

To test any number of sockets with one call to select(), place the sockets to test into a bit set, passing the bit set to the select() call. A bit set is a string of bits where each member of the set is represented by 0 or 1. If the members bit is 0, the member is not in the set; if the members bit is 1, the member is in the set. For example, if socket 3 is a member of a bit set, then bit 3 is set; otherwise, bit 3 is cleared.

In C language, the following functions are used to manipulate the bit sets:
FD_SET
Sets the bit corresponding to a socket.
FD_ISSET
Tests whether the bit corresponding to a socket is set or cleared.
FD_ZERO
Clears the entire bit set.
If a socket is active, it is ready for read or write data. If the socket is not active, an exception condition might have occurred. Therefore, the server specifies three bit sets of sockets in its call to the select() call as follows:
  • One bit set for sockets on which to receive data
  • One bit set for sockets on which to write data
  • Any sockets with exception conditions
The select() call tests each socket in each bit set for activity and returns only those sockets that are active.

A server that processes many clients at once can be written to process only those clients that are ready for activity.

When all initialization is complete, and the server main process is ready to enter normal work, it builds a bit mask for a select() call. The select() call is used to test pending activity on a list of socket descriptors owned by this process. Before issuing the select() call, construct three bit strings representing the sockets you want to test, as follows:
  • Pending read activity
  • Pending write activity
  • Pending exceptional activity

The length of a bit string must be expressed as a number of fullwords. If the highest socket descriptor you want to test is socket descriptor number 3, you must pass a 4-byte bit string, because this is the minimum length. If the highest number is 32, you must pass 8 bytes (2 fullwords).

The number of fullwords in each select mask can be calculated as follows:
INT(highest socket descriptor / 32) + 1

Table 1 shows the first fullword passed using a bit string.

Table 1. First fullword passed in a bit string select()
Socket descriptor numbers represented by byte Bit 0 Bit 1 Bit 2 Bit 3 Bit 4 Bit 5 Bit 6 Bit 7
Byte 0 31 30 29 28 27 26 25 24
Byte 1 23 22 21 20 19 18 17 16
Byte 2 15 14 13 12 11 10 9 8
Byte 3 7 6 5 4 3 2 1 0

Using standard assembler numbering notation, the leftmost bit or byte is relative to 0.

If you want to test socket descriptor number 5 for pending read activity, you raise bit 2 in byte 3 of the first fullword (X'00000020'). To test both socket descriptors 4 and 5, raise both bit 2 and bit 3 in byte 3 of the first fullword (X'00000030').To test socket descriptor Number 32, pass 2 fullwords, where the numbering scheme for the second fullword resembles that of the first. Socket descriptor Number 32 is bit 7 in byte 3 of the second fullword. To test socket descriptors Number 5 and Number 32, pass 2 fullwords with the following content: X'0000002000000001'. The bits in the second fullword represent the socket descriptor numbers shown in Table 2.

Table 2. Second fullword passed in a bit string using select()
Socket descriptor numbers represented by byte Bit 0 Bit 1 Bit 2 Bit 3 Bit 4 Bit 5 Bit 6 Bit 7
Byte 4 63 62 61 60 59 58 57 56
Byte 5 55 54 53 52 51 50 49 48
Byte 6 47 46 45 44 43 42 41 40
Byte 7 39 38 37 36 35 34 33 32

Subsequent mask words continue this pattern; word 3 for sockets 64-95, word 4 for sockets 96-127, and so on.

To set and test these bits in another way, use the following assembler macro, found in file SEZACMAC:

.********************************************************************
.*                                                                  *
.* Part Name:          TPIMASK                                      *
.*                                                                  *
.* SMP/E Distribution Name:  EZABCTPI                               *
.*                                                                  *
.* Component Name:     SOK                                          *
.*                                                                  *
.* Copyright:    Licensed Materials - Property of IBM               *
.*               This product contains "Restricted Materials of IBM"*
.*               5645-001 5655-HAL (C) Copyright IBM Corp. 1996.    *
.*               All rights reserved.                               *
.*               US Government Users Restricted Rights -            *
.*               Use, duplication or disclosure restricted by       *
.*               GSA ADP Schedule Contract with IBM Corp.           *
.*               See IBM Copyright Instructions.                    *
.*                                                                  *
.* Status:             TCP/IP for MVS                               *
.*                                                                  *
.* Function:           Macro used to set or test bits in the        *
.*                     read, write and exception masks used         *
.*                     in the SELECT/SELECTEX macro or calls.       *
.*                                                                  *
.* Part Type:          MACRO - assembler                            *
.*                                                                  *
.* Usage:                                                           *
.*                     TPIMASK SET,MASK=READMASK,SD=SOCKDESC        *
.*                          or TEST, or WRITEMASK,                  *
.*                                   or EXCEPTMASK,                 *
.*                                                                  *
.*                     SET  - Set the SD bit on in MASK             *
.*                     TEST - Test SD bit in MASK for on/off        *
.*                            Follow the macro invocation with:     *
.*                            BE (Branch Equal) - Bit was on        *
.*                            BNE (Branch Not Equal) - Bit was off  *
.*                                                                  *
.* Change Activity:                                                 *
.* CFD List:                                                        *
.*                                                                  *
.* $xn= workitem  release  date  pgmr:  description                 *
.*                                                                  *
.* End CFD List:                                                    *
.*                                                                  *
.********************************************************************
         MACRO
         TPIMASK &TYPE,        SET or TEST bit setting                 X
               &MASK=,         Read, Write or Except array             X
               &SD=            Socket descriptor TOR PARAMETER
         SR    14,14           Clear Reg14
         AIF   ('&SD'(1,1) EQ '(').SDREG
         LH    15,&SD          Get Socket Descriptor
         AGO   .SDOK
.SDREG ANOP
         LR    15,&SD          Get Socket Descriptor
.SDOK ANOP
         D     14,=A(32)       Divide by 32, R15 = word bit is in
         SLL   15,2            Multiply word by word length: 4
         AIF   ('&MASK'(1,1) EQ '(').MASKREG
         LA    1,&MASK         Mask starts here
         AGO   .MASKOK
.MASKREG ANOP
         LR    1,&MASK         Mask starts here
.MASKOK  ANOP
         AR    15,1            Increment to word bit is in
         LA    1,1             Set rightmost bit on
         SLL   1,0(14)         Shift left remainder from division
         O     1,0(15)         Or with word from mask
         AIF   ('&TYPE' EQ 'SET').DOSET
         C     1,0(15)         If equal, bit was set on
         MEXIT
.DOSET ANOP
         ST    1,0(15)         Update new mask after SET
         MEND
Figure 1. To set/test bits for SELECT calls

If you develop your program using another programming language, you might be able to benefit from the EZACIC06 routine, which is provided as part of TCP/IP Services. This routine translates between a character string mask (1 byte per flag) and a bit string mask (1 bit per flag). If you use the select() call in COBOL, EZACIC06 can be very useful.

Build the three bit strings for the socket descriptors you want to test, and the select() call passes back three corresponding bit strings with bits raised for those of the tested socket descriptors with activity pending. Test the socket descriptors using the following sample:
*---------------------------------------------------------------------*
* Test for socket descriptor activity with the SELECT call            *
*---------------------------------------------------------------------*
         EZASMI TYPE=SELECT,       *Select call                        C
               MAXSOC=TPIMMAXD,    *Max. this many descr. to test      C
               TIMEOUT=SELTIMEO,   *One hour timeout value             C
               RSNDMSK=RSNDMASK,   *Read mask                          C
               RRETMSK=RRETMASK,   *Returned read mask                 C
               WSNDMSK=WSNDMASK,   *Write mask                         C
               WRETMSK=WRETMASK,   *Returned write mask                C
               ESNDMSK=ESNDMASK,   *Exception mask                     C
               ERETMSK=ERETMASK,   *Returned exception mask            C
               ECB=ECBSELE,        *Post this ECB when activity occurs C
               ERRNO=ERRNO,        *- ECB points to an ECB plus 100    C
               RETCODE=RETCODE,    *- bytes of workarea for socket     C
               ERROR=EZAERROR      *- interface to use.
         ICM   R2,15,RETCODE       *If Retcode < zero it is
         BM    EZAERROR            *- an error
*
SELMASKS DS    0F
RSNDMASK DC    XL8'00000000'       *Read mask
RRETMASK DC    XL8'00000000'       *Returned read mask
WSNDMASK DC    XL8'00000000'       *Write mask
WRETMASK DC    XL8'00000000'       *Returned write mask
ESNDMASK DC    XL8'00000000'       *Exception mask
ERETMASK DC    XL8'00000000'       *Returned exception mask
*
NOSELCD  DC    A(0)                *Keep track of selected sd's
SELTIMEO DC    A(3600,0)           *One hour timeout
ECBSELE  DC    A(0)                *Select ECB
         DC    100X'00'            *Required by EZASMI
*
TPIMMAXD DC    AL4(50)             *Maximum descriptor number
*
ERRNO    DC    A(0)                *Error number from EZASMI
RETCODE  DC    A(0)                *Returncode from EZASMI
In the above select() call, the asynchronous facilities of the socket assembler macro interface is used. By placing an ECB parameter on the EZASMI macro call, the select() call does not block the process; we receive control immediately, even if none of the specified socket descriptors had activity. Use this technique to enter a wait, which waits for a series of events of which the completion of a select() call is just one. In the sample application, the main process was placed into a wait from which it would return when any of the following events occurred:
  • Socket descriptor activity occurred, and the select() call was posted.
  • One of your subtasks terminated unexpectedly.
  • The MVS™ operator issued a MODIFY command to stop the server.

The number of socket descriptors with pending activity is returned in the RETCODE field. You must process all selected socket descriptors before you issue a new select() call. A selected socket descriptor is selected only once.

When a connection request is pending on the socket for which the main process issued the listen() call, it is reported as a pending read.

When the main process has given a socket, and the subtask has taken the socket, the main process socket descriptor is selected with an exception condition. The main process is expected to close the socket descriptor when this happens.

Applications can handle multiple sockets. In such situations, use the select() call to determine the sockets that have data to be read, those that are ready for data to be written, and the sockets that have pending exceptional conditions. An example of how the select() call is used is shown in Figure 2.
Figure 2. An application using the select() call
fd_set readsocks;
fd_set writesocks;
fd_set exceptsocks;
struct timeval timeout;
int number_of_sockets;
int number_found;
⋮
/* set bits in read write except bit masks.
* To set mask for a descriptor’s use
* FD_SET(s, &readsocks)
* FD_SET(s, &writesocks)
* FD_SET(s, &exceptsocks)
*
* set number of sockets to be checked (plus 1)
* number_of_sockets = x;
*/
⋮
number_found = select(number_of_sockets,
          &readsocks, &writesocks, &exceptsocks, &timeout)
 

In this example, the application uses bit sets to indicate that the sockets are being tested for certain conditions, and also indicates a timeout. If the timeout parameter is NULL, the call does not wait for any socket to become ready. If the timeout parameter is nonzero, the select() call waits for the amount of time required for at least one socket to become ready under the indicated condition. This process is useful for applications servicing multiple connections that cannot afford to block, thus waiting for data on one connection. For a description, see select().

Go to the previous page Go to the next page




Copyright IBM Corporation 1990, 2014