Remote Procedure Calls (RPC).


In the normal scope of things, a program can only call a function that is linked into the executable or provided by a shared library. RPC allows programs to execute functions in another executing program, cool!

RPC has a concept of clients and servers.

  1. The client issues requests to the server.
  2. Servers perform the requests and return the results.
  3. The data that flows between client and server includes int, float, strings and structures.
  4. The client and server can be on the same host or different hosts connected via a network.
  5. The hosts do not have to be the same artitechture.
The RPC API has three levels of support. By using the highest level RPC is responcable for most of the code but is not too flexable. The lowest level requres more coding but gives the programmer more control over how RPC functions.

The easiest way to start with RPC is to use a program called rpcgen this reads a file that describes the required interface between client and server and generates C code that you can include in your client and server.


	prog.x --> rpcgen ---> prog.h        Header file
                          ---> prog_clnt.c   Client stubs file
                          ---> prog_svc.c    Server stubs file
                          ---> prog_xdr.c    XDR routines (more later).

You write prog.x and rpcgen generates prog.h prog_clnt.c prog_svc.c prog_xdr.c You then write the client and server and link them with the rpcgen code to complete the RPC system.

	client.c    -----> client executable
        prog.h      ---|
        prog_clnt.c ---|
        prog_xdr.c  ---|

        server.c    -----> Server executable
        prog.h      ---|
        prog_svc.c  ---|
        prog_xdr.c  ---|


Ok, time for some examples.

Calling an RPC server function without passing any arguments.

This is the simplest form of RPC.

void.x

  /* RPCGEN code decribing the client/server API. */
 
  program MJLPROG
  {
    version MJLVERS
    {
      void VOID(void) = 1;
    
    } = 1;
  } = 0x20000001;

void.x describes the RPC interface between the client and server. There are some important items to note here.

program MJLPROG
{
} = 0x20000001;
This is the RPC program number. It is used by the client to identify the server it intends to use. It is important that you provide a unique number here. You can see which values are in use with the Unix command rpcinfo -p or by looking at /etc/rpc. Please note that the number is supplied in void.x as a hex value but shown as a decimal value by rpcinfo One other point, you should only use values in the range 0x20000000 0x3FFFFFFF as these have been reserved for use local use.
version MJLVERS
{
} = 1;
The RPC Version number.
void VOID(void) = 1;
This defines the only RPC function that the server will provide.

void_client.c

  #include <rpc/rpc.h>
  #include "void.h"

  main()
  {
      CLIENT *pclnt;
      void   *pVoid;
    
      char    Host[256];

      /* Get the name of the host running the server. */
    
      gethostname(Host, 256);

      /* Connect to the server. */
    
      pclnt = clnt_create(Host, MJLPROG, MJLVERS, "udp");

      /* Issue a request to the server. */
    
      void_1(pVoid, pclnt);

      /* Disconnect from the server. */
    
      clnt_destroy(pclnt);

  }

#include <rpc/rpc.h>

Include the standard RPC headers.
#include "void.h"
Include the header file generated by rpcgen
pclnt = clnt_create();
Connect to the server MJLPROG on Host and return a pointer to the CLIENT control structure.
void_1(pVoid, pclnt);
Call the remote function.
clnt_destroy();
Disconnect from the server.

void_server.c

  #include 
  #include "void.h"

  void *void_1_svc(void *pVoid,  struct svc_req *X)
  {
      printf("Function called without passing arguments\n");
  }

void *void_1_svc()
The server function that will be run for the client.

Please note that the server does not have a main(), rpcgen generates it for you.

The code can be compiled with the following commands

  gcc void_server.c void_svc.c -o void_server
  gcc void_client.c void_clnt.c -o void_client

In theory you should be able to start the server and it will respond everytime the client is executed. I have not included any error recovery into this example as it makes the code harder to read. As an exercise try adding the error recovery code yourself :-)

Transfer integers between the client and server

integer.x

  /* RPCGEN code decribing the client/server API. */
 
  program MJLPROG
  {
    version MJLVERS
    {
      int INTEGER(int) = 1;
    
    } = 1;
  } = 0x20000001;

int INTEGER(int) = 1;
Server function now accepts an integer and returns an integer.


See Also:

VOID keyword.

Top Master Index Keywords Functions


29-Dec-97
Martin Leslie