The Complete Magazine on Open Source

rpcgen: The Simple Way to Develop Distributed Applications

5.05K 0

In distributed computing, the data and the services processing the data are placed in different computers connected by a network. This makes developing a distributed application a daunting task. This article presents a simple method for developing a distributed application using rpcgen.

Many scientific problems are solved using distributed systems, as shown in Figure 1. Basically, a distributed system is a collection of autonomous computers connected by a network that appears to the users of the system as a single computer. The message passing mechanism plays a major role in the success of distributed computing. For a distributed application, developers have to worry about details such as sockets, network byte order, host byte order, etc. In this situation, Remote Procedure Call (RPC) presents a simple mechanism for distributed computing without the need to include socket code in the distributed application.

rpcgen
Open Network Computing (ONC) Remote Procedure Call (RPC) is a widely deployed remote procedure call system. ONC was originally developed by Sun Microsystems in the 1980s as part of the company’s Network File System project, and is sometimes referred to as Sun RPC. rpcgen is an interface generator precompiler for Sun Microsystems ONC RPC. Now, rpcgen is supported by many systems. With the availability of the rpcgen application, developers can concentrate on developing the core features of their application, instead of spending most of their time on developing and debugging their network interface code.

Figure 1: Distributed computing environment

Figure 2: Test bed

Application development using RPC
Distributed computing uses the divide and conquer principle to solve computationally-intensive problems. The problem is divided into many tasks, each of which is computed by one or more computers in the distributed systems. For the sake of simplicity, let us start developing a distributed application with two computing services called max and min running on two different computers, as shown in Figure 2. The service max finds the maximum number in the given list of numbers and the service min finds the minimum number in the given list of numbers.

Distributed application development, using rpcgen, starts with designing the Interface Definition Language file. This file contains the details about the services that run on different autonomous computers in the distributed system. The file has to be saved with a .x extension like dist_app.x, as in this case.

struct ipair { // Data that will be processed by the services
int data[10];
int count;
};
program MINMAX{ // MINMAX is the name of interface 
version VER1 { //VER1 is the version 
int max(ipair)=1;
int min(ipair)=2;
}=1;
}=0x3a3afeeb; // 32 bit program number

The next step is compiling dist_app.x with rpcgen.
$rpcgen –C dist_app.x as shown in Figure 3 creates four new files—dist_app_clnt.c, dist_app.h, dist_app_svc.c and dist_app_xdr.c. The option –C is used to generate ANSI C code. The files dist_app_clnt.c and dist_app_svc.c are called the client stub and server stub, respectively. These are responsible for maintaining networking connections. The file dist_app.h is the header file which will be included in the distributed application. The file dist_app_xdr.c is called the eXternal data representation file. It will help in data conversions.

Figure 3: Compiling the IDL file with rpcgen

Figure 4: Creating sample client and sample server programs with rpcgen

Figure 5: Generating a distributed application with gcc

The next step is to create the distributed application’s sample client and sample server programs using the options –Sc and –Ss with rpcgen, as shown in Figure 4.
We then slightly modify the sample files dist_app_client.c, dist_app_server1.c and dist_app_server2.c according to our needs, and then compile them using the gcc compiler as shown in Figure 5.

/* This is dist_app_client.c generated by rpcgen and modified according to the need */

#include “dist_app.h”
void minmax_1(char *host1,char *host2,int *p,int length) // Client Program has to communicate
{ // with two Computers as per Figure 2. 
CLIENT *clnt1,*clnt2;
int *result_1,i;
struct ipair op;
int *result_2;
for(i=0;i<length;i++) //making data ready 
op.data[i]=p[i];
op.count=length;

#ifndef DEBUG
clnt1 = clnt_create (host1, MINMAX, VER1, “udp”); // for making UDP connection 
if (clnt1 == NULL) {
clnt_pcreateerror (host1);
exit (1);
}
clnt2 = clnt_create (host2, MINMAX, VER1, “udp”); // for making UDP Connection
if (clnt2 == NULL) {
clnt_pcreateerror (host2);
exit (1);
}
#endif /* DEBUG */

result_1 = max_1(&op, clnt1); // sending data to service Max as per Figure 2
if (result_1 == (int *) NULL) {
clnt_perror (clnt1, “call failed”);
}
printf(“\n The result from the Service Max is :%d\n”, *result_1);
result_2 = min_1(&op, clnt2); // sending data to service Min as per Figure 2
if (result_2 == (int *) NULL) {
clnt_perror (clnt2, “call failed”);
}
printf(“\n The result from the Service Min is :%d\n”, *result_2);
#ifndef DEBUG
clnt_destroy (clnt1);
clnt_destroy (clnt2);
#endif /* DEBUG */
}
int main (int argc, char *argv[])
{
char *host1,*host2;

int i,x[10];
printf(“\n give any 10 elements”); // For collecting the list of elements from USER
for(i=0;i<10;i++)
scanf(“%d”,&x[i]);
host1=”192.168.142.130”; //VM2 as per Figure 2
host2 = “192.168.142.131”; //VM1 as per Figure 2
minmax_1 (host1,host2,x,10); 
exit (0);
}

/* This is dist_app_sever1.c generated by rpcgen and modified according to the need */

#include “dist_app.h”
int * max_1_sec(ipair *argp, struct sec_rereq *rqstp) // The service Max definition
{
static int result;
int i,big;
printf(“\n Got request for finding the max element in the given array\n”);
big=argp->data[0];
for(i=1;i<argp->count;i++)
if(big<argp->data[i])
big=argp->data[i];
result=big;
return &result;
}
int * min_1_sec(ipair *argp, struct sec_req *rqstp) // This is not used here as it is not required. 
{
static int result;
/*
* insert server code here
*/
return &result;
}
/* This is dist_app_sever2.c generated by rpcgen and modified according to the need */
#include “dist_app.h”

int * max_1_sec(ipair *argp, struct sec_req *rqstp) // This is not used here as it is not required.
{
static int result; /*
* insert server code here
*/
return &result;
}
int * min_1_sec(ipair *argp, struct sec_req *rqstp) // The service Min Definition
{
static int result;

int i,small;
printf(“\n Got request for finding the min element in the given array\n “);
small=argp->data[0];

for(i=1;i<argp->count;i++)
if(small>argp->data[i])
small=argp->data[i];

result=small;
return &result;
}

Figure 6: Executing the client program in VM3

Figure 7: Executing the service max in VM2

Figure 8: Executing the service min in VM1

Executing the distributed application
We can execute the distributed application as shown in Figures 6, 7 and 8, respectively. The above modified code can also be downloaded from http://opensourceforu.com/article_source_code/jan2016/rcpgen.zip
Developing a distributed application is simple and easy with RPC, as compared to socket programming. Developers can use rpcgen to generate sample client and server programs, and then modify them easily, according to requirements.