This question already has answers here:
java.rmi.NoSuchObjectException: no such object in table
(7 answers)
Closed 3 years ago.
My goal is to create a Distributed computing program that launches a server and client at the same time. I need it to be able to install on a couple of machines and have all the machines communicating with each other, i.e. Master node and 5 slave nodes all from one application.
My problem is that I cannot properly use unicastRef, I'm thinking that it is a problem with launching everything on the same port, is there a better way I am overlooking?
this is part of my code (the part that matters)
try {
RMIServer obj = new RMIServer();
obj.start(5225);
} catch (Exception e) {
e.printStackTrace();
}
try {
System.out.println("We are slave's ");
Registry rr = LocateRegistry.getRegistry("127.0.0.1", Store.PORT, new RClient());
Call ss = (Call) rr.lookup("FILLER");
System.out.println(ss.getHello());
} catch (Exception e) {
e.printStackTrace();
}
}
this is my main class (above)
this is the server class (below)
public RMIServer() {
}
public void start(int port) throws Exception {
try {
Registry registry = LocateRegistry.createRegistry(port, new RClient(), new RServer());
Call stuff = new Call();
registry.bind("FILLER", stuff);
System.out.println("Server ready");
} catch (Exception e) {
System.err.println("Server exception: " + e.toString());
e.printStackTrace();
}
}
I don't know what I am missing or what I am overlooking but the output looks like this.
Listen on 5225
Listen on 8776
Server ready
We are slave's
Listen on 8776
java.rmi.NoSuchObjectException: no such object in table
at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:255)
at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:233)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:359)
at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source)
at Main.main(Main.java:62)
line 62 is this ::: Call ss = (Call) rr.lookup("FILLER");
Maybe it's because your reference to the stub in your server class is local to the try block and the reference is immediately garbage collected after. Try making stuff a class variable instead.
Related
This question already has an answer here:
RMI connection refused on localhost
(1 answer)
Closed 5 years ago.
Doing a course, and I am trying to wrap my head around RMI. I cant seem to get it right. Link to unmodified source code: https://drive.google.com/open?id=0B7NQABLlsgGWbXNhb0JHall4NXM
package helloworld;
import java.rmi.Naming;
public class HelloRMIServer {
// TODO 08. Set the OBJECT_NAME to the same value used by the client.
private static String OBJECT_NAME = "TEST";
public static void main(String[] args) {
try {
// TODO 09. Create a new instance of the remote object.
MessageInterface message = new MessageInterface();
// TODO 10. Re-bind the object in the registry.
Naming.rebind("rmi://" + "127.0.0.1" + "/" + OBJECT_NAME, message);
System.out.println("Server object message bound into registry.");
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Server done creating and binding objects.");
}
}
What am I doing wrong?
You haven't started the rmiregistry.
I created a sucessful RMI server, thank god for that :)
It works perfectly..
I have a JForm and it gets activated clicking on a button.
Altough i wanted to create too a button to deactivate it, but i am having a problems to unexport it.
Ok then and this is the way i was trying to exporting and terminating the RMI Server
private void btStopServerActionPerformed(java.awt.event.ActionEvent evt) {
try {
// Nome do objecto
String objectname = txtObjectName.getText();
// obtem o número da porta
int port = Integer.parseInt(txtServerPort.getText());
RemoteMessageObject remote = new RemoteMessageObject();
Registry registry = LocateRegistry.getRegistry(port);
UnicastRemoteObject.unexportObject(LocateRegistry.getRegistry(port), true);
registry.unbind(objectname);
System.out.println("Server offline");
} catch (IOException ex) {
Logger.getLogger(ServerGUI.class.getName()).log(Level.SEVERE, null, ex);
} catch (NotBoundException ex) {
Logger.getLogger(ServerGUI.class.getName()).log(Level.SEVERE, null, ex);
}
}
I get this exception:
java.rmi.NoSuchObjectException: object not exported
at the line:
UnicastRemoteObject.unexportObject(LocateRegistry.getRegistry(port), true);
What am i doing wrong here?
Solved................
I discovered it before :P
Anywway thanks #EJP for the correct answer.
So the solution for me was to create the Register when the class starts as a public variable, so it could be use inside both click events (Start server and stop server).
I removed too a lot of nonsense stuff that was not necessary for disabling the RMI server just like #EJP sayed.
Its now working this way:
private void btStopServerActionPerformed(java.awt.event.ActionEvent evt) {
try {
// Nome do objecto
String objectname = txtObjectName.getText();
// obtem o número da porta
int port = Integer.parseInt(txtServerPort.getText());
Registry registry = LocateRegistry.getRegistry(port);
UnicastRemoteObject.unexportObject(this.registry, true);
registry.unbind(objectname);
System.out.println("Server offline");
} catch (IOException ex) {
GuiUtils.addText(txtLog, "Erro", "Servidor desligado");
btStopServer.setEnabled(false);
btStartServer.setEnabled(true);
} catch (NotBoundException ex) {
Logger.getLogger(ServerGUI.class.getName()).log(Level.SEVERE, null, ex);
}
}
You need to unexport the object returned by LocateRegistry.createRegistry(). The object returned by getRegistry() isn't the actual Registry object, it is a stub, and you can't unexport those.
But unexporting the Registry and then calling unbind() doesn't make sense. Doing it the other way round makes a little sense, but not much.
And you also have to unexport your own remote object.
And creating a new remote object in a method that is trying to unexport the existing one doesn't make sense either.
I'm now processing a client-server communication in Java, by using Socket and ServerSocket objects.
Once the server has been initialised, it puts on hold with new clients through the accept() method, from ServerSocket class; I immediately provide to put this socket in a client map on the server:
- keys: ClientNode(Socket s, CommunicationChannels channels);
- values: Info();
(CommunicationChannels contains ObjectOutputStream and ObjectInputStream from socket; Info contains some information about client, as username, messages etc..).
Given that, at the very beginning, the socket does not have any other information on the client besides the socket itself, first insertion on the map is map.put(ClientNode, null). I will fill the field "value" afterwards.
Now, on Client class, I am going to initialise a Socket("127.0.0.1", 13001), namely with a loopback address and gate 13001. Once communication channels have been initialised, client connects to the server.
Once the client starts, he takes a remote copy of the server through RMI (stub) libraries and the server makes a register() method available: it would allow to use this method to write requested information (from the clients) on the map.
How can the client go back to the socket with which it has been registered on the server? Frankly speaking, I supposed that accept() method from ServerSocket could take the socket established on the startup client back to the server, namely with the new Socket("127.0.0.1", 13001), but it seems to me that this does not happen.
Here you can find parts of the code, so you can better understand what I'm talking about. I've already taken into account a few things that I will share with you in case of need.
public class Server implements Runnable, RemoteServices {
...
private Map<ClientNode, Info> map = new HashMap<ClientNode, Info>();
...
public void run() {
ServerSocket ss = null;
try {
ss = new ServerSocket();
while (true) {
if (!ss.isBound()) {
ss.bind(new InetSocketAddress(ipServer, port));
}
Socket client = ss.accept();
CommunicationChannels channels = new CommunicationChannels(new ObjectOutputStream(client.getOutputStream()), new ObjectInputStream(client.getInputStream()));
map.put(new ClientNode(client, channels), null);
}
} catch (IOException e) {
e.printStackTrace();
}
}
// RemoteServices implementa Remote e mette a disposizione register()
public void register(Info info) throws RemoteException {
// TODO
}
public class Client implements Runnable {
...
...
#Override
public void run() {
Socket client = null;
try {
client = new Socket(ipServer, port);
out = new ObjectOutputStream(client.getOutputStream());
in = new ObjectInputStream(client.getInputStream());
Registry registry = LocateRegistry.getRegistry("127.0.0.1");
stub = (RemoteServices) registry.lookup("remoteObject");
Info info = new Info();
info.setID(getID());
info.setUsername("Giordano");
stub.register(info);
} catch (IOException e) {
System.err.println("Spiacente: il server ha terminato l'esecuzione.");
e.printStackTrace();
} catch (NotBoundException e) {
e.printStackTrace();
}
}
}
Remarks:
I have not included the code of some classes because I thought it was superfluous; for example the "info" class is just a series of "getter and setter" of some fields; the CommunicationChannels class represents communication channels of the client, taken directly from the socket, etc ..
The server, after the accept(), does not instantiate any thread to communicate with the client because communication has to come afterwards. However, if there was a way to solve my problem with a thread of communication I would find a way to fix it.
My question starts from the need to make interact 2 clients with a server without using more PCs; therefore all clients will have the IP loopback and therefore I cannot use the IP address as a discriminating between two sockets, otherwise I would have already solved it.
In other words, I know that methods as socket.getInetAddress().getHostAddress() can help me to distinguish between two socket, but if I initialise two clients on the same PC I have to use loopback address and the method always returns "127.0.0.1".
The register() method is obviously incomplete even in the signature; once understood how to compare the server socket and client one through a Serializable discriminating object (like the hashcode()) probably I might put it in the arguments of the method, so you can easily make the comparison.
Finally, main() methods:
public static void main(String[] args) {
Server server = new Server("127.0.0.1", 13001);
RemoteServices stub;
try {
stub = (RemoteServices) UnicastRemoteObject.exportObject(server, 0);
Registry registry = LocateRegistry.getRegistry();
registry.bind("remoteObject", stub);
(new Thread(server)).start();
} catch (RemoteException e) {
System.err.println("Verificare l'apertura dei registri");
} catch (AlreadyBoundException e) {
System.err.println("Server già attivo. Controllare che i registri siano chiusi correttamente.");
}
}
public static void main(String[] args) { Client client = new Client("127.0.0.1", 13001);
new Thread(client).start();
}
I really hope everything is clear and that you can help me.
Hi all I have question related with Pyro4 and Java. My question is how can I send information between RMI server in Java and clients RMI in Python?.
This is my code, I don't have any errors but I can't send anything.
Java Code:
implements ReceiveMessageInterface
{
int thisPort;
String thisAddress;
Registry registry; // rmi registry for lookup the remote objects.
// This method is called from the remote client by the RMI.
// This is the implementation of the �gReceiveMessageInterface�h.
public void receiveMessage(String x) throws RemoteException
{
System.out.println(x);
}
public RmiServer() throws RemoteException
{
try{
// get the address of this host.
thisAddress= (InetAddress.getLocalHost()).toString();
}
catch(Exception e){
throw new RemoteException("can't get inet address.");
}
thisPort=3232; // this port(registry�fs port)
System.out.println("this address="+thisAddress+",port="+thisPort);
try{
// create the registry and bind the name and object.
registry = LocateRegistry.createRegistry( thisPort );
registry.rebind("rmiServer", this);
}
catch(RemoteException e){
throw e;
}
}
static public void main(String args[])
{
try{
RmiServer s=new RmiServer();
}
catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
}
And this is my code in Python:
import Pyro4
proxy=Pyro4.core.Proxy("PYRONAME:PhDJara/127.0.1.1")
print("5*11=%d" % proxy.multiply(5,11)) print("'x'*10=%s" %
proxy.multiply('x',10))
Thanks for your help.
jarain78
What makes you think that you should be able to connect these two?
Pyro4 is only conceptually similar to Java's RMI, but they're two totally different protocols. You cannot connect them directly.
If you want to write a Python client using Pyro and talk to a server, that server has to be a Pyro server. The only way to create one in Java is by using Jython + Pyro.
I have a small Java RMI Server and Client program I'm writing. I have spent some time trying to figure out the error messages without success.
The Client generates the following error:
Trying to connect to: 127.0.0.1:3232
ERROR!!!: StockClient: main: Could not connect to the server: java.rmi.UnmarshalException: Error unmarshaling return header; nested
exception is:
java.rmi.UnmarshalException: Error unmarshaling return header; nested exception is:
java.io.EOFException
java.io.EOFException
at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:209)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:359)
at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source)
at StockClient.StockClient.main(StockClient.java:44)
Caused by: java.io.EOFException
at java.io.DataInputStream.readByte(DataInputStream.java:250)
at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:195)
... 3 more
With the server the following error only when the client attempts to connect.
this address=localhost/127.0.0.1,port=3232
Exception in thread "RMI TCP Connection(idle)" java.security.AccessControlException: access denied
(java.net.SocketPermission 127.0.0.1:62586 accept,resolve)
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:374)
at java.security.AccessController.checkPermission(AccessController.java:549)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
at java.lang.SecurityManager.checkAccept(SecurityManager.java:1157)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.checkAcceptPermission(TCPTransport.java:636)
at sun.rmi.transport.tcp.TCPTransport.checkAcceptPermission(TCPTransport.java:275)
at sun.rmi.transport.Transport$1.run(Transport.java:158)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Transport.java:155)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:535)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:790)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:649)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:680)
Because of the server error I'm fairly sure its a security or registry error, security policy for the server is:
grant {
permission java.security.AllPermission;
};
and being run with the following argument
-Djava.security.policy=client.policy
I've tried everything I can find but seem to keep going around in circles.
relevant methods:
Server:
public static void main(String[] args)
{//main(...) starts
// set up the data structures and data
//add users
//Users hard coded as this is an example proof on concept program
//Names and passwords not hashed for simplicity
User alpha = new User("Alpha", "AlphaPass");
User omega = new User("Omega", "OmegaPass");
users.add(alpha);
users.add(omega);
//startup the RMI server
try
{
System.setSecurityManager(new RMISecurityManager());
StockServer server = new StockServer();
StockServerInterface inter = (StockServerInterface)
UnicastRemoteObject.exportObject (server,0);
// create the registry and bind the name and object.
registry = LocateRegistry.createRegistry(thisPort);
registry.rebind("StockServer", inter);
}
catch (Exception e)
{
System.out.println("Unable to create StockServer: " + e);
e.printStackTrace();
System.exit(1);
}
}//main(...) ends
/**
* Constructor for StockServer
*
* #throws RemoteException
*/
public StockServer() throws RemoteException
{
//try to get the host machine's IP address
try
{
// get the address of this host.
thisAddress = (InetAddress.getLocalHost()).toString();
} catch (Exception e)
{
throw new RemoteException("can't get inet address. " + e);
}
//Set the port
thisPort = 3232;
//Print out the server address and port
System.out.println("this address=" + thisAddress + ",port=" + thisPort);
}
Client:
private static StockServerInterface stockServer;
static public void main(String args[])
{
Registry registry;
//get the server address from the args
String serverAddress = args[0];
//get the server port from the args
String serverPort = args[1];
//Let the user know we are about to try to connect
System.out.println("Trying to connect to: " + serverAddress + ":" + serverPort);
try
{
// get the registry
registry = LocateRegistry.getRegistry(
serverAddress,
(new Integer(serverPort)).intValue());
// look up the remote object
stockServer = (StockServerInterface) (registry.lookup("StockServer"));
//Authenticate the user
authenticate();
//setup the hashset
HashSet<Stock> hashStockSet = null;
//setup the hashset of desired stocks
try
{
hashStockSet = getHashSet();
} catch (IOException e)
{
e.printStackTrace();
System.exit(1);
} catch (ClassNotFoundException e)
{
e.printStackTrace();
System.exit(1);
}
//bit of a heavy handed infinte loop so we continue to get the loop
while(true)
{
//Run the ticker
ticker(hashStockSet);
}
// call the remote method
}
catch (RemoteException e)
{
System.out.println("ERROR!!!: StockClient: main: Could not connect to the server: "+e);
e.printStackTrace();
}
catch (NotBoundException e)
{
System.out.println("ERROR!!!: StockClient: main: Could not connect to the server: "+e);
e.printStackTrace();
}
You don't need a SecurityManager in an RMI server unless the client is relying on the codebase feature to supply the server with classes. Either remove it, or debug the .policy file. Clearly the one you've written isn't being loaded.
Run your server with -Djava.security.debug=access,failure and you will see where all the security domains are getting their configurations from, and the domain that is failing at the point where the exception is thrown.