CSC 125/259 : Distributed Horse Race Assignment This assignment requires you to apply basic sychronization techniques in a distributed setting. Ideally you should use several computers to run the experiment, but the processes can also be executed on the same computer. The basic idea is to have the same horserace displayed on all screens. No horse should have an advantage over other horses just because they're running on a faster machine or have a faster connection to the server. In a properly synchronized program each horse should have an equal chance to win the race. You may want to first watch the demo video to get an idea as to what the program should do. On the class webpage you will find a series of files pertaining to this project. The only one that you would need to edit is the file hrserver.java. However, you need to study some of the other files carefully as well. hrserver.java is a skeleton and DOES NOT WORK. You want to produce a program that works correctly. The horserace is coordinated by an RMI Remote object. The file horserace.java contains the interface for this object: public interface horserace extends Remote { raceinfo joinrace(String name) throws RemoteException; raceinfo moveForward(int id, int step) throws RemoteException; raceinfo quitrace(int id) throws RemoteException; } "raceinfo" is a "serializable" class, which represents objects that can be passed to a remote method and be returned by a remote method. One fundamental difference between using remote objects and local objects is that one cannot just pass pointers to remote sites. Java's primitive types int, double, String are already serializable. An array is serializable if its elements are serializable. Similarly, a class can be declared serializable if all of its constituents are serializable. Study the raceinfo and associated horse serializable classes carefully. The horse class contains basic information for each horse, such as its name and current position in the race. The x coordinate will change as the race runs. public class horse implements java.io.Serializable { boolean inrace; int x; int y; // screen coordinates of horse, y is constant String name; public horse(boolean i, int x0, int y0, String n) { inrace=i; x=x0; y=y0; name=n; } } The raceinfo class consists principally of an array of horse objects: class raceinfo implements java.io.Serializable { byte id; // id of racer - used only at the beginning horse[] horses; public raceinfo(byte i, horse[] h) {id=i; horses=h;} } It is this structure that is returned by the Remote synchronization object's method - it tells each client where to display each horse. The one-byte id number is assigned by the server to each client, and determines the position in the array of each client. ================ horserace remote methods ================= The main part of your assignment is to complete the implementations of the following two remote methods: raceinfo joinrace(String name) throws RemoteException; raceinfo moveForward(int id, int step) throws RemoteException; When a horserace server is started, it will expect a certain number of horses (clients) to join the race. The threads that are executing each joinrace call need to block until all horses have joined the race. At this time the server returns a raceinfo structure to each client, which informs the client of what horses are in the race, as well as the position in the array (id) the client has been assigned to. All graphics and animation is handled by the hrclient program, and you don't have to touch this. However, you need to understand that each client program will run in a loop that repeatedly generates a random number "steps", and calls newinfo = hrserver.moveForward(id,steps); The call to moveForward informs the server/coordinator that horse id should have its x coordinate changed by steps amounts. You'll have to figure how this method may have to be synchronized. This method returns a new raceinfo structure which will allow each client display to be updated accordingly. In the file hrserver.nosynch, you will find half-written versions of joinrace and moveForward that "need fix'in". So please fix them, then change the name of the file to hrserver.java ------ To run the experiment: First make sure you have javac installed: "which javac" Download all horserace files into a separate directory. Correct write hrserver.java javac *.java rmiregistry & - starts the rmiregistry. There only needs to be one registry for multiple clients. This steps only needs to be done once java hrserver 4 10.1.0.1 - starts the synchronization server, where 10.1.0.1 is the sample ip adress of the machine that's running the rmiregistry and 4 is the number of horses that the server is expecting to join the race On each client : java hrclient "speedy racer" 10.1.0.1 40 This starts a client, naming the horse and the ip address of the registry from which it will look up hrserver. The last parameter 40 is IMPORTANT: it represents the time in milliseconds your client will delay between iterations of its main loop; that is, between calls to moveForward. When running the experiment, be sure to use DIFFERENT delay values for each client. Also, please use ip address instead of hostnames like "thincrust" - this is a problem with RMI that took me many days to figure out! ============= 2 : Fault Tolerence ============== What happens if a client suddenly quits the race. If you're lucky, the client will call quitrace to register the quit, but nobody has that much luck. Most likely the client will simply kill the program. You need to implement a mild form of fault tolerence. The calls to wait() in your methods need to take a timeout value (4000 milliseconds should be more than enough). When the specified time has occured, the program proceeds just as if the waiting thread has been notified. To tell if your wait(4000) was notified or timed out, you need to use other boolean conditions. Your program should continue to run after somebody stops their client program. The position of that horse should no longer change Please be aware that this problem may be A LOT trickier than it may appear. You need to keep reminding yourself that multiple threads are executing the same code, but some actions must only be done once! In any case, this is only a "mild" form of fault tolerence because everything depends on a centralized server for coordination. But what if the server dies? Can we have a backup server so that the programs can continue to run? Such a degree of fault tolerence might not be so critical for multiplayer games, but imagine an air-traffic control system, for example.