How to do naming system with RMI in different hosts? - java

I have two java classes one is the client and the other is the server, in the client I have to give the server ip address, but I want to make it dynamique so the client knows the ip of a third machine(naming system) which search for the method (like DNS) and returns the ip address of the specific server who provides this method.
Edited:
classe client :
public class Client {
private Client() {}
public static void main(String[] args) {
String host = (args.length < 1) ? null : args[0];
try {
//Registry registry = LocateRegistry.getRegistry(host);
Registry registry = LocateRegistry.getRegistry("192.168.1.9",1091);
Calculator stub = (Calculator) registry.lookup("Hello");
String response = stub.add(4,2);
System.out.println("response: " + response);
} catch (Exception e) {
System.err.println("Client exception: " + e.toString());
e.printStackTrace();
}
}
}
server :
public class Server implements Calculator{
public Server() {}
public String add(int a,int b) {
return "Hello, a+b= "+(a+b);
}
public String sub(int a,int b) {
return "Hello, a-b= "+(a-b);
}
public static void main(String args[]) {
try {
Server obj = new Server();
Calculator stub = (Calculator) UnicastRemoteObject.exportObject(obj, 0);
// Bind the remote object's stub in the registry
Registry registry = LocateRegistry.createRegistry(1091);
registry.bind("Hello", stub);
System.err.println("Server ready");
} catch (Exception e) {
System.err.println("Server exception: " + e.toString());
e.printStackTrace();
}
}
}

You can't do this with the RMI Registry. Only a process running in the same host as the Registry can bind to it. You would have to use a different naming service such as LDAP.
However the rest of your description is what RMI already does. You look up a name in the Registry and it returns you a stub that knows how to communicate with the corresponding remote object.

Related

java rmi notboundexception

I'm trying to develop. My RMI code Initiation that had Server/Client locally for learning purposes. The server part had two interfaces Echo & Sum implemented in the serverRMI and I tried to call from the client side but got this error. Does anyone have any ideas how I can resolve this?
Server.java
public class Server {
public static void main(String[] args) {
try {
MyServerRMI server = new MyServerRMI();
LocateRegistry.createRegistry(1099);
Naming.rebind("rmi://localhost:1099/Server", server);
System.out.println("Server is ready for clients to connect");
} catch (Exception e) {
System.out.println("Server failed: " + e);
}
}
}
MyServerRMI
public class MyServerRMI extends UnicastRemoteObject implements EchoInterface, SumInterface {
public MyServerRMI() throws RemoteException {
super();
}
public String echo(String s) throws RemoteException {
return s;
}
public int sum(int a, int b) throws RemoteException {
return a + b;
}
}
MyClientRMI
public class MyClientRMI {
public static void main(String[] args) {
try {
EchoInterface objetEcho = (EchoInterface) Naming.lookup("rmi://localhost:1099/server");
SumInterface objetSum = (SumInterface) Naming.lookup("rmi://localhost:1099/server");
System.out.println("Echo: " + objetEcho.echo("Hello World from RMI server"));
System.out.println("Sum: " + objetSum.sum(5, 10));
} catch (Exception e) {
System.out.println("Client failed: " + e);
}
}
}
You have not associated the bindings in the client. To do that, you should use:
Registry registry = LocateRegistry.getRegistry(host);
or
Registry registry = LocateRegistry.getRegistry(port);
and then
EchoInterface objetEcho = (EchoInterface) registry.lookup("rmi://localhost:1099/server");
SumInterface objetSum = (SumInterface) registry.lookup("rmi://localhost:1099/server");
also, please use
e.printStackTrace();
instead of just printing e, as the stack trace provides a lot more information.

Java RMI: how to make client stub method called on server print message on client screen?

I'm making a chat with rmi in Java. I have one server object and at least two clients objects. When a client send a message to the server calling the method recebeMensagem remotely, the server must print that message on all clients' screen (except the client that sent the message).
The client class has a method printMenssagem(Mensagem msg), that is called remotely by the server. The problem is that that method is printing on server's screen. How do I make to print the message on client's screen instead?
Server.java:
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.function.Predicate;
public class Server implements ChatServer {
private ArrayList<String> listaClientes = new ArrayList<>();
private static int port = 5002;
public static void main(String[] args) {
try {
Server obj = new Server();
ChatServer stub = (ChatServer)
UnicastRemoteObject.exportObject(obj, port);
// Bind the remote object's stub in the registry
Registry registry = LocateRegistry.createRegistry(port);
registry.bind("chat", stub);
System.out.println("Server ready!");
} catch (Exception e) {
System.err.println("Server exception: " + e.toString());
e.printStackTrace();
}
}
#Override
public void adicionaCliente(String user) {
this.listaClientes.add(user);
}
#Override
public void retiraCliente(String userName) {
Predicate<String> clientePredicate = cp ->
cp.equals(userName);
listaClientes.removeIf(clientePredicate);
try {
Registry registry = LocateRegistry.getRegistry(port);
registry.unbind(userName);
} catch (RemoteException e) {
e.printStackTrace();
} catch (NotBoundException e) {
e.printStackTrace();
}
}
#Override
public void recebeMensagem(Mensagem msg) {
try {
Registry registry = LocateRegistry.getRegistry(port);
for(String cliente : listaClientes) {
if (!cliente.equals(msg.getRemetente())) {
Client stub = (Client) registry.lookup(cliente);
stub.printMensagem(msg);
}
}
} catch (RemoteException e) {
e.printStackTrace();
} catch (NotBoundException e) {
e.printStackTrace();
}
}
public ArrayList<String> getListaClientes() {
return listaClientes;
}
public void setListaClientes(ArrayList<String> listaClientes) {
this.listaClientes = listaClientes;
}
}
Client.java :
import java.io.Serializable;
import java.rmi.Remote;
public class Client implements Remote, Serializable {
private static final long serialVersionUID = 6864579049922061838L;
private static int port = 5002;
private static String host = "127.0.0.1";
public static void main(String[] args) {
new Thread(new ClientInterface(host, port)).start();
}
public void printMensagem(Mensagem mensagem) {
System.out.println(mensagem.getRemetente() + ": " + mensagem.getMensagem());
}
}
how to make client stub method called on server print message on client screen?
The client doesn't have a stub. It isn't a remote object. It is a serializable object and it has been transported to the Registry holus bolus, and it runs in whatever JVM performed the Registry.lookup() to obtain it. This is not what you want. You want it to be a remote object, with a stub, so you have to make it implement a remote interface, and export it, and use it via its remote interface at the peer.
You also need to be aware that your present architecture won't work across more than one host, as you can't bind to a remote Registry. You will need to add a client registration method to the server.

Is it possible to synchronize two threads over shared Remote Object?

public class RMIClient {
public static void main(String[] args) {
String serverURL = "rmi://" + args[0] + "/GameServer";
String viewURL = "rmi://" + args[0] + "/ViewServer";
try {
GameInterface gameIntf = (GameInterface)Naming.lookup(serverURL);
PlayerView view = (PlayerView)Naming.lookup(viewURL);
while(!gameIntf.getGameOver()){
synchronized(GameInterface.sharedObject){
GameInterface.sharedObject.notify();
System.out.println(view.getMessage());
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
if(br.readLine().contains("y"))
gameIntf.setNextMove(true);
GameInterface.sharedObject.wait();
}
}
} catch (MalformedURLException | RemoteException | NotBoundException e1) {
e1.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public interface GameInterface extends Remote{
public static final Object sharedObject = new Object();
public void setNextMove(boolean val) throws RemoteException;
public boolean getGameOver() throws RemoteException;
}
Currently when I start rmiregistry, server and start two RMI clients, both clients wait forever after getting 1st input i. e. one client is not notifying other. I am starting RMI clients on same JVM.
No. The stub object at the client is not the same Java object as the remote server in the server host, and synchronizing on it or notifying it doesn't magically propagate across the network to the server or to other clients.
The answers in the link you cited don't support your theory either. You need to read the answers by #MarcH and me, and ignore the others, which are wrong in various ways.

java rmi multiple clients same application

I am trying to do an RMI mastermind application in java, where each client needs a separate game from the server, but somehow the combinations for each new client that runs are appended to one game, so it is as if each new client joins the main game.
Here is my server code:
public class MastermindServer
{
public static void main(String[] args) throws RemoteException, MalformedURLException
{
try
{
java.rmi.registry.LocateRegistry.createRegistry(1111);
System.out.println("RMI registry ready...");
}
catch (Exception e)
{
e.printStackTrace();
System.out.println("Exception starting RMI registry");
}
Naming.rebind("//localhost:1111/MastermindServer", new MastermindImplementation());
}
}
and my client code:
public class MastermindClient
{
private static MastermindMenuGUI menuFrame;
public static void main(String[] args)
{
System.out.println("before try catch");
try {
Registry clientRegistry = LocateRegistry.getRegistry("127.0.0.1",1111);
System.out.println("Client registry " + clientRegistry);
MastermindInterface game = (MastermindInterface) clientRegistry.lookup("theGame") ;
System.out.println("Client ready");
System.out.println(game.createCombination());
}
catch (Exception e) {
e.printStackTrace();
System.out.println("Exception in client");
}
}
}
How do I make a new separate game for each client?
Thanks in advance!
The object in the Registry should be a factory object. The client should look it up and then call a factory method which returns a new game, which should be another remote object.

no such object in table when calling registry.lookup

i am having a trouble when trying to run communication between server and client using RMI. My code is attached below. Server runs fine, i can see listening port in list of pc ports, client fails on registry.lookup. I didnt find any similar problem. Please help.
Server:
public class Main {
private static int port = Registry.REGISTRY_PORT;
private static Registry registry;
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
if (args.length == 1) {
try {
port = Integer.parseInt(args[0]);
}
catch (NumberFormatException e) {
System.out.println("Port number is not valid!");
System.exit(0);
}
}
if (System.getSecurityManager() == null)
System.setSecurityManager(new RMISecurityManager());
String name = "DBInterface";
System.out.println("Starting server.");
try {
DBInterface DBInterface = new DBClass();
DBInterface stub = (DBInterface) UnicastRemoteObject.exportObject(DBInterface, 5000);
registry = LocateRegistry.createRegistry(port);
registry.rebind(name, stub);
}
catch (RemoteException e)
{
System.out.println(e.getMessage());
}
System.out.println("Server succesfully started.");
}
}
Client:
public class Client {
private static String ipAddress = "localhost";
private static int port = Registry.REGISTRY_PORT;
private static String confFile = "";
public static DBInterface dbServer = null;
public static String name = "DBInterface";
public static void main(String[] args) {
System.out.println("Starting client.");
if (System.getSecurityManager() == null)
System.setSecurityManager(new RMISecurityManager());
if (args.length == 3) {
try {
ipAddress = args[0];
port = Integer.parseInt(args[1]);
confFile = args[2];
}
catch (NumberFormatException e) {
System.out.println("Port number is not valid!");
System.exit(0);
}
}
else
{
System.out.println("Some parameter is missing!");
System.out.println("Valid parameters are: IP(0) Port(1) Config_file_name(2).");
}
ArrayList<ArrayList<String>> commands = Tools.loadConfigFile(confFile);
Iterator<ArrayList<String>> commandsIterator = commands.iterator();
Registry registry;
try {
registry = LocateRegistry.getRegistry(ipAddress, port);
dbServer = (DBInterface) registry.lookup(name); //code fails here
} catch (RemoteException e) {
System.out.println(e.getMessage()); //"no such object in table" is printed on the screen
} catch (NotBoundException e) {
System.out.println(e.getMessage());
}
Tools tools = new Tools(dbServer);
...
What you describe is basically impossible. That exception means that the stub you are using, in this case a Registry, no longer refers to a live exported object in the target JVM. However as Registry stubs are created locally there is no opportunity for them to expire at all. The only mechanism would be the Registry you created exiting, but the static Registry reference should prevent that.
I would change a few things though:
DBInterface stub = (DBInterface) UnicastRemoteObject.exportObject(DBInterface, 5000);
registry = LocateRegistry.createRegistry(port);
Reverse these two lines, and use port for both the Registry and the export. You don't need two ports. Also, in all your catch blocks, never just suppress the exception message in favour of your own. You should always at least log the actual exception message.

Categories

Resources