ProgramThis
November 6th, 2009, 07:44 AM
Alright, I've answered enough questions to hopefully have one of my own answered :p
I am trying to write a distributed system in which I will have several servers (written in Java) that will all have the same data store on them. The goal of the application is to demonstrate data replication. So, if a client connects to a server (randomly chosen from a list of available servers), and he updates a piece of the data store (for simplicity I have chosen an int array), then the other servers need to notify each other that an update has been made and they must bring their data store up to the latest version.
I do not have access to multiple machines (as this needs to work on a single machine for testing / demonstration), so what I am trying to do is set up the servers simply to run on different ports on the rmiregistry.
Here is the interface message stub:
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface MessageInterface extends Remote {
boolean sendUpdate(int index, int value) throws RemoteException;
boolean sendBroadcast(int data[]) throws RemoteException;
void broadcastInvalidate(int index) throws RemoteException;
int[] getDateStore() throws RemoteException;
int getSingleDataValue(int index) throws RemoteException;
}Here is the Server implementing the interface:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
public class Server extends UnicastRemoteObject implements MessageInterface {
private static final long serialVersionUID = -4982932302868830173L;
private ArrayList<Server> servers = new ArrayList<Server>();
private ArrayList<Integer> data = new ArrayList<Integer>();
private String serverName;
private int port;
public Server() throws RemoteException { super(); }
public void broadcastInvalidate(int index) throws RemoteException {
for(Server s : servers) {
}
}
public int[] getDateStore() throws RemoteException {
int[] intArray = new int[data.size()];
for (int i = 0; i < data.size(); i++) {
intArray[i] = data.get(i);
}
return intArray;
}
public int getSingleDataValue(int index) throws RemoteException {
System.out.println("Client requested data at index: " + index);
return data.get(index);
}
public boolean sendBroadcast(int[] data) throws RemoteException {
return false;
}
public boolean sendUpdate(int index, int value) throws RemoteException {
return false;
}
public void setServerName(String name) {
this.serverName = name;
}
public String getServerName() {
return this.serverName;
}
public void displayStartupMessage() {
StringBuilder sb = new StringBuilder();
sb.append("***********************************************************");
sb.append("****************** Welcome to FooServer *****************");
sb.append("***********************************************************");
System.out.println(sb);
}
public void getPort(BufferedReader br) throws IOException {
System.out.println("**** Please enter a port for the Server to listen on ****");
boolean isInteger = false;
while(!isInteger) {
System.out.print("**** port: ");
String port = br.readLine();
try {
this.port = Integer.parseInt(port);
isInteger = true;
} catch(NumberFormatException ne) {
System.out.println("**** ERROR: You have entered an invalid port, please try again.");
}
}
}
public void testData() {
data.add(11);
data.add(12);
data.add(13);
data.add(14);
data.add(15);
data.add(16);
data.add(17);
data.add(18);
data.add(19);
}
}
I am using a Master Server in order to generate the servers (only 1 so far)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.rmi.AlreadyBoundException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
public class MasterServer {
private int port;
public static void main(String[] args) {
try {
MasterServer ms = new MasterServer();
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
Server server = new Server();
server.testData();
server.displayStartupMessage();
server.getPort(br);
server.setServerName("Server"+ms.port);
UnicastRemoteObject.unexportObject(server, true);
MessageInterface stub = (MessageInterface) UnicastRemoteObject.exportObject(server,ms.port);
Registry registry = LocateRegistry.getRegistry();
try {
registry.bind(server.getServerName(), stub);
} catch(AlreadyBoundException ae) {
registry.rebind(server.getServerName(), stub);
}
} catch(IOException e) {
e.printStackTrace();
System.exit(1); // Force an exit because there might be other threads
} catch (Exception e) {
e.printStackTrace();
System.err.println("Usage: java [-Dbankname=<name>] RemoteBankServer");
System.exit(1); // Force an exit because there might be other threads
}
}
}
And of course, what would we do without a client:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.rmi.Naming;
import java.rmi.RMISecurityManager;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class Client {
private static void displayStartupMessage() {
StringBuilder sb = new StringBuilder();
sb.append("***********************************************************");
sb.append("****************** Welcome to FooClient *****************");
sb.append("***********************************************************");
System.out.println(sb);
}
public static void main(String[] args) {
try {
Client.displayStartupMessage();
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String input = "";
while(!input.equalsIgnoreCase("exit")) {
System.setSecurityManager(new RMISecurityManager());
String url = "rmi:///Server2000";
MessageInterface server = null;
Registry r = LocateRegistry.getRegistry(2000);
server = (MessageInterface)r.lookup("Server2000");
System.out.println("\nPlease enter a command from the following:\n");
System.out.println("sdv - Single data value followed by the index (ex 'sdv 4'");
System.out.println("exit - quit application");
input = br.readLine();
String values[] = input.split(" ");
if (values[0].equalsIgnoreCase("sdv") && values.length == 2) {
int x = Integer.parseInt(values[1]);
int n = server.getSingleDataValue(x);
System.out.println("Value at x = " + n);
}
else System.out.println("Unknown command");
}
} // Catch and display RMI exceptions
catch (RemoteException e) {
e.printStackTrace();
} // Other exceptions are probably user syntax errors, so show usage.
catch (Exception e) {
e.printStackTrace();
System.err.println("Usage: java [-Dbank=<url>] Bank$Client " +
"<cmd> <name> <password> [<amount>]");
System.err.println("where cmd is: open, close, deposit, " +
"withdraw, balance, history");
}
}
}I have read a few tutorials on using RMI. Most everything that I find says "why would you want to listen on a different port than 1099?" Well, I do :D. So I start up my rmiregistry as such:
>rmiregistry 2000
And then my Master server and I get:
C:\webapps\workspace\Replication\src>java -Djava.security.policy=c:\webapps\workspace\Replication\src\wideopen.policy MasterServer
***************************************************************************** Welcome to FooServer ********************************
**** Please enter a port for the Server to listen on ****
**** port: 2000
java.rmi.ConnectException: Connection refused to host: 192.168.114.107; nested exception is:
java.net.ConnectException: Connection refused: connect
at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:601)
at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:198)
at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:184)
at sun.rmi.server.UnicastRef.newCall(UnicastRef.java:322)
at sun.rmi.registry.RegistryImpl_Stub.bind(Unknown Source)
at MasterServer.main(MasterServer.java:48)
Caused by: java.net.ConnectException: Connection refused: connect
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:333)
at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:195)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:182)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)
at java.net.Socket.connect(Socket.java:519)
at java.net.Socket.connect(Socket.java:469)
at java.net.Socket.<init>(Socket.java:366)
at java.net.Socket.<init>(Socket.java:180)
at sun.rmi.transport.proxy.RMIDirectSocketFactory.createSocket(RMIDirectSocketFactory.java:22)
at sun.rmi.transport.proxy.RMIMasterSocketFactory.createSocket(RMIMasterSocketFactory.java:128)
at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:595)
... 5 more
Now, granted the port may be blocked here at work (I know, get back to work!), but at school I get security exceptions, at home the same (I will post them later when I get there).
I have several questions that I am not finding the answer to online.
First:
How do I set up the system to allow multiple servers? Can they all listen on the same port or do I need to bind them to different ports (different as far as I know, but maybe the registry will dish out requests based on name over the same port, this isn't clear from the documentation I have found)? If I need to bind each server to a different port, how do I get the rmiregistry to listen on multiple ports when it only takes one argument? Java RMI (http://java.sun.com/j2se/1.3/docs/tooldocs/solaris/rmiregistry.html)
Secondly:
When I was getting the security exception, this was at the school, with no ports being blocked. Am I doing something wrong in the client when I try to locate the registry? From all of the examples I have seen online, this is the way to do it, I just don't see what I am doing wrong.
Thanks,
I am trying to write a distributed system in which I will have several servers (written in Java) that will all have the same data store on them. The goal of the application is to demonstrate data replication. So, if a client connects to a server (randomly chosen from a list of available servers), and he updates a piece of the data store (for simplicity I have chosen an int array), then the other servers need to notify each other that an update has been made and they must bring their data store up to the latest version.
I do not have access to multiple machines (as this needs to work on a single machine for testing / demonstration), so what I am trying to do is set up the servers simply to run on different ports on the rmiregistry.
Here is the interface message stub:
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface MessageInterface extends Remote {
boolean sendUpdate(int index, int value) throws RemoteException;
boolean sendBroadcast(int data[]) throws RemoteException;
void broadcastInvalidate(int index) throws RemoteException;
int[] getDateStore() throws RemoteException;
int getSingleDataValue(int index) throws RemoteException;
}Here is the Server implementing the interface:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
public class Server extends UnicastRemoteObject implements MessageInterface {
private static final long serialVersionUID = -4982932302868830173L;
private ArrayList<Server> servers = new ArrayList<Server>();
private ArrayList<Integer> data = new ArrayList<Integer>();
private String serverName;
private int port;
public Server() throws RemoteException { super(); }
public void broadcastInvalidate(int index) throws RemoteException {
for(Server s : servers) {
}
}
public int[] getDateStore() throws RemoteException {
int[] intArray = new int[data.size()];
for (int i = 0; i < data.size(); i++) {
intArray[i] = data.get(i);
}
return intArray;
}
public int getSingleDataValue(int index) throws RemoteException {
System.out.println("Client requested data at index: " + index);
return data.get(index);
}
public boolean sendBroadcast(int[] data) throws RemoteException {
return false;
}
public boolean sendUpdate(int index, int value) throws RemoteException {
return false;
}
public void setServerName(String name) {
this.serverName = name;
}
public String getServerName() {
return this.serverName;
}
public void displayStartupMessage() {
StringBuilder sb = new StringBuilder();
sb.append("***********************************************************");
sb.append("****************** Welcome to FooServer *****************");
sb.append("***********************************************************");
System.out.println(sb);
}
public void getPort(BufferedReader br) throws IOException {
System.out.println("**** Please enter a port for the Server to listen on ****");
boolean isInteger = false;
while(!isInteger) {
System.out.print("**** port: ");
String port = br.readLine();
try {
this.port = Integer.parseInt(port);
isInteger = true;
} catch(NumberFormatException ne) {
System.out.println("**** ERROR: You have entered an invalid port, please try again.");
}
}
}
public void testData() {
data.add(11);
data.add(12);
data.add(13);
data.add(14);
data.add(15);
data.add(16);
data.add(17);
data.add(18);
data.add(19);
}
}
I am using a Master Server in order to generate the servers (only 1 so far)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.rmi.AlreadyBoundException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
public class MasterServer {
private int port;
public static void main(String[] args) {
try {
MasterServer ms = new MasterServer();
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
Server server = new Server();
server.testData();
server.displayStartupMessage();
server.getPort(br);
server.setServerName("Server"+ms.port);
UnicastRemoteObject.unexportObject(server, true);
MessageInterface stub = (MessageInterface) UnicastRemoteObject.exportObject(server,ms.port);
Registry registry = LocateRegistry.getRegistry();
try {
registry.bind(server.getServerName(), stub);
} catch(AlreadyBoundException ae) {
registry.rebind(server.getServerName(), stub);
}
} catch(IOException e) {
e.printStackTrace();
System.exit(1); // Force an exit because there might be other threads
} catch (Exception e) {
e.printStackTrace();
System.err.println("Usage: java [-Dbankname=<name>] RemoteBankServer");
System.exit(1); // Force an exit because there might be other threads
}
}
}
And of course, what would we do without a client:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.rmi.Naming;
import java.rmi.RMISecurityManager;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class Client {
private static void displayStartupMessage() {
StringBuilder sb = new StringBuilder();
sb.append("***********************************************************");
sb.append("****************** Welcome to FooClient *****************");
sb.append("***********************************************************");
System.out.println(sb);
}
public static void main(String[] args) {
try {
Client.displayStartupMessage();
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String input = "";
while(!input.equalsIgnoreCase("exit")) {
System.setSecurityManager(new RMISecurityManager());
String url = "rmi:///Server2000";
MessageInterface server = null;
Registry r = LocateRegistry.getRegistry(2000);
server = (MessageInterface)r.lookup("Server2000");
System.out.println("\nPlease enter a command from the following:\n");
System.out.println("sdv - Single data value followed by the index (ex 'sdv 4'");
System.out.println("exit - quit application");
input = br.readLine();
String values[] = input.split(" ");
if (values[0].equalsIgnoreCase("sdv") && values.length == 2) {
int x = Integer.parseInt(values[1]);
int n = server.getSingleDataValue(x);
System.out.println("Value at x = " + n);
}
else System.out.println("Unknown command");
}
} // Catch and display RMI exceptions
catch (RemoteException e) {
e.printStackTrace();
} // Other exceptions are probably user syntax errors, so show usage.
catch (Exception e) {
e.printStackTrace();
System.err.println("Usage: java [-Dbank=<url>] Bank$Client " +
"<cmd> <name> <password> [<amount>]");
System.err.println("where cmd is: open, close, deposit, " +
"withdraw, balance, history");
}
}
}I have read a few tutorials on using RMI. Most everything that I find says "why would you want to listen on a different port than 1099?" Well, I do :D. So I start up my rmiregistry as such:
>rmiregistry 2000
And then my Master server and I get:
C:\webapps\workspace\Replication\src>java -Djava.security.policy=c:\webapps\workspace\Replication\src\wideopen.policy MasterServer
***************************************************************************** Welcome to FooServer ********************************
**** Please enter a port for the Server to listen on ****
**** port: 2000
java.rmi.ConnectException: Connection refused to host: 192.168.114.107; nested exception is:
java.net.ConnectException: Connection refused: connect
at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:601)
at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:198)
at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:184)
at sun.rmi.server.UnicastRef.newCall(UnicastRef.java:322)
at sun.rmi.registry.RegistryImpl_Stub.bind(Unknown Source)
at MasterServer.main(MasterServer.java:48)
Caused by: java.net.ConnectException: Connection refused: connect
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:333)
at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:195)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:182)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)
at java.net.Socket.connect(Socket.java:519)
at java.net.Socket.connect(Socket.java:469)
at java.net.Socket.<init>(Socket.java:366)
at java.net.Socket.<init>(Socket.java:180)
at sun.rmi.transport.proxy.RMIDirectSocketFactory.createSocket(RMIDirectSocketFactory.java:22)
at sun.rmi.transport.proxy.RMIMasterSocketFactory.createSocket(RMIMasterSocketFactory.java:128)
at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:595)
... 5 more
Now, granted the port may be blocked here at work (I know, get back to work!), but at school I get security exceptions, at home the same (I will post them later when I get there).
I have several questions that I am not finding the answer to online.
First:
How do I set up the system to allow multiple servers? Can they all listen on the same port or do I need to bind them to different ports (different as far as I know, but maybe the registry will dish out requests based on name over the same port, this isn't clear from the documentation I have found)? If I need to bind each server to a different port, how do I get the rmiregistry to listen on multiple ports when it only takes one argument? Java RMI (http://java.sun.com/j2se/1.3/docs/tooldocs/solaris/rmiregistry.html)
Secondly:
When I was getting the security exception, this was at the school, with no ports being blocked. Am I doing something wrong in the client when I try to locate the registry? From all of the examples I have seen online, this is the way to do it, I just don't see what I am doing wrong.
Thanks,