I want to build system so that : 1. Client connects to Server 2. Client asks for a port to server him 3. Server creates a remote object to serve the Client and binds it to a port 4. return the port number to client 5. Client connects to the port
My session/connection manager
public class ConnectionManager extends UnicastRemoteObject implements Server
{
public List<ClientHandler> clients = Collections.synchronizedList(new ArrayList<>());
public ConnectionManager() throws RemoteException
{
super();
}
public static final String RMI_ID = "Server";
@Override
public boolean checkConnection() throws RemoteException
{
return true;
}
@Override
public int getPort(String ip) throws RemoteException
{
int i = 10000+clients.size()*2;
clients.add(new ClientHandler(ip, i));
return i;
}
}
Session implementation
public class ClientHandler extends UnicastRemoteObject implements Transfer
{
Registry rmi;
Registry reg;
PrintWriter log;
public Client client;
public ClientHandler(String ip, int port) throws RemoteException
{
super();
try
{
File f = new File(ip+" "+new Date()+".txt");
log = new PrintWriter(f);
}catch (Exception e)
{
e.printStackTrace();
}
rmi = LocateRegistry.createRegistry(port);
try
{
rmi.bind(String.valueOf(port),this);
}catch(Exception e)
{
e.printStackTrace();
}
}
The problem that if the object is created in a remote call , it is considered of remote origin and so unless you are on the same host it is not allowed to bind one to the LocalRegistry. and server throws java.rmi.AccessException Registry.Registry.bind disallowed : origin IP address is non-local host.
Untrue. This is simply not correct. You've just made this up. Don't do that.
But you are on the same host. The constructor
ClientHandler
runs in the same host as theConnectionManager
and it creates aRegistry,
also in the same host. Indeed all this takes place within the same JVM.No it doesn't. I tested your code. After fixing a compilation error it worked. Cannot reproduce.
HOWEVER
You don't need the part about the port, or the extra bind. All remote objects can share the same port. The server only needs to return a new instance of the remote session object to the client, directly.
A simple implementation of your requirement, using your classnames, looks like this, with a certain amount of guesswork as you didn't provide the
Server
interface:EDIT
It is clear from your post and your comment below that you are suffering from a number of major misconceptions about Java RMI:
The port on which an object is exported has nothing to do with the Registry.
It is determined when you construct an object that extends
UnicastRemoteObject
, via thesuper()
, call, or when you callUnicastRemoteObject.exportObject()
for other objects. If you supply a non-zero port number, that port is used, and can normally shared with other remote objects. Otherwise if there is already an RMI port in use it is shared with this object, otherwise a system-allocated port number is obtained.Note that the export step precedes the bind step, so it is quite impossible for your misconception to be correct.
LocateRegistry.createRegistry()
, all other remote objects you export from that JVM can share the port with the Registry.Remote methods can return remote objects.
The Registry is an example: it is actually very little more than a remote hash-map. Your methods can do it too. The objects are replaced by their stubs during the return process.
For those reasons, your intended design is completely fallacious and your comment below complete nonsense.
Further notes:
RemoteServer.getClientHost().
ClientHandler
should not catchIOExceptions
internally: it should throw them to the caller, so the caller can be aware of the problem.