CSE515 Distributed Computing Systems

Winter 2004

 
 

Homework 3: Implement a Remote Message System

Problem Summary

For this Homework you are required to implement a simplified Remote Message Send (RMS) Mechanism for Java (or another Object-Oriented language). This mechanism will be similar in functionality to Java RMI. 

I expect most students to do this assignment in Java; it is easiest in Java because we provide some of the pieces for you, and because the Java network interfaces are at a higher level than, say, the C interfaces. However, if you prefer you can choose to use some other object-oriented language.

Of course, Java already has a RMS mechanism - Java RMI. Java RMI already contains everything that you are required to produce for this assignment! The point of the homework is that you implement your own versions of the Java RMI components, not copy the ones provided by Sun. However, you are allowed to use other Java libraries, such as those providing socket communication, "serialization" and "reflection".

The purpose of the assignment is to help you gain a better understanding of RMS and RPC mechanisms.

Module Overview

This diagram shows the main components in the RMS system that you will be building.
  1. The gray boxes represent classes that are provided for you. 
    • The dark gray classes, CSE515Registry and RegistryClerk together implement the registry function.
    • The light gray classes, ZipCodeClient and ZipCodeServerImpl, are samples of typical client and server classes.
  2. The white rectangles represent code that you must provide or complete.
  3. The colored rectangles represent Java Virtual Machines (VMs). All of the objects inside one Virtual Machine can communicate using ordinary (local) Java message send. Between VMs, the only way to communicate is to use an operating system service, such as a network socket.
  4. To make your experience more authentic, please try running each VM on a separate physical machine. However, for debugging purposes, it may be convenient to run all three on the same physical machine.
  5. The CSE515Registry could run on a third machine, or it could run on the same machine as one of the other VMs.

How it works

Getting Started: lookup and rebind

Initially, CSE515Registry must be started (say, from the command line). It will wait for either a lookup request from the client or a rebind request from the server.

When the server (ZipCodeSeverImpl) initializes itself and is ready to service requests, it first registers itself in the CSE515Registry. It does this using the rebind method of a RegistryClerk. The server sends a Remote Object Reference (ROR) representing itself to the clerk, which transmits it to the registry. This ROR contains the address of the machine on which server its running, the port number through which clients can communication with the server, the remote interface name, and a uid identifying the specific server object.

Before the client can make a request to the server, it must first lookup the server in the registry to obtain an ROR. To do this, the client sends a lookup message to the RegistryClerk, which communicates with the registry for the client. In return, it gets the ROR from the registry. This contains the address of the server's machine and the port number on which it is listening. It also contains the remote interface name, which can be used for type checking: ideally, the Client should check that the interface of the stub is in fact the same as the interface of the server. (Why might it not be? Because either the client or the server might be a newer version ... )

Request/Reply

The stub performs the marshaling of the data and sends it over the socket to the server. On the remote host, YourRMI is waiting for the request from the client. 

Once YourRMI gets the request, it unmarshals the uid and then gets the skeleton for the corresponding object. The skeleton unmarshals the message and the arguments, and invokes the corresponding method on the server (ZipCodeServerImpl). The server would then process the request and reply to the skeleton, which would marshal the reply and send a network message back to the stub. Finally, the stub unmarshals the result and returns to the client.

What is the difference between YourRMI and skeleton? YourRMI is library code, and is written once (by you, the RMS implementor). The skeleton is generated by the stub generator; it is diferent for each remote interface. Each stub class has a corresponding skeleton.

Actually, there are some choices to be made about how much work is done by YourRMI and how much by the skeleton. YourRMI could do all of the unmarshaling, and could call the server object directly, rendering the skeleton unnecessary. In fact, the first implementation of Java RMI from Sun used a skeleton, whereas the current implementation does not.

Similarly, on the client side, the stub should do the work that is specific to the particular interface being implemented (ZipCodeDirectory), but the stub may want to use some library objects (written by you!) to take care of the generic work. In other words, the "generated" code in the stub should be limited to the code that really does change from one interface to another.

Code Provided:

  1. YourRMI.java: an outline of a server-side Communication Module. You must complete it.
  2. RORtbl.java: an outline of the implementation of the ROR table. You must complete it.

The Zip Code Example

In this assignment, we will be using the example of a server that maps town names to Zip Codes. 
  • A list of towns and their Zip codes is stored on the server.
  • The server can map a town name to a Zip code (method find),
  • The server can provide the entire list of towns and corresponding Zip codes to the sender (method findAll).
  • The server's list of towns and codes can be initialized (method initialize)
  • For debugging, the server can print the whole list on standard Output (method printAll).
The code provided for this is as follows.
  1. ZipCodeDirectory.java: defines the above interface.
  2. ZipCodeServerImpl.java: the zip code server implementation.
  3. ZipCodeList.java: A utility class used by the client and the ZipCodeServer
  4. ZipCodeClient.java: a client program.
  5. data.txt: Example data - towns and their Zip Codes.

The Registry, and Remote Object References.

The registry (sometimes called the binder ) is a separate service that maintains a table of mappings from textual names to Remote Object references. It is used by servers to register their remote objects by name, and by clients to look them up. It needs to be running when you try to initialize client-server communication. 

A Remote Object Reference is an object that contains all of the information necessary to initiate a remote message send: the address of the machine hosting the remote object, the port number for the server process, the object id of the object and interface that the object exports.

How is an Remote Objcet Reference different from a Proxy? They contain essentially the same information (or a reference to the same information). However, in Java the type system prevents them from being the same. The Proxy object has an interface that is identical to the object that it represents, and this will of course be different for each remote interface. Remote Object Reference instances have a method (localize) that creates the Proxy class instance.

The registry provides a way (not using RMS!) for the client to get the first Remote Object Reference (ROR), which is needed to send the first remote message. (Once the first message has been sent to an object, the reply can contain additional remote object references.)

The classes provided are:

  1. CSE515Registry.java: the registry program itself. It creates the table and stores the mapping.
  2. RegistryThread.java: a utility class used by the registry program.
  3. RegistryClerk.java: the class that defines the behavior of a RegsitryClerk. To create a clerk, use the constructor of this class. The clerk provides the lookup method for the client and the rebind method for the server.
  4. RemoteObjectRef.java: the class whose instances represent Remote Object References

What you should do:

  • Copy all of the sample programs to your own working directory. All of the code is here; it is also available as a zip archive, for easier copying. (Beware! The zipped versions have DOS line ending conventions.)
  • Complete the program YourRMI.java, so that it starts the ZipCodeServer.
  • Complete the class RORtbl.
  • Generate by Hand the client stubs for the ZipCodeDirectory. You are not required to write a stub compiler for this assignment. (You can do so if you wish.) Instead, write the stub object for this particular interface by hand.
  • If your design uses a server-specific skeleton (also called a server stub), generate the skeleton by hand too. Alternatively, you may choose not to have a skeleton, and to perform completely generic server-side unmarshaling and marshaling using reflection. 

  •  

     
     
     
     
     
     
     

    The stubs, which are the methods on the Proxy, marshall and send messages to the server module. The design to be followed for marshaling and unmarshaling can be one of the following:

    1. Use of Reflection;
    2. Use Java Serialization (this method is simpler).
    Refer to section 4.3.2 of Coulouris for more information. In both cases, make a stream out of the data and send it via a TCP socket.
  • Link your RMS system with the ZipCodeClient and Server provided, and test them.
  • Think about the following issue. When marshlling a reply from the server to the client, what should you do with objects in result? Should you marshal copies, or should you send back RORs to the original objects, which remain on the server. Write a paragraph summarizing your conclusions.
  • For extra credit, if you so desire (but not required!) 
    • Instead of using TCP, use UDP (DatagramSocket) and implement the Birrell and Nelson packet exchange protocol.
    • Time your implementation of remote messages in the same way as you did in assignment 2. This will require implementing another client and server.
    • Write a stub compiler. The input should be the interface of the service, e.g., ZipCodeDirectory.java

Executing the Programs

  1. On machine one.somedomain.net, run the registry program CSE515Registry
java CSE515Registry <registry port number>
    Note: Port numbers are integers in the range 0 to 65535; however, low numbered ports are reserved for system servers, and require system privileges.
  1. On your server machine: 
java YourRMI ZipCodeServerImpl one.somedomain.net <registryPortNumber> ZipCodeServer
    The YourRMI program takes as arguments:
    1. the name of the class that implements the service (ZipCodeServerImpl); 
    2. the IP address and port at which the registry can be found; and 
    3. the name of the service that will be advertised to the registry, a string (ZipCodeServer). 
  1. On your client machine 
Java ZipCodeClient one.somedomain.net <registryPortNumber> ZipCodeServer data.txt

Useful Resources

  • For socket programming , refer to classes java.net.Socket and java.net.ServerSocket in the Java API.
  • Refer to java.lang.Object and java.lang.Class of the Java API for the methods getClass(), newInstance(), etc,
  • For serialization, refer to the interface java.io.Serializable in the Java API. The Serialization Specification may be useful too.
  • For reflection, see the package java.lang.reflect.
  • Useful notes from Coulouris et al section 4.3.2 on how to serialize data in Java. 

A Final Caution

The code samples have passed through many hands. There may be bugs in them! If something looks bogus, ask the TA about it before you spend hours puzzling over it.