IPC Remote Procedure Call by wON0m3


									                                        Operating systems
                      IPC Remote Procedure Call
Brian Bramer (thanks to Steve Rumsby for original notes)

Many distributed systems are built around a client/server model. Since the clients and the servers are on different
machines they have to communicate across a network, one can:

    1. use message passing with send/receive; is I/O oriented and quite complex to use. e.g. using TCP (virtual
       circuit) or UDP (datagram) from the TCP/IP stack means one has to
           a. TCP – set up the virtual circuit connection to a specified IP and port, set the data in the appropriate
                 form, then close the connection.
           b. UDP – create the datagram (e.g. an array of bytes) and send it to a specified IP and port number
    2. remote procedure call: the client makes a call to a server for some service and waits until the reply comes
       back. In practice the call looks like a normal program function or procedure call.

Remote procedure call was invented in 1984 by Birrell and Nelson, and was meant to look like a call to a local
procedure or function, except the procedure was executed on a remote machine.

Procedure call looks like:

dosomething(a, b, c);------- parameters --------> procedure dosomething
                <--------- results returned ----------

With RPC the procedure will be executed on a remote machine. The procedure call looks like a normal procedure call
in your program. The call has to go somewhere, though. It goes to a dummy procedure called a (client) stub.

                  Client machine                    network      server machine
 /---------\   - /-------------\    - /--------\        -     /--------\ - /--------\
 | users |------|     procedure |------| client |-------------| server |-----| server |
 | program |------| dosomething |------| stub |-------------| stub |-----|process |
 \---------/   ? \-------------/    ? \--------/        ?     \--------/ ? \--------/

The stubs implement RPC using message passing (hiding the complexities of message passing such as TCP from the
user), i.e.:

    1. The user programs calls dosomething with parameters like a normal program procedure.
    2. The client stub procedure gets the parameters off the stack, builds them into a network message and sends
       it off on to the network.
    3. At the other end, the server has a stub which takes the message, unpacks the parameters, builds it into a
       procedure call and calls the real dosomething in the server, e.g. print a file, get data from a database, etc.
    4. When dosomething returns, it returns to the server stub, which packs the results back into a message and
       sends it to the client stub.
    5. The client stub unpacks the message and builds a stack frame and returns to the user program.
    6. The user program takes the results off the stack and continues.

The stubs are normally generated for by a special interface compiler (e.g. RMIC in Java). You have to specify the
interface to the interface compiler. The interface contains details of the procedures the server is supplying and
their parameters. The parameters can be input, output, or input-output.

Operating systems: IPC Remote Procedure Call                                                                       1
Packing Parameters

This is known as parameter marshalling. The server might have several procedures that can be called, e.g. read
something, write something, etc., so we need to send the procedure name we want to call in the network packet
along with the parameters.


Problems can arise if the machines on the network are not all the same type. Clients and servers must be able to
communicate using a machine-independent data representation, e.g. problems could be:

    1. Might use different character sets e.g. ASCII v EBCDIC
    2. Might store multi-byte integers differently. Machines can be little endian (e.g. Intel 386) or big endian
       (e.g. Motorola 68000). Some machines can be either, depending on a switch value. For example, if we
       have hex 1234 stored in two bytes, in a little endian machine it is stored as:

                 byte    1 | 0
                        1 2 | 3 4

         and in a big endian machine it is

                 byte    1 | 0                 (or if you prefer byte    0 | 1
                        3 4  1 2                                        1 2 3 4 )

    3. Variable may be different lengths, e.g. C/C++ only specifies a minimum of 16 bits and in practice an int may be
       16, 32 or 64 bits
    4. Floating point - even more variation, although many machines now use IEEE format.
    5. Global variables - not in parameter list. Either prohibit or pass specially.

Using TCP or UDP the programmer usually has to sort this out – in Java this is done automatically using Seralization.

Operating systems: IPC Remote Procedure Call                                                                            2
Java RMI (Remote Method Invocation)
 see http://java.sun.com/javase/technologies/core/basic/rmi/index.jsp

The first thing is the server and client need to agree an interface which implements the communication. For example,
this interface has a single method which given the length and height of a rectangle returns the area:

// RMIarea.java           - the interface to RMIareaServer

import java.rmi.*;
public interface RMIarea extends Remote
  // pass rectange length and height and returns area
  public float area(float length, float height) throws RemoteException;

one then has to implement a server

// RMIareaServer.java -           receives rectangle data from RMI client and calculates area

import java.rmi.*;
import java.net.*;
import java.util.*;

public class RMIareaServer extends java.rmi.server.UnicastRemoteObject
       implements RMIarea
  // constructor
  public RMIareaServer() throws RemoteException

    // pass rectangle length and height and returns area
    public float area(float length, float height) throws RemoteException
       return length * height;

    // create the server
    public static void main(String args[])
        RMIareaServer server = new RMIareaServer();             // create server
        Naming.rebind("rmi://localhost/RMIareaServer", server); // register it with RMIregistry
        System.out.println("RMI area Server ready");
      catch (RemoteException re)                      // error! catch it!
        System.out.println("Remote Exception " + re);
      catch (Exception e)
        System.out.println(" Exception " + e);

Operating systems: IPC Remote Procedure Call                                                                           3
and implement a client which calls the server

// RMIareaClient.java - sends rectangle data to RMI server and gets area back

import java.rmi.*;

public class RMIareaClient
  public static void main(String args[])
      RMIarea server = (RMIarea) Naming.lookup("RMIareaServer");                // lookup RMI server
      System.out.println("rectangle 3.5 * 4.5 area = " + server.area(3.5f, 4.5f));        // call server
    catch (Exception e)
      System.out.println("Exception in main " + e);

Usually the server makes itself known to clients through some sort of naming service which give clients the address
they need to open a communication channel with the server. In the case of Java this is called the RMIregistry.

To run the client/server (the following assumes all the terminals are in the same directory)
    1.      compile the interface, then the server and client
    2.      create the stub using the RMIC compiler, i.e. rmic RMIareaServer
    3.      open a terminal and run the registry, i.e. RMIregistry
    4.      open a terminal and run the server, i.e. java RMIareaServer
    5.      open a terminal and run the client, i.e. java RMIareaClient

the client displays
    rectangle 3.5 * 4.5 area = 15.75

For more examples see http://www.cse.dmu.ac.uk/~bb/Teaching/NetWorks/Laboratory/RMI/

Note that the above example the client initiates the communication buy calling the method area() in the server. In this
case the server has no way of initiating communication with the client. However, this may be done using RMI callback
in which both the client and server implement interfaces. For an example see a chat program using RMIcallback


Operating systems: IPC Remote Procedure Call                                                                         4

So far it has all seemed relatively easy. To a programmer the RPC looks like a local procedure call. Unfortunately
though, a network of machines is less reliable than a single machine. There are 5 occasions where failure an occur.

1.   Client cannot locate server
2.   Message from client to server gets lost
3.   Reply from server to client gets lost
4.   Client crashes after sending message.
5.   Server crashes after receiving message


1. Client cannot locate server: Server might have crashed or be disconnected or not be running any more (New
   version might have changes in parameters - need to stop client talking to wrong version of server). Usually fatal.
   Print some soothing message.

2. Message from client to server gets lost: Time out and retransmit. Eventually conclude (1) if no response.

3. Reply from server to client gets lost: Have to be careful with retransmitting, since it could cause problems. The
   server (or client) might be slow or overloaded. Could end up doing operation more than once. E.g. transfer
   $1000000 from my bank account to your bank account. Ok for you, not so good for me. Have to incorporate
   sequence numbers.

4. Client crashes after sending message: If nothing done, server might have files locked etc. Means extra work
   (sending retries etc). We have an orphan process. It could get worse, the server might decide the client has
   crashed, and deletes all reference to the client. But it could be the client or the network was slow, and
   suddenly it re-appears. (Server pretends not to know (oops)).

5. Server crashes after receiving message: This is the really tricky one. It cannot be solved by uing sequence
   numbers. It all depends exactly when the server crashes.

Three scenarios :-

             -------                                 -------                       -------
request -->| receive |                  request -->| receive |        request -->| receive |
           | execute |                             | execute |                   | crash |
reply   <--| reply |                     ????   <--| crash |           ????   <--|   ???? |
             -------                                 -------                       -------
               (a)                                     (b)                           (c)

With (a) all works OK, no problems.
With (b) client doesn't want to repeat the operation
With (c) client wants to repeat the operation.

The ideal is to have exactly once semantics - (a). Either it does it exactly once or not at all. Unfortunately we can't
achieve this.

We can have:

(i) At least once semantics:
         if server fails, wait until it is fixed and try again
(ii) At most once semantics:
         if server fails give up and report failure.
         With ordinary procedures if server fails, so does the client, i.e. both are on same machine
(iii) Unknown number of times:
         might give up immediately or try again.

Operating systems: IPC Remote Procedure Call                                                                         5

To top