Home > C, English, Erlang > REMOTE PROCEDURE CALLs: C vs. Erlang (part 1)

REMOTE PROCEDURE CALLs: C vs. Erlang (part 1)


In the last weeks I have been geeking a while with Remote Procedure Calls.

RPCs were invented at Sun Microsystems in the 80s, and can be seen as “normal” procedure calls on a distributed system. The concept behind RPCs is the following: you don’t have to declare the function you want to use in your client, you can declare that function on a server and than if you invoke it, a so-called “middleware” is going to forward the request from the client to the server, where the function is executed and the result is returned back to the client.

Since I’m still confident that Erlang is much more better than C for distributed systems I’ll try to code in both languages a server that keeps a counter in it, each time a client calls via RPC a function it will increment that value.

In C I could do it coding three files. Let’s start with the first: a file (counter.x) with the specifications of the service provided by the functions that can be called remotely. The specifications must be converted to stubs and header files for the middleware using the tool rpcgen (we will se it later).

When you write the specifications, you must identify the functions that are going to be called remotely. The functions must specify the return type and arguments. For every function (called RPC), you must assign an ID and must include it in a program that must be uniquely referred to by an ID and a version.

Our counter.x may look like this:

program COUNTERPROG {
  version COUNTERVERS {
    int COUNTER() = 1;
  } = 1;
} = 0x20000001;

where the remote procedure COUNTER has ID 1 and is included in the version 1 of the program COUNTERPROG. The ID of the program is 0x20000001.

After that you must write the procedure code as if you would write it locally, but with slight changes. The procedure must use a conventional name PROGRAM_VERSION_svc (in our case counter_1_svc). The procedure uses pointers to return the result and receive the arguments.
One more argument is required to identify the execution context.

Thus in our case we can create a file named counter_proc.c of the following form:

#include <stdio.h>
#include "counter.h"
int *counter_1_svc(void *msg, struct svc_req *req)
{
  static int result = 0;
  result++;
  return (&result);
}

The header file counter.h is one of the files generated by rpcgen. As you can see we create a STATIC variable result that lives in the space allocated for static variables so that it can survive when the execution of the fuction ends. Whenever the function is called we increment that value and return the address of that static variable.

Now we have to write to client! This client, before performing the remote call to the server, must connect to it. Then, after the call it can disconnect. The connection is done using the function clnt_create(server address, program id, program version, transport protocol). The disconnection is done using the function clnt_destroy().

Let’s create a file called rcounter.c of the following form:

#include <stdio.h>
#include <string.h>
#include "counter.h"
int main(int argc, char **argv)
{
  CLIENT *clnt;
  int *result;
  char *server;
  // try to get the server address from command line
  if (argc != 2) {
    fprintf(stderr, "Usage is the following: %s server\n", argv[0]);
    return -1;
  }
  server = argv[1];
  // create the client
  clnt = clnt_create(server, COUNTERPROG, COUNTERVERS, "udp"); //udp may be set to tcp
  if (clnt == NULL) {
    clnt_pcreateerror(server);
    return -1;
  }
  // call the function
  result = counter_1(NULL, clnt);
  if (result == NULL) {
    clnt_perror(clnt, server);
    return -1;
  }
  // print the value obtained from the call
  printf("The value of the counter is %d\n", *result);
  // destroy the client
  clnt_destroy(clnt);
  return 0;
}

Now let’s compile all the files:

bellerofonte@pegaso:~$ rpcgen counter.x

This generates: counter.h counter_svc.c counter_clnt.c

bellerofonte@pegaso:~$ gcc counter_svc.c counter_proc.c -o counter_svr -lnsl
bellerofonte@pegaso:~$ gcc counter_clnt.c rcounter.c -o counter_clt -lnsl

and execute them:

bellerofonte@pegaso:~$ ./counter_svr &
[1] 4898
bellerofonte@pegaso:~$ ./counter_clt localhost
Counter is 1
bellerofonte@pegaso:~$ ./counter_clt localhost
Counter is 2
bellerofonte@pegaso:~$ kill -9 4898

As you can see at every call the value returned is the previous one plus 1 (starting from zero).

I killed the server in the end because I started it in background mode…if you want you can run the two files in different shells to avoid this.

Ok, this post starts being long…so for the Erlang code I will open a new one🙂

Categories: C, English, Erlang Tags: , , ,
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: