The main classes in your implementation will be:
Note that the scheme you produce will not precisely implement
the Amoeba protocol. In that protocol, messages are sent unreliably to
the sequencer in the first instance. In yours, messages to be multicast
are handed to the sequencer using RMI.
Don't set your sockets' time-to-live (TTL) to more than 1. That
way, your multicast packets will not be transmitted beyond the local Mbone
router.
Teams are required to demonstrate their implementation. The demonstration
should include as many as possible of the following features: simple message
sending, stress-testing, recovery from simulated multicast datagram loss,
heartbeat messages and history truncation.
import java.rmi.*;
import java.net.*;
import java.io.*;
public interface Sequencer extends Remote
{
// join -- request for "sender" to join sequencer's
multicasting service;
// returns an object specifying the multicast address
and the first sequence number to expect
public SequencerJoinInfo join(String sender)
throws RemoteException,
SequencerException;
// send -- "sender" supplies the msg to be sent,
its identifier,
// and the sequence number of the last received
message
public void send(String sender, byte[] msg, long msgID,
long lastSequenceReceived)
throws RemoteException;
// leave -- tell sequencer that "sender" will no
longer need its services
public void leave(String sender)
throws RemoteException;
// getMissing -- ask sequencer for the message whose
sequence number is "sequence"
public byte[] getMissing(String sender, long sequence)
throws RemoteException,
SequencerException;
// heartbeat -- we have received messages up to number
"lastSequenceReceived"
public void heartbeat(String sender, long lastSequenceReceived)
throws RemoteException;
}
import java.io.*;
import java.net.*;
public class SequencerJoinInfo implements Serializable
{
public InetAddress addr;
public long sequence;
public SequencerJoinInfo(InetAddress addr, long sequence)
{
this.addr = addr;
this.sequence = sequence;
}
}
import java.io.*;
public class SequencerException extends Exception implements Serializable
{
public SequencerException(String s)
{
super(s);
}
}
import java.net.*;
import java.util.*;
import java.io.*;
import java.rmi.*;
public class Group implements Runnable
{
public Group(String host, MsgHandler handler,
String senderName) throws GroupException
{
// contact Sequencer on "host"
to join group,
// create MulticastSocket and
thread to listen on it,
// perform other initialisations
}
public void send(byte[] msg) throws GroupException
{
// send the given message
to all instances of Group using the same sequencer
}
public void leave()
{
// leave group
}
public void run()
{
// repeatedly: listen to
MulticastSocket created in constructor, and on receipt
// of a datagram call "handle"
on the instance
// of Group.MsgHandler which
was supplied to the constructor
}
public interface MsgHandler
{
public void handle(int
count, byte[] msg);
}
public class GroupException extends Exception
{
public GroupException(String
s)
{
super(s);
}
}
public class HeartBeater extends Thread
{
// This thread sends heartbeat
messages when required
}
}
After marshalling, the data can be obtained from bstream for inclusion in a DatagramPacket:
byte[] theData = bstream.toByteArray();
(For unmarshalling there are corresponding classes ByteArrayInputStream
and DataInputStream.)