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

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


In the previous post, I have told you how to make a counter server in C and then call its functionalities through RPC calls.

In Erlang it is defined a module called rpc. It provides services which are similar to remote procedure calls. It also contains broadcast facilities and parallel evaluators. As I told you also in the previous blog a remote procedure call is a method to call a function on a remote node and collect the answer.

The most important function in this module is rpc:call(Node, Module, Function, Arguments), it executes the specific function defined in the specific module, with the specified arguments on the node Node and returns the corresponding that can be either the return value, or a tupla of the form {badrpc, Reason}.

Sounds easy! Thus let’s start by coding our counter server:

%%%-------------------------------------------------------------------
%%% File    : counter_svr.erl
%%% Author  : XXXXX
%%% Description : A counter server
%%%
%%% Created : 19 Dec 2009 by XXXXX
%%%-------------------------------------------------------------------
-module(counter_svr).

-behaviour(gen_server).

%% API
-export([start_link/0,count/0]).

%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
	 terminate/2, code_change/3]).

-record(state, {counter=0}).

%%====================================================================
%% API
%%====================================================================
%%--------------------------------------------------------------------
%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
%% Description: Starts the server
%%--------------------------------------------------------------------
start_link() ->
    gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).

%%====================================================================
%% gen_server callbacks
%%====================================================================

%%--------------------------------------------------------------------
%% Function: init(Args) -> {ok, State} |
%%                         {ok, State, Timeout} |
%%                         ignore               |
%%                         {stop, Reason}
%% Description: Initiates the server
%%--------------------------------------------------------------------
init([]) ->
    {ok, #state{}}.

%%--------------------------------------------------------------------
%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
%%                                      {reply, Reply, State, Timeout} |
%%                                      {noreply, State} |
%%                                      {noreply, State, Timeout} |
%%                                      {stop, Reason, Reply, State} |
%%                                      {stop, Reason, State}
%% Description: Handling call messages
%%--------------------------------------------------------------------
handle_call(count, _From, State) ->
    Reply = State#state.counter + 1,
    NewState = #state{counter=Reply},
    {reply, Reply, NewState};

handle_call(_Request, _From, State) ->
    Reply = ok,
    {reply, Reply, State}.

%%--------------------------------------------------------------------
%% Function: handle_cast(Msg, State) -> {noreply, State} |
%%                                      {noreply, State, Timeout} |
%%                                      {stop, Reason, State}
%% Description: Handling cast messages
%%--------------------------------------------------------------------
handle_cast(_Msg, State) ->
    {noreply, State}.

%%--------------------------------------------------------------------
%% Function: handle_info(Info, State) -> {noreply, State} |
%%                                       {noreply, State, Timeout} |
%%                                       {stop, Reason, State}
%% Description: Handling all non call/cast messages
%%--------------------------------------------------------------------
handle_info(_Info, State) ->
    {noreply, State}.

%%--------------------------------------------------------------------
%% Function: terminate(Reason, State) -> void()
%% Description: This function is called by a gen_server when it is about to
%% terminate. It should be the opposite of Module:init/1 and do any necessary
%% cleaning up. When it returns, the gen_server terminates with Reason.
%% The return value is ignored.
%%--------------------------------------------------------------------
terminate(_Reason, _State) ->
    ok.

%%--------------------------------------------------------------------
%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
%% Description: Convert process state when code is changed
%%--------------------------------------------------------------------
code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
count() ->
    gen_server:call(?MODULE, count).

As you can see I used the template of a gen_server for my implementation of the counter server. The value of the counter is stored inside its state, and it starts with the value of 0. The server handles a specific call that is aimed to retrieve the counter from the server, increment it by one and return that value to the client.  In the internal functions space, I defined a function named count that performs the specific call to the gen_server.

Easy, isn’t it?

Now we have only to start the server in a Erlang node (we name it server@ourlocalhost).

bellerofonte@pegaso:~$ erl -sname server@pegaso
Erlang R13B02 (erts-5.7.3)
Eshell V5.7.3  (abort with ^G)
(server@pegaso)1> counter_svr:start_link().
{ok,<0.40.0>}

At this point the server is up an running on our Erlang node, so the only thing left is to start another Erlang node (or many nodes) and perform some RPC from these. First of all we start the second node, you should know that this node must be connected to the previous one and share with it the same cookie, if you don’t see Erlang User Guide for more info. In brief I can tell you that you can check whether two nodes are connected by calling in one node the function net:ping(‘othernode@host’) that gives back a ‘pong’ if they are connected, or a ‘pang’ if they are not…..moreover you can check if the nodes have the same cookie by calling in both nodes the function erlang:get_cookie() (otherwise you can set the cookie with erlang:set_cookie(Cookie). Coming back to our discussion on rpc, inside the second node we call the function through RPC by using as stated above rpc:call(Node, Module, Function, Arguments)…in our specific case Node is the node where the server is running, Module is the module implementing the server, Function is the function that retrieves the counter and increments it and Arguments is an empty list, since the function takes no arguments.

bellerofonte@pegaso:~$ erl -sname client@pegaso
Erlang R13B02 (erts-5.7.3)
Eshell V5.7.3  (abort with ^G)
(client@pegaso)1> rpc:call('server@pegaso', counter_svr, count, []).
1
(client@pegaso)2> rpc:call('server@pegaso', counter_svr, count, []).
2
(client@pegaso)3> rpc:call('server@pegaso', counter_svr, count, []).
3
(client@pegaso)4> rpc:call('server@pegaso', counter_svr, count, []).
4

As you may see in the example I posted above, multiple RPCs to our server, give back the result expected…..

In my opinion this comparison explains why I still prefer using Erlang when talking or coding distributed systems!

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: