Writing an RPC(Remote Procedure Call) program is not so hard as it sounds.
If you are using Linux OS, it is really easy to do it. Look at the screenshots provided and follow the steps, then finally you will have a working RPC program.
Let the server procedure run as the localhost for this example. But you can customize the Linux command to interact with any other server you know of. It is simple.(Better to use the latest LTS version of Ubuntu if you do)
Step 1 : Check rpcinfo and install rpcbind
Before talking about rpcinfo let us see what rpcbind is.
Type the following command in the terminal to check this RPC registration information.
:-$ rpcinfo
This will show you the registration information in the terminal if it is successful.
Otherwise,
If you don't have the rpcbind package installed in your computer. You will be prompted to enter the following command.
:-$ sudo apt-get install rpcbind
This will install the rpcbind package in your computer, but make sure that it is connected with the internet. You can do this even if you are running your linux OS in a Virtual Machine.
You can see here that you may get an error saying E: unable to locate package rpcbind when you try the above command.
Then what you need to do is to run the following command in the terminal.
:-$ sudo apt-get update && apt-get upgrade
Then try the sudo apt-get install rpcbind command again and retype rpcinfo to verify the installation.
Step 2 : Write and compile your IDL file.
This is a sample IDL file which is used to create a simple calculator program where all the calculations happen at the server end.
/*The IDL File --- name IDL.x*/
/*Structure to hold the 2 values to be used in computation*/
struct values{
float num1;
float num2;
char operation;
};
/*Programme, version and procedure definition*/
program COMPUTE{
version COMPUTE_VERS{
float ADD(values) =1;
float SUB(values)=2;
float MUL(values)=3;
float DIV(values)=4;
} =6;
} = 456123789;
values ---> This is the name of the data structure to send the parameters of the computation to the server.
COMPUTE ---> This is the name of the programme.
COMPUTE_VERS ---> This is the name of the programme version.
ADD(values) ---> This is one of the methods that we are going to call remotely. The data structure containing the 2 operands and the operation to perform is given as parameter to the remote method. This is similar for the other methods given here as well.
You can see that at the end of each method and the programme and version, we have given some numbers. These numbers are used to uniquely identify each entity. You can give any number that you like here.
When compiled using rpcgen compiler, this IDL file generates the
1. Client stub
2. Server skeleton
3. Sample client program
4. Sample server program
5. Header file
6. XDR routines used by both the client and the server.
7. Makefile
when executing the following command.
:-$ rpcgen -a -C IDL.x
Note the the name of our IDL file will be IDL.x. This command should be executed while your current directory is the directory where the IDL file is. Here we have used the C language (the -C in the Linux command is for this.)
If you type the command rpcgen in the terminal, you will see a set of commands that can be used with the rpcgen compiler as shown below.
Step 3 : Edit the client and server programs.
This is the client program (IDL_client.c) that I have edited to suit our requirement of writing a simple calculator which can add, subtract, multiply and divide. If you are familiar with C language, you can easily edit this program according to your needs.
#include "IDL.h"
#include <stdio.h>
float
compute_6(char *host,float a,float b,char op)
{
CLIENT *clnt;
float *result_1;
values add_6_arg;
float *result_2;
values sub_6_arg;
float *result_3;
values mul_6_arg;
float *result_4;
values div_6_arg;
if(op=='+'){
add_6_arg.num1=a;
add_6_arg.num2=b;
add_6_arg.operation=op;
clnt = clnt_create (host, COMPUTE, COMPUTE_VERS, "udp");
if (clnt == NULL) {
clnt_pcreateerror (host);
exit (1);
}
result_1 = add_6(&add_6_arg, clnt);
if (result_1 == (float *) NULL) {
clnt_perror (clnt, "call failed");
}
clnt_destroy (clnt);
return (*result_1);
}
else if(op=='-'){
sub_6_arg.num1=a;
sub_6_arg.num2=b;
sub_6_arg.operation=op;
clnt = clnt_create (host, COMPUTE, COMPUTE_VERS, "udp");
if (clnt == NULL) {
clnt_pcreateerror (host);
exit (1);
}
result_2 = sub_6(&sub_6_arg, clnt);
if (result_2 == (float *) NULL) {
clnt_perror (clnt, "call failed");
}
clnt_destroy (clnt);
return (*result_2);
}
else if(op=='*'){
mul_6_arg.num1=a;
mul_6_arg.num2=b;
mul_6_arg.operation=op;
clnt = clnt_create (host, COMPUTE, COMPUTE_VERS, "udp");
if (clnt == NULL) {
clnt_pcreateerror (host);
exit (1);
}
result_3 = mul_6(&mul_6_arg, clnt);
if (result_3 == (float *) NULL) {
clnt_perror (clnt, "call failed");
}
clnt_destroy (clnt);
return (*result_3);
}
else if(op=='/'){
if(b==0){
printf("You are trying to divide by zero. Please insert a valid number.\n");
exit(0);
}
else{
div_6_arg.num1=a;
div_6_arg.num2=b;
div_6_arg.operation=op;
clnt = clnt_create (host, COMPUTE, COMPUTE_VERS, "udp");
if (clnt == NULL) {
clnt_pcreateerror (host);
exit (1);
}
result_4 = div_6(&div_6_arg, clnt);
if (result_4 == (float *) NULL) {
clnt_perror (clnt, "call failed");
}
clnt_destroy (clnt);
return (*result_4);
}
}
}
int
main (int argc, char *argv[])
{
char *host;
float number1,number2;
char oper;
printf("Enter the 2 numbers followed by the operation to perform:\n");
scanf("%f",&number1);
scanf("%f",&number2);
scanf("%s",&oper);
host = argv[1];
printf("Answer= %f\n",compute_6 (host,number1,number2,oper));
exit(0);
}
The edited server program (IDL_server.c) is as follows.
#include "IDL.h"
#include <stdio.h>
float *
add_6_svc(values *argp, struct svc_req *rqstp)
{
static float result;
result = argp->num1 + argp->num2;
return &result;
}
float *
sub_6_svc(values *argp, struct svc_req *rqstp)
{
static float result;
result = argp->num1 - argp->num2;
return &result;
}
float *
mul_6_svc(values *argp, struct svc_req *rqstp)
{
static float result;
result = argp->num1 * argp->num2;
return &result;
}
float *
div_6_svc(values *argp, struct svc_req *rqstp)
{
static float result;
result = argp->num1 / argp->num2;
return &result;
}
Step 4 : Compile all the files
For that, type the command
:-$ make -f Makefile.IDL
The output will be as shown in the following screenshot.
(All the object files will be created in the current directory)
Now you can run the server in the same terminal using the following command.
:-$ sudo ./IDL_server
Open another terminal and run the client there.
:-$ sudo ./IDL_client localhost
(P.S.You will have to enter you password when prompted.)
Enter the 2 numbers that you want to compute followed by the relevant operator symbol for this simple calculator program. When you press enter, you will get the answer as shown in the following screenshot.
So this is the simple calculator RPC program that you can try out quite easily in you Linux OS.
Hey Tharika! Thanks a lot for the help. Everything was so aptly explained. Hats Off! :)
ReplyDeleteThanks for the comments Lakshay. :)
ReplyDeleteCan we use this program by making the server run in a different system and doing an RPC to the server from one system through lan? If yes, can you tell how?
ReplyDeleteCan we use this program by making the server run in a different system and doing an RPC to the server from one system through lan? If yes, can you tell how?
ReplyDeleteYes Arjun, it is possible. You can do this by running the client with the relevant host name/ ip address of the machine in which the server runs (instead of localhost in the command sudo ./IDL_client localhost). I haven't tried it with this particular program myself, but you can try and confirm it here.
ReplyDeleteI copied only IDL_Client object file to remote machine and tried to run with server ip but not working. Please elaborate if any file need to copy along with client object?
DeleteVinod, I assume you copied the binary IDL_client, not the object file. I tested it, copied that file to hostB, then sudo ./IDL_client hostA (in hostA run this command, sudo ./IDL_server). It worked.
DeleteIs RPC support bi-directional communication. If yes, can you please tell me how to do that?
ReplyDeleteThis comment has been removed by the author.
ReplyDeleteGreat example. Appreciate it.
ReplyDeleteMam I am getting this when I COMPILED all the files.
ReplyDeleteplease help me in this.
nihal@nihal-VirtualBox:~/Documents/Nihal FACE RPC$ make -f Makefile.IDL
cc -g -c -o IDL_clnt.o IDL_clnt.c
In file included from IDL_clnt.c:7:
IDL.h:9:10: fatal error: rpc/rpc.h: No such file or directory
9 | #include
| ^~~~~~~~~~~
compilation terminated.
make: *** [: IDL_clnt.o] Error 1
I am getting this error do something.
ReplyDeletenihal@nihal-VirtualBox:~$ make -f Makefile.IDL
cc -g -c -o IDL_clnt.o IDL_clnt.c
In file included from IDL_clnt.c:7:
IDL.h:9:10: fatal error: rpc/rpc.h: No such file or directory
9 | #include
| ^~~~~~~~~~~
compilation terminated.
make: *** [: IDL_clnt.o] Error 1
nihal@nihal-VirtualBox:~$
} = 456123789;
ReplyDeleteWhat this signify. Please elaborate
the number 456123789 is very significant to use mortal human kind. as you can see the start 2 digits of the number is 45 which is divisible by 5 and next 3 digits 612 can be divided by 2. if you are getting the gist of it the other logic behind remaining digits will become clear soon as 3789 is 3 numbers in order as 7,8 and 9 so 3789
Deleteadding this comment here so i can search this easily: dc practical rpc program using idl
Deletevery insightful,dear sir
DeleteIndian people are very bad at teaching.
ReplyDeleteHello, guys! I was facing this error after compiling the code: cc -g -c -o IDL_clnt.o IDL_clnt.c
ReplyDeleteIn file included from IDL_clnt.c:7:
IDL.h:9:10: fatal error: rpc/rpc.h: No such file or directory
9 | #include
| ^~~~~~~~~~~
compilation terminated.
make: *** [: IDL_clnt.o] Error 1
I found a solution to this problem, so I wanted to share the solution with those who faced the same issue:
Use this code to compile the files instead: make -f Makefile.IDL CFLAGS="-I/usr/include/tirpc" LDLIBS="-lnsl -ltirpc"
Thanks so much
Delete