CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 5 of 5
  1. #1
    Join Date
    Feb 2008
    Posts
    966

    [RESOLVED] RMI Using different ports

    Alright, I've answered enough questions to hopefully have one of my own answered

    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:
    Code:
    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:
    Code:
    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)
    Code:
    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:
    Code:
    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 . 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

    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,

  2. #2
    Join Date
    Apr 2007
    Posts
    425

    Re: RMI Using different ports

    Just to back you up for a second here, is RMI really the best choice for doing this? It seems to me that a multi-cast protocol would work very nicely to notify all of the serves. Incidentally, there is a great library to use for such a task: http://www.jgroups.org/

    The other option is to use a message queue (apache activeMQ, or sun's implementation). anyone listening to that queue and topic can automatically read and process this message.
    ------
    If you are satisfied with the responses, add to the user's rep!

  3. #3
    Join Date
    May 2002
    Location
    Lindenhurst, NY
    Posts
    867

    Re: RMI Using different ports

    Just a couple of suggestions (not that technical though).

    Re: not having access to multiple machines:
    You could use VMWare or Virtual PC (VMWare Server & Virtual PC are free).

    And for your RMI problems, I'd suggest making something much more SSCCE-ish, till you work things out. For instance reduce the methods in your Remote interface from 5 methods to 1 simple 'testRmi' method.

  4. #4
    Join Date
    Feb 2008
    Posts
    966

    Re: RMI Using different ports

    I appreciate the suggestions.

    As for having 5 methods and testing one, I am only testing one of them, even though there are 5 stubs.

    As for libraries, I would LOVE to use one However, this is an assignment and we are required to reinvent the wheel, as most assignments go . We are supposed to be doing this at a very low level, and he wants us using either RMI in Java, or RPC in C.

  5. #5
    Join Date
    Feb 2008
    Posts
    966

    Re: RMI Using different ports

    Alright, after much frustration and trials I have found the solution

    If you are performing the LocateRegistry.createRegistry(port) and binding it, you do not need to perform the command line rmiregistry. That was confusing the system. So all I have to do now is start my server and then my clients and it all works nicely .

    Here is the code change for the master server in case anybody is interested.

    Code:
    public class MasterServer {
    
        public void displayStartupMessage() {
            StringBuilder sb = new StringBuilder();
            sb.append("***********************************************************");
            sb.append("******************  Welcome to FooServer  *****************");
            sb.append("***********************************************************");
            System.out.println(sb);
        }
    
        public int getPort(BufferedReader br) throws IOException {
            System.out.println("**** Please enter a port for the Server to listen on, enter 0 to finish ****");
            int port = 0;
            while (true) {
                System.out.print("****  port: ");
                String ports = br.readLine();
                System.out.println("You entered port: " + ports + "\n");
                try {
                    port = Integer.parseInt(ports);
                    break;
                } catch (NumberFormatException ne) {
                    System.out.println("****  ERROR: You have entered an invalid port, please try again.");
                }
            }
            return port;
        }
    
        private void createServers() throws IOException {
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            int port = 0;
            displayStartupMessage();
            while(true) {
                port = getPort(br);
                if(port==0)break;
                Server server = new Server();
                server.testData();
                server.setServerName("Server" + port);
                server.setPort(port);
                UnicastRemoteObject.unexportObject(server, true);
                MessageInterface stub = (MessageInterface) UnicastRemoteObject
                        .exportObject(server, port);
                Registry registry = LocateRegistry.createRegistry(port);
    
                try {
                    registry.bind(server.getServerName(), stub);
                } catch (AlreadyBoundException ae) {
                    registry.rebind(server.getServerName(), stub);
                }
                System.out.println("Listening on port: " + port + " to server: "
                        + server.getServerName());
            }
        }
    
        public static void main(String[] args) {
            try {
                MasterServer ms = new MasterServer();
                ms.createServers();
            } catch (IOException e) {
                e.printStackTrace();
                System.exit(1); // Force an exit because there might be other threads
            } catch (Exception e) {
                e.printStackTrace();
                System.exit(1); // Force an exit because there might be other threads
            }
        }
    }

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured