SE 765 - Distributed Software Development (CRN 73169)

CS 610 - Introduction to Parallel and Distributed Computing (CRN 73173)

Assignment #5

To be begun in class and completed at home. The final program, a snapshot of its workings, and answers to questions should be emailed to me by 6PM, December 10th.

 

Simple client/server in Erlang exercise.

 

1     Introduction

 

You will build a simple client server system in Erlang.

 

2     A simple server

 

A server generally has some state. Thus we have to use patterns similar to the following:

server(State) -> receive

 

some_request   ->

 

%%.....   do   some   stuff

 

%% ..... compute the new state NewState server(NewState)

 

end.

 

You will extend the following very simple server. Your server should have one piece of state, a value that records how many times it has been called.

 

server(State) -> receive

 

{request,Return_PID}   ->

io:format("SERVER ~w: Client request received from ~w~n", [self(), Return_PID]) ,

 

NewState   =   State   +   1,

 

Return_PID   !   {hit_count,NewState},

server(NewState)

end.

 

The  client  is  simpler,  it  takes  as  a  parameter  the  server  PID,  sends  a  request, and  prints  out  a  value.

client(Server_Address)   ->

Server_Address   !   {request,   self()},

receive

{hit_count,Number}   ->

io:format("CLIENT   ~w:   Hit   count   was   ~w~n",[self(),   Number])

    end.

Combine server and client in one  file  named  simple.erl  and  try  it.  .

-module(simple).

-export([server/1,client/1,start/0]).

 

  server(State)   ->

receive

{request,Return_PID}   ->

io:format("SERVER   ~w:   Client   request   received   from   ~w~n",

[self(),   Return_PID])   ,

NewState   =   State   +   1,

Return_PID   !   {hit_count,NewState},

server(NewState)

end.

 

client(Server_Address)   ->

Server_Address   !   {request,   self()},

receive

{hit_count,Number}   ->

io:format("CLIENT   ~w:   Hit   count   was   ~w~n",[self(),   Number])

end.

 

start()   ->

Server_PID   =   spawn(simple,server,[0]),

 

spawn(simple,client,[Server_PID]).

Compile  and  run this code  from  the  Erlang  shell

3     Many  clients

 

Add the following function to spawn multiple clients:

 

spawn_n(N,Server_PID) -> if

 

N>0 -> spawn(simple,client,[Server_PID]),

 

%% Use a random sleep in  miliseconds to simulate the

 

%% client traffic pattern. timer:sleep(random:uniform(100)),

spawn_n(N-1,Server_PID);

N ==   0      ->

 

io:format("Last   client   spawned.~n")

 

end.

 

4     Questions

 

You should turn in (email to me)  answers  to  the  questions  below .

 

Question 1:   In  the  simple  server

 

server(State) -> receive

 

{request,Return_PID}   ->

 

io:format("SERVER ~w: Client request received from ~w~n", [self(), Return_PID]),

 

NewState   =   State   +   1,

 

Return_PID ! {hit_count,NewState}, server(NewState)

 

end.

 

What does the following line do?

Return_PID   !   {hit_count,NewState},

 

Question  2:   In  the  simple  client

 

client(Server_Address) -> Server_Address ! {request, self()}, receive

 

{hit_count,Number}   ->

 

io:format("CLIENT   ~w:   Hit   count   was   ~w~n",[self(),   Number])

 

end.

 

What  does  self()  do  and  why  is  it  used  in  this  example?

 

 

Question 3:    In the  simple  start() function  what  does the following line do?

 

spawn(simple,client,[Server_PID]).

 

5     Add functionality to the client and server

 

Start with the simple.erl file and add functionality by following the steps below. Submit the completed simple.erl file.

 

Step 1: Modify start() to take a single parameter which is the number of clients that have to be spawned. Don’t forget to modify the export directives correctly.

Step 2: The owner of the server should have the right to query the count without incrementing it. Modify the server by inserting code for the message:

{server_owner,Server_PID}

 

into the postion shown below

 

server(State) -> receive

 

{request,Return_PID}   ->

 

io:format("SERVER ~w: Client request received from ~w~n", [self(), Return_PID]) ,

 

NewState   =   State   +   1,

 

Return_PID ! {hit_count,NewState}, server(NewState) ;

 

{server_owner,Owner_PID}   ->

 

.......

 

end.

 

Step 3: Modify start() to have a single owner process that constantly queries the server for its state. You should fill in the ....s and decide on what other messages are passed between the server and the owner. You should print out the value received from the server using io:format.

 

owner(Server_PID)   ->

 

%% Use a random sleep in ms to simulate the owner traffic pattern. timer:sleep(random:uniform(100)),

 

Server_PID! .... , receive

 

{   ....   }   ->

 

..... , io:format(......) ,

 

owner(Server_PID) end.

 

Step 4: Give the owner the power to reset the server counter to 0. Modify the server as follows:

 

server(State) -> receive

 

{request,Return_PID}   ->

 

io:format("SERVER ~w: Client request received from ~w~n", [self(), Return_PID]) ,

 

NewState   =   State   +   1,

 

Return_PID ! {hit_count,NewState}, server(NewState) ;

 

        reset   ->

io:format(   ....   )   ,

server(....)

  end.

 

Again print out messages to demonstrate that the server has been reset.

 

Step 5: Now modify the owner process to reset the server counter if it exceeds 5. Hint: look at how the Erlang if statement works or how to use guards in Erlang receive statements.

 

6     Test  run

 

 

A test  run  of  the  finished  program  should  look  something  similar  to  this:

 

SERVER <0.27.0>: Client request received from <0.29.0>

CLIENT <0.29.0>: Hit count was 1

 

SERVER <0.27.0>: Owner query received from <0.28.0>

SERVER <0.27.0>: Client request received from <0.30.0>

 

OWNER <0.28.0>: Hit count is 1

CLIENT <0.30.0>: Hit count was 2

 

SERVER <0.27.0>: Owner query received from <0.28.0>

SERVER <0.27.0>: Client request received from <0.31.0>

 

OWNER <0.28.0>: Hit count is 2 CLIENT <0.31.0>: Hit count was 3

 

SERVER <0.27.0>: Owner query received from <0.28.0>

SERVER <0.27.0>: Client request received from <0.32.0>

 

OWNER <0.28.0>: Hit count is 3

CLIENT <0.32.0>: Hit count was 4

 

SERVER <0.27.0>: Owner query received from <0.28.0>

SERVER <0.27.0>: Client request received from <0.33.0>

 

OWNER <0.28.0>: Hit count is 4

CLIENT <0.33.0>: Hit count was 5

 

SERVER <0.27.0>: Owner query received from <0.28.0>

SERVER <0.27.0>: Client request received from <0.34.0>

 

OWNER <0.28.0>: Hit count is 5

CLIENT <0.34.0>: Hit count was 6

 

SERVER <0.27.0>: Owner query received from <0.28.0>

SERVER <0.27.0>: Client request received from <0.35.0>

 

OWNER   <0.28.0>:   Hit   count   is   6,   send   reset   message....

 

CLIENT   <0.35.0>:   Hit   count   was   7

 

SERVER <0.27.0>: Owner reset message received

SERVER <0.27.0>: Owner query received from <0.28.0>

SERVER <0.27.0>: Client request received from <0.36.0>

OWNER <0.28.0>: Hit count is 0

CLIENT   <0.36.0>:   Hit   count   was   1

SERVER <0.27.0>: Owner query received from <0.28.0>

SERVER <0.27.0>: Client request received from <0.37.0>

OWNER <0.28.0>: Hit count is 1

CLIENT <0.37.0>: Hit count was 2

SERVER <0.27.0>: Owner query received from <0.28.0>

SERVER <0.27.0>: Client request received from <0.38.0>

 

Note: The server hit count may not be immediately reset once the owner process discover the count to exceed the limit (5). This is due to client requests being received by the server before the owner reset message is received by the server.