ONC+ Developer's Guide

Using Non-Blocking I/O

To use non-blocking I/O, configure a client handle using the CLSET_IO_MODE rpciomode_t* option of the clnt_control() function with the RPC_CL_NONBLOCKING argument. See the clnt_control(3NSL) man page for further information.

When the transport queue is full, the buffer is used. The buffer continues to be used until two criteria are fulfilled:

Requests then go directly to the transport queue until the queue is full. The default size of the buffer is 16 kbytes.

Note that the buffer is not emptied automatically. You must flush the buffer when it contains data.

When you chose the RPC_CL_NONBLOCKING argument of CLSET_IO_MODE, you have a choice of flush modes. You can specify either the RPC_CLBESTEFFORT_FLUSH or RPC_CL_BLOCKING_FLUSH argument to CLSET_FLUSH_MODE. You can also empty the buffer by sending a synchronous call, such as clnt_call(). See the clnt_control(3NSL) man page for further information.

If the buffer is full, an RPC_CANTSTORE error is returned to the client and the request is not sent. The client must send the message again later. You can find out or change the size of the buffer by using the CLSET_CONNMAXREC and CLGET_CONNMAXREC commands. To determine the size of all pending request stored in the buffer, use the CLGET_CURRENT_REC_SIZE command. For further information on these commands see the clnt_control(3NSL) man page.

The server does not confirm whether the request is received or processed. After a request enters a buffer, you can use clnt_control() to obtain information on the status of the request.

Using a simple counter with non-blocking I/O

The client.c file in the one-way messaging example is modified in this section to demonstrate how to use the non-blocking I/O mode. In this new file, client_nonblo.c, the I/O mode is specified as non-blocking with the RPC_CL_NONBLOCKING argument, the flush mode is chosen to be blocking by use of the RPC_CL_BLOCKING_FLUSH. The I/O mode and flush mode are invoked with CLSET_IO_MODE. When an error occurs RPC_CANT_STORE is returned to the client and the program tries to flush the buffer. To choose a different method of flush consult the clnt_control(3NSL) man page.

#include <stdio.h>
#include "counter.h"

main(int argc, char *argv[])
{
    CLIENT* clnt;
    enum clnt_stat result;
    char *server;
    int number;
    bool_t bres;
		/* 
		 * Choose the I/O mode and flush method to be used.
		 * The non-blocking I/O mode and blocking flush are 
		 * chosen in this example.
		 */
    int mode = RPC_CL_NONBLOCKING;
    int flushMode = RPC_CL_BLOCKING_FLUSH;

    if (argc != 3) {
			  fprintf(stderr, "usage: %s server_name number\n", argv[0]);
			  exit(1);
    }
    server = argv[1];
    number = atoi(argv[2]);

    clnt= clnt_create(server, COUNTERPROG, COUNTERVERS, "tcp");
    if (clnt == (CLIENT*) NULL) {
			  clnt_pcreateerror(server);
			  exit(1);
    }

		/* 
 	 * Use clnt_control to set the I/O mode. 
 	 * The non-blocking I/O mode is 
 	 * chosen for this example.
 	 */
    bres = clnt_control(clnt, CLSET_IO_MODE, (char*)&mode);
    if (bres)
	    /* 
		  * Set flush mode to blocking 
		  */
        bres = clnt_control(clnt, CLSET_FLUSH_MODE, (char*)&flushMode);

    if (!bres) {
        clnt_perror(clnt, "clnt_control");
        exit(1);
    }
		 /* 
 	  * Call the RPC services.
 	  */
    result = add_1(number, clnt);

    switch (result) {
    case RPC_SUCCESS:
        fprintf(stdout,"Success\n");
        break;
		/*
 	 * RPC_CANTSTORE is a new value returned to the 
		 * client when the buffer cannot store a request.
		 */
    case RPC_CANTSTORE:
        fprintf(stdout,"RPC_CANTSTORE error. Flushing ... \n");
		/*
		 * The buffer is flushed using the blocking flush method
		 */
			  bres = clnt_control(clnt, CLFLUSH, NULL);
        if (!bres) {
	    		   clnt_perror(clnt, "clnt_control");
			  }
        break;
    default:
			  clnt_perror(clnt, "call failed");
        break;
    }

    /* Flush */
    bres = clnt_control(clnt, CLFLUSH, NULL);
    if (!bres) {
			  clnt_perror(clnt, "clnt_control");
    }

    clnt_destroy(clnt);
    exit(0);
}