Skip Navigation Links | |
Exit Print View | |
ONC+ Developer's Guide Oracle Solaris 11.1 Information Library |
1. Introduction to ONC+ Technologies
4. Programmer's Interface to RPC
5. Advanced RPC Programming Techniques
6. Porting From TS-RPC to TI-RPC
7. Multithreaded RPC Programming
8. Extensions to the Oracle Solaris RPC Library
One-way call using a simple counter service
Client Connection Closure Callback
Example of client connection closure callback
User File Descriptor Callbacks
Example of User File Descriptors
Non-blocking I/O avoids the client being blocked while waiting for a request to be accepted by the transport layer during one-way messaging for connection-oriented protocols.
For connection-oriented protocols, there is a limit to the amount of data that can be put in a network protocol queue. The limit depends on the transport protocols used. When a client sending a request reaches the data limit, this client is blocked from processing until its request has entered the queue. You cannot determine how long a message will wait before being added to the queue.
In non-blocking I/O, when the transport queue is full, there is an additional buffer available between the client and the transport layer. As requests not accepted by the transport queue can be stored in this buffer, the client is not blocked. The client is free to continue processing as soon as it has put the request in the buffer. The client does not wait until the request is put in the queue and does not receive information on the status of the request after the buffer accepts the request.
By using non-blocking I/O you gain further processing time as compared to two-way and one-way messaging. The client can send requests in succession without being blocked from processing.
The following figure shows a case where you choose the non-blocking argument of the I/O mode and the transport layer queue is full.
Figure 8-3 Non-Blocking Messaging
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:
The buffer is empty
The queue can immediately accept a request
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.
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); }
For a one-way message, use the clnt_send() function. No time-out is applied as the client sends a request to a server and does not wait for a reply.
For two-way messaging, use clnt_call(). The client remains blocked until the server sends a reply or an error status message, or until a time-out occurs at the client side.
The non-blocking feature enables you to send two-way and one-way calls together. If you use clnt_call() on the client side configured as non-blocking, that is, using the RPC_CL_NONBLOCKING I/O MODE, you get the following modified behavior. When a two-way request is sent to the buffer, all one-way requests already in the buffer are sent through the transport layer before the two-way request is processed. The time taken to empty the buffer is not counted in the two-way call timeout. For further information, see the clnt_control(3NSL) man page.