RPC Extensions Developer's Guide

One-Way Messaging

In one-way messaging the client thread sends a request containing a message to the server. The client thread does not wait for a reply from the server and is free to continue processing when the request has been accepted by the transport layer. The request is not always sent immediately to the server by the transport layer, but waits in a queue until the transport layer sends it. The server executes the request received by processing the message contained in the request.

After the transport layer accepts a request, the client is not notified of failures in transmission and does not receive a receipt from the server from the request. For example, if the server refuses the request due to an authentication problem, the client is not notified of this problem. If the transport layer does not accept the request, the sending operation returns an immediate error to the client.


Note –

If you need to check that the server is functioning correctly, you can send a two-way request to the server. Such a request can determine whether the server is still available and if it has received the one-way requests sent by the client.


For one-way messaging, the clnt_send() function, has been added to the Sun RPC library, and the oneway attribute has been added to the RPC grammar.

clnt_send()

In previous versions of the Sun RPC library, you use the clnt_call() function to send a remote procedure call. With the extended one-way messaging service, the clnt_send() function sends one-way remote procedure calls.

When the client calls clnt_send(), the client sends a request to the server and continues processing. When the request arrives at the server, the server calls a dispatch routine to process the incoming request.

Like clnt_call(), the clnt_send() function uses a client handle to access a service. See the clnt_send(3NSL) and clnt_call(3NSL) man pages for further information.

If you don't provide the correct version number to clnt_create(), clnt_call() fails. In the same circumstances, clnt_send() does not report the failure, as the server does not return a status.

The oneway Attribute

To use one-way messaging, add the oneway keyword to the XDR definition of a server function. When you use the oneway keyword, the stubs generated by rpcgen use clnt_send(). You can either:

For one-way messaging, use version 1.1 of the rpcgen command.

When declaring the oneway keyword, follow the RPC language specification using the following syntax:

"oneway" function-ident "(" type-ident-list ")" "=" value;
See “RPC Protocol and Language Specification” in ONC+ Developer's Guide for details on RPC language specifications.

When you declare the oneway attribute for an operation, no result is created on the server side and no message is returned to the client.

Information on the oneway attribute must be added to the RPC Language Definition Table in “The RPC Language Specification” in ONC+ Developer's Guide as shown in Table 1–1:

Table 1–1 RPC Language Definitions

Term 

Definition 

procedure 

type-ident procedure-ident (type-ident) = value

oneway procedure-ident (type-ident) = value


Example 1–1 One-way call using a simple counter service

This example illustrates how to use a one-way procedure on a simple counter service. In this counter service the ADD() function is the only function available. Each remote call sends an integer and this integer is added to a global counter managed by the server. For this service, you must declare the oneway attribute in the RPC language definition, as described in Table 1–1.

In this example, you generate stubs using the -M, -N and -C rpcgen options. These options ensure that the stubs are multithread safe, accept multiple input parameters and that generated headers are ANSI C++ compatible. Use these rpcgen options even if the client and server applications are mono-threaded as the semantic to pass arguments is clearer and adding threads in applications is easier since the stubs do not change.

  1. Write the service description in the counter.x file.

       /* counter.x: Remote counter protocol */
    program COUNTERPROG {
     	version COUNTERVERS {
     	  oneway ADD(int) = 1;
     	} = 1;
    } = 0x20000001;

    The service has a program number, (COUNTERPROG) 0x200000001, and a version number, (COUNTERVERS) 1.

  2. Call rpcgen on the counter.x file.

    rpcgen -M -N -C counter.x
    This generates client and server stubs, counter.h, counter_clnt.c and counter_svc.c.

  3. As shown in the server.c file, write the service handler for the server side and the counterprog_1_freeresult() function used to free memory areas allocated to the handler. The RPC library calls this function when the server sends a reply to the client.

    	  #include <stdio.h>
    #include "counter.h"
    
    int counter = 0;
    
      	 bool_t
    add_1_svc(int number, struct svc_req *rqstp)
    {
     	 bool_t retval = TRUE;
    
      	 counter = counter + number;
    
      	 return retval;
    }
     	 int
    counterprog_1_freeresult(SVCXPRT *transp, xdrproc_t xdr_result, caddr_t
                             result)
    {
     	 (void) xdr_free(xdr_result, result);
    
      	 /*
    		  * Insert additional freeing code here, if needed 
    		  */
    
      	 return TRUE;
    }

    Build the server by compiling and linking the service handler to the counter_svc.c stub. This stub contains information on the initialization and handling of TI-RPC.

  4. Write the client application, client.c.

    	  #include <stdio.h>
    #include "counter.h"
    
    main(int argc, char *argv[])
    {
     	 CLIENT *clnt;
     	 enum clnt_stat result;
     	 char *server;
     	 int number;
    
      	 if(argc !=3) {
     		  fprintf(stderr, "usage: %s server_name number\n", argv[0];
    			  exit(1);
    	 	 }
     	 server = argv[1];
     	 number = atoi(argv[2]);
    
      	 /* 
    		  * Create client handle 
    		  */
     	 clnt = clnt_create(server, COUNTERPROG, COUNTERVERS, "tcp");
    
      	 if(clnt == (CLIENT *)NULL) {
    		 /* 
    		  * Couldn't establish connection 
    		  */
    	 		  clnt_pcreateerror(server);
     		  exit(1);
     	 }
    
      	 result = add_1(number, clnt);
     	 if (result !=RPC_SUCCESS) {
     		  clnt_perror(clnt, "call failed");
     	 }
    
      	 clnt_destroy(clnt);
     	 exit(0); 
    }

    The add_1() client function is the counter_clnt.c stub generated for the remote function.

    To build the client, compile and link the client main and the counter_clnt.c.

  5. Launch the server that you built.

    % ./server
  6. Invoke the service in another shell.

    % ./client servername 23

    23 is the number being added to the global counter.