Recent Changes - Search:

Network Programming

This website demonstrates using wikis as teaching and learning tool.

The course instructor is happy to share the teaching materials here with those who find it readable.

Network Programming in C and UNIX - RPC

A Network Programming Lecture by Steven Choy

Lecture Overview: In this lecture, you learn the concepts underlying a remote procedure call (RPC), which is a popular model for client-server communication. We also provide a programming example to show how it works.


Introduction

  • Remote Procedure Call (RPC) is a mechanism which enables you to set up communication between the client and the server in a distributed application without involving you in the details of network communication.
  • The RPC is a high-level model for client-server communication. It provides programmers with a standard mechanism for building client-server applications.
  • RPC is an Inter-process communication technology that allows a computer program to cause a subroutine or procedure to execute in another address space (commonly on another computer on a shared network) without the programmer explicitly coding the details for this remote interaction. That is, the programmer would write essentially the same code whether the subroutine is local to the executing program, or remote. When the software in question is written using object-oriented principles, RPC may be referred to as remote invocation or remote method invocation. (extracted from Wikipedia)

Network communication with the remote procedure call

  • Programming with RPC produces programs that are designed to run within a client/server network model.
  • Such programs use RPC mechanisms to avoid the details of interfacing to the network, and provide network services to their callers without requiring that the caller be aware of the existence and function of the underlying network.
  • For example, a program can simply call rusers(3N), a C routine that returns the number of users on a remote machine.
  • The caller is not explicitly aware of using RPC -- the call to rusers is as simple as a call to a local procedure.

The RPC Mechanism

The following summarizes the RPC mechanism:

1) The client provides the arguments and calls the client stub in the normal way.
2) The client stub builds (marshals) a message (call request) and sends it to the Operating System and network kernel (communication module).
3) The kernel sends the message to the remote kernel. The remote kernel receives the message and gives it to the server dispatcher.
4) The dispatcher selects the appropriate server stub.
5) The server stub unpacks (unmarshals) the parameters and calls the corresponding server procedure.
6) The server procedure does the work and returns the result to the server stub.
7) The server stub packs (marshals) it in a message (call return) and sends it to the Operating System and network kernel.
8) The remote (receiver) kernel sends the message to the client kernel.
9) The client kernel gives the message to the client stub.
10) The client stub unpacks (unmarshals) the result and returns to client.

RPC Implementation

The three main tasks in RPC implementation are: interface processing, communication handling, and binding.
  • Interface processing
The interface compiler (called RPC generator in Sun RPC) processes interface definitions written in an interface definition language.
After executing, the interface compiler generates client and server stub procedures with marshalling and unmarshalling operations.
  • Communication handling
TCP and UDP communications are supported to transmit and receive request and reply messages within the Internet environment.
  • Binding
Binding specifies a mapping process from a name to a particular object, which is usually identified by a communication ID.
Binding is important, because an interface definition specifies a textual service name for use by clients and servers. We need a binder, which is a separate service that maintains a table containing mappings from service names to server ports. Moreover, a client’s request message must be addressed to a server port. Note that all other services depend on the binder service. If we did not have the binding service, we would not know how to access remote services.
Servers use two binder interfaces, Register and Withdraw, and clients use one binder interface, Portlookup.
The procedure
Register (String ServiceName, Port ServerPort, int version)
is used to register the name of a server process ServiceName with its server’s port ServerPort. Note that the integer version is used to record the number of versions registered in the server.
The procedure
Withdraw (String ServiceName, Port ServerPort, int version)
is to withdraw the registration.
The procedure
Portlookup (String ServiceName, int version)
is used by a client to search the corresponding ServerPort by given ServerName.

RPC Programming

  • You will study the most common RPC implementation: Sun RPC.
  • Sun RPC consists of the following parts:
1) rpcgen, an interface compiler that takes the definition of a remote procedure interface and generates a client stub and a server stub.
2) XDR (External Data Representation), the interface definition language, which is a standard way of encoding data in a portable fashion between different systems.
3) A run-time library that handles all of the details.
  • Example program for your study:
The client calls remote services using RPC. The server has the following two functions:
bin_date_1: This returns the current time as the number of seconds since 00:00:00 GMT, January 1, 1970.
str_date_1: This takes a long integer value from the above function and converts it into an ASCII string that is human readable format.
  • Interface definition
date.x is a RPC specification file that specifies the signatures of the remote server procedures in date_server.c. The content of date.x is listed below:
  1. /*
  2.  * date.x - specification of remote date and time service
  3.  */
  4.  
  5. /*
  6.  * Define 2 procedures:
  7.  *    bin_date_1() returns the binary time and date (no arguments).
  8.  *    str_date_1() takes a binary time and returns a human-readable string.
  9.  *
  10.  */
  11.  
  12. program DATE_PROG {
  13.    version DATE_VERS {
  14.        long   BIN_DATE(void) = 1;   /* procedure number = 1 */
  15.        string STR_DATE(long) = 2;   /* procedure number = 2 */
  16.    } = 1;                           /* version number = 1 */
  17. } = 0x31234567;                     /* program number = 0*31234567 */
The file declares both of the procedures and specifies the argument and return values for each.
It also assigns a procedure number to each function (1 and 2), along with a program number (0x31234567) and a version number (1).
Procedure numbers start at 0. Every remote program and version must define procedure number 0 as the ‘null procedure’. It does not require any arguments and returns nothing. The rpcgen compiler automatically generates it. The function of this procedure number is to allow a client to call it to verify that the particular program and version exist. It is also useful for clients to calculate the round-trip time, since if a client calls it, it does nothing and returns a null reply to the client. Thus, the time taken to call an RPC with procedure number 0 is the round-trip communication time.
The rpcgen compiler generates the actual remote procedure names by converting the names BIN_DATE and STR_DATE to bin_date_1 and str_date_1 respectively. The methodology used is to change the name from uppercase to lowercase and then append an underscore and the version number. For example, if the procedure name in the RPC specification file is ABCDE with version number 2, the actual remote procedure name is abcde_2.
We define the remote procedure BIN_DATE as taking no arguments (void) and returning a long integer result (int). Also, the remote procedure STR_DATE takes a long integer argument (int) and returns a string result (static char). We explain later why we use static char but not char. Note that Sun RPC allows at most one single argument and returns at most one single result. If more arguments are expected, we have to use a data structure as the argument. Also, if more than one value is returned, a data structure must be used as the return value.
To execute the rpcgen compiler, you should type the following command:
       >rpcgen date.x
Then the rpcgen compiler generates three different files from date.x — date_svc.c, date.h, and date_clnt.c.
The content of the file date.h is shown below:
  1. /*
  2. * Please do not edit this file.
  3. * It was generated using rpcgen.
  4. */
  5. #include <rpc/types.h>
  6. #define DATE_PROG ((u_int)0x31234567)
  7. #define DATE_VERS ((u_int)1)
  8. #define BIN_DATE ((u_int)1)
  9. extern long *bin_date_1();
  10. #define STR_DATE ((u_int)2)
  11. extern char **str_date_1();
It defines our function bin_date_1 as returning a pointer to a long integer.
It also defines our function str_date_1 as returning a pointer to a character pointer.
date_svc.c and date_clnt.c are the client and server stub procedures respectively. They are used to compile with the client and server processes when we compile.
To create a client program from the client main function chkdate.c in the client side, you should type the following commands in the following order:
       >cc –c chkdate.c chkdate.o
       >cc –c date_clnt.c –o date_clnt.o
       >cc –o chkdate chkdate.o date_clnt.o -lrpc
Note that rpc is the RPC run-time library.
On the server side, you should type the following commands in the following order:
       >cc –c date_server.c date_server.o
       >cc –c date_svc.c –o date_svc.o
       >cc –o date_server date_server.o date_svc.o -lrpc
  • The client program chkdate.c
  1. /*
  2.  * rdate.c - client program for remote date service.
  3.  */
  4.  
  5. #include <stdio.h>  
  6. #include <rpc/rpc.h> /* standard RPC include file */
  7. #include "date.h"     /* this file is generated by rpcgen */
  8.  
  9. main(argc, argv)
  10. int   argc;
  11. char  *argv[];
  12. {
  13.    CLIENT   *cl;       /* RPC handle */
  14.    char     *server;  
  15.    long     *lresult;  /* return value from bin_date_1() */
  16.    char     **sresult; /* return value from str_date_1() */
  17.  
  18.    if (argc != 2) {
  19.       fprintf(stderr, "usage: %s hostname\n", argv[0]);
  20.       exit(1);
  21.    }
  22.    server = argv[1];
  23.  
  24.    /*
  25.     * Create the client "handle."
  26.     */
  27.  
  28.    if ( (cl = clnt_create(server, DATE_PROG, DATE_VERS, "tcp"))==NULL) {
  29.       /*
  30.        * Couldn't establish connection with server.
  31.        */
  32.  
  33.       clnt_pcreateerror(server);
  34.       exit(2);
  35.    }
  36.  
  37.    /*
  38.     * First call the remote procedure "bin_date".
  39.     */
  40.  
  41.    if ((lresult = bin_date_1(NULL, cl))==NULL) {
  42.       clnt_perror(cl,server);
  43.       exit(3);
  44.    }
  45.    printf("time on host %s = %ld\n", server, *lresult);
  46.  
  47.    /*
  48.     * Now call the remote procedure "str_date".
  49.     */
  50.  
  51.    if ((sresult = str_date_1(lresult,cl))==NULL) {
  52.        clnt_perror(cl,server);
  53.        exit(4);
  54.    }
  55.    printf("time on host %s = %s", server, *sresult);
  56.  
  57.    clnt_destroy(cl);   /* done with the handle */
  58.    exit(0);  
  59. }
The program flow is simple.
First, check the existence of the second argument, which should contain the name of the remote server.
Second, call clnt_create to create an RPC handle to the specified program (the second argument) and version (the third argument) on a host. We also need to specify which communication protocol we used. It is usually either TCP or UDP. In our example, we used TCP, so the fourth argument is tcp. Note that the first argument is the name of the remote server. After executing the function call clnt_create, we have the handle.
Third, we can call the remote procedures bin_date_1 and str_date_1 for that particular program and version.
Fourth, When we finish executing the two remote procedures, we call clnt_destroy to destroy the RPC handle.
  • The server program date_server.c
  1. /*
  2.  * dateproc.c - remote procedures; called by server stub.
  3.  */
  4.  
  5. #include <rpc/rpc.h>   /* standard RPC include file */
  6. #include "date.h"      /* this file is generated by rpcgen */
  7.  
  8. /*
  9.  * Return the binary date and time.
  10.  */
  11.  
  12. long *
  13. bin_date_1()
  14. {
  15.    static long   timeval;   /* must by static */
  16.    time_t          time();    /* Unix function */
  17.  
  18.    timeval = (long)time((long *) 0);
  19.    return(&timeval);
  20. }
  21.  
  22. /*
  23.  * Convert a binary time and return a human readable string.
  24.  */
  25.  
  26. char **
  27. str_date_1(bintime)
  28. long  *bintime;
  29. {
  30.    static char   *ptr;      /* must be static */
  31.    char          *ctime();  /* Unix function */
  32.  
  33.    ptr = ctime(bintime);    /* convert to local time */
  34.  
  35.    return(&ptr);            /* return the address of pointer */
  36. }
As mentioned, the server program is just a set of functions and is not a main program. The flow is very simple. The first function just calls the time function to get the current time, and the second function converts it into a human readable format. Note that the return values must be static variables, because if we do not use static variables, their values would be undefined after the return statement passes control back to the server stub that calls our remote procedure.
  • How to run the RPC example program?
In the server side, we execute the server program as follows:
       > date_server &
Note that & means background execution.
On the client side, we execute the client program and obtain the following daytime result from the server:
       > chkdate localhost
       time on host localhost = 1016692751
       time on host localhost = Thu Mar 21 14:39:11 2009
Note that localhost is used as the remote server for our testing.

Tools and References


Thanks for Reading

If you would rather like to have this lecture note in printed format, please click the print action link in the top right corner.

If you find any problem in this lecture note, please feel free to tell Steven via steven@findaway.hk.

Edit - History - Print - Recent Changes - Search
Page last modified on December 03, 2009, at 09:49 AM