Go to main content

ONC+ RPC Developer's Guide

Exit Print View

Updated: November 2020
 
 

Batching RPC Clients

RPC is designed so that clients send a call message and wait for servers to reply to the call. This procedure implies that a client is blocked while the server processes the call. This result is inefficient when the client does not need each message acknowledged.

    RPC batching lets clients process asynchronously. RPC messages can be placed in a pipeline of calls to a server. Batching requires that:

  • The server does not respond to any intermediate message.

  • The pipeline of calls is transported on a reliable transport, such as TCP.

  • The result's XDR routine in the calls is NULL.

  • The RPC call's timeout is zero.

Because the server does not respond to each call, the client can send new calls in parallel with the server processing previous calls. The transport can buffer many call messages and send them to the server in one write() system call. This buffering decreases interprocess communication overhead and the total time of a series of calls. The client should end with a nonbatched call to flush the pipeline.

The following code example shows the unbatched version of the client. It scans the character array, buf, for delimited strings and sends each string to the server.

Example 53  Unbatched Client
#include <stdio.h>
#include <rpc/rpc.h>
#include "windows.h"
 
main(argc, argv)
	int argc;
	char **argv;
{
	struct timeval total_timeout;
	register CLIENT *client;
	enum clnt_stat clnt_stat;
	char buf[1000], *s = buf;
 
	if ((client = clnt_create( argv[1], WINDOWPROG, WINDOWVERS,
					"circuit_v")) == (CLIENT *) NULL) {
		clnt_pcreateerror("clnt_create");
		exit(1);
	}
 
	total_timeout.tv_sec = 20;
	total_timeout.tv_usec = 0;
	while (scanf( "%s", s ) != EOF) {
		if (clnt_call(client, RENDERSTRING, xdr_wrapstring, &s,
		   xdr_void, (caddr_t) NULL, total_timeout) != RPC_SUCCESS) {
			clnt_perror(client, "rpc");
			exit(1);
		}
	}
 
	clnt_destroy( client );
	exit(0);
}

The following code example shows the batched version of the client. It does not wait after each string is sent to the server. It waits only for an ending response from the server.

Example 54  Batched Client
#include <stdio.h>

#include <rpc/rpc.h>
#include "windows.h"
 
main(argc, argv)
	int argc;
	char **argv;
{
	struct timeval total_timeout;
	register CLIENT *client;
	enum clnt_stat clnt_stat;
	char buf[1000], *s = buf;
 
	if ((client = clnt_create( argv[1], WINDOWPROG, WINDOWVERS,
					"circuit_v")) == (CLIENT *) NULL) {
		clnt_pcreateerror("clnt_create");
		exit(1);
	}
	timerclear(&total_timeout);
	while (scanf("%s", s) != EOF)
		clnt_call(client, RENDERSTRING_BATCHED, xdr_wrapstring,
		           &s, xdr_void, (caddr_t) NULL, total_timeout);
	/* Now flush the pipeline */
	total_timeout.tv_sec = 20;
	clnt_stat = clnt_call(client, NULLPROC, xdr_void,
	         (caddr_t) NULL, xdr_void, (caddr_t) NULL, total_timeout);
	if (clnt_stat != RPC_SUCCESS) {
		clnt_perror(client, "rpc");
		exit(1);
	}
	clnt_destroy(client);
	exit(0);
}

The following code example shows the dispatch portion of the batched server. Because the server sends no message, the clients are not notified of failures.

Example 55  Batched Server
#include <stdio.h>
#include <rpc/rpc.h>
#include "windows.h"
 
void
windowdispatch(rqstp, transp)
	struct svc_req *rqstp;
	SVCXPRT *transp;
{
	char    *s = NULL;
 
	switch(rqstp->rq_proc) {
		case NULLPROC:
			if (!svc_sendreply( transp, xdr_void, NULL))
				fprintf(stderr, "can't reply to RPC call\n");
			return;
		case RENDERSTRING:
			if (!svc_getargs( transp, xdr_wrapstring, &s)) {
				fprintf(stderr, "can't decode arguments\n");
				/* Tell caller an error occurred */
				svcerr_decode(transp);
				break;
			}
			/* Code here to render the string s */
			if (!svc_sendreply( transp, xdr_void, (caddr_t) NULL))
				fprintf( stderr, "can't reply to RPC call\n");
			break;
		case RENDERSTRING_BATCHED:
			if (!svc_getargs(transp, xdr_wrapstring, &s)) {
				fprintf(stderr, "can't decode arguments\n");
				/* Be silent in the face of protocol errors */
				break;
			}
			/* Code here to render string s, but send no reply! */
			break;
		default:
			svcerr_noproc(transp);
			return;
	}
	/* Now free string allocated while decoding arguments */
	svc_freeargs(transp, xdr_wrapstring, &s);
}

Note - To illustrate the benefits of batching, Example 53, Unbatched Client and Example 55, Batched Server were completed to render the lines in a 25,144-line file. The rendering service throws away the lines. The batched version of the application is four times as fast as the unbatched version.