| Home > Advance
Java FAQ
> RMI FAQ |
| RMI |
| |
|
Q .
What is remote method invocation?
|
Ans :
Remote method invocation (RMI), is a mechanism for invoking an object's methods, even though the object is executing on a foreign Java Virtual Machine (JVM).
RMI is similar to remote procedure calls (RPCs), but has an added advantage - method signatures can contain Java objects as well as primitive data types.
Even objects that a foreign JVM has never encountered before can be used, so new tasks and methods can be passed across a network.
|
|
Q . When should I use remote method invocation?
|
Ans
:
Here's a few rules of thumb :
When you wish to execute code on remote systems (distributed systems)
When you have a network that has machines capable of supporting JVMs on all machines you would wish to connect to RMI
When you don't want your RMI applications to be used from machines that don't support JVMs, or from applications written in C++/Ada/Cobol/Fortran/[insert
non-java lang here]
|
|
Q . Why can't I access RMI from C++?
|
Ans
:
Remote method invocation allows method signatures to contain Java objects, and C++ isn't capable of executing Java bytecode. If your RMI system only used
primitive data types, you might be able to write a software bridge between the two - but this isn't direct remote method invocation. You'd be better off
investigating CORBA.
|
|
Q . Why won't my RMI implementation compile under JDK1.1?
|
Ans
:
Under JDK1.02, RMI implementations extend java.rmi.server.UnicastRemoteServer. This changed in JDK1.1 - you should now extend
java.rmi.server.UnicastRemoteObject.
|
|
Q . Why won't my RMI implementation run under Java 2?
|
Ans
:
If you're running the client or server with Java 2, then you'll need to specify a security policy file, to prevent SecurityExceptions being thrown. This
policy file will allow your application to bind to a local port (if a service), and to connect to remote hosts (if a client).
The following changes should be made when running the client/server :
java -Djava.security.policy=java.policy yourserver
You'll also need to create a policy file (if one does not already exist). Here's a sample policy file that will allow you to accept conections from ports
higher than 1024, but connect to all ports as a client.
grant {
permission java.net.SocketPermission "*:1024-65535",
"connect,accept,resolve";
permission java.net.SocketPermission "*:1-1023",
"connect,resolve";
};
|
|
Q . Should I use CORBA in preference to RMI? Or DCOM? Or what?
|
Ans :
If your distributed programs are all in Java, then RMI provides a
simpler mechanism that allows the transfer of code, pass-by-value of
real Java objects, and automatic garbage collection of remote objects.
If you need to connect to C++ (or other language) systems or you need CORBA-specific services, then CORBA is your choice.
In July 1997, Sun announced that it was aligning RMI to work more closely with CORBA. Sun is simply adding an IIOP transport layer to RMI
to support interoperability with CORBA. Java programs can then use RMI
to access CORBA-based objects through IIOP, the OMG's CORBA-based protocol. This is very good news for those building heterogenous
Enterprise systems, although it will take some additions to IIOP to support the pieces that RMI uses.
In 1998 Microsoft spokespeople tried to promote DCOM by spreading misinformation that RMI is changing or being dropped. That is totally
wrong. The RMI API continues unchanged in its current form. Using DCOM
restricts your code to only ever run on Microsoft platforms using Intel hardware, and negates the "write once, run anywhere" Java philosophy.You would have to recompile your DCOM code to run it on other Microsoft
platforms like Compaq's (formerly DEC's) alpha computer. Non-portable,
single vendor code should be avoided. DCOM/DNA has limitations for usein the enterprise.
Other sites:
http://www.javaworld.com/javaworld/jw-10-1997/jw-10-corbajava.html has a good intro to CORBA in the Java world.
http://www.objenv.com/cetus
has a CORBA/RMI comparison.
|
|
Q .
How do I do RMI into a different domain?"
|
Ans
:
Similar to the proxy answer in a section below; you must tell the
program where to find the server. In this case start up the client with
this commandline option: -Djava.rmi.server.hostname=hostname.domainname
|
|
Q . RMI seems to have stopped working for me in JDK 1.1. Why is this?
|
Ans
:
The rules for where the client looks for a stub class seem to have
changed making it necessary to reset your class path on the client
after starting the RMI registry. In particular, it looks like rmic was
not updated to the new "don't need $CLASSPATH for current dir" convention as the compiler was. You are best off setting classpath
explicitly.
Other sites:
There are several very good sources available from Sun which cover many simple and advanced RMI problems.
1. The documentation, of course: http://java.sun.com/products/jdk/1.1/docs/guide/rmi/index.html
2. Dedicated FAQs on RMI and Object Serialization http://java.sun.com/products/jdk/rmi/faq.html
3. Mailing list RMI-USERS@JAVASOFT.COM with archive at http://chatsubo.javasoft.com/email/rmi-users/
Visit the archive!
|
|
Q .
After a number of RMI client to server connections, subsequent RMI clients trying to connect fail. Why?
|
Ans
:
You are hitting the default limit of 64 open file descriptors. Try
increasing the limit in your OS.
In addition there is currently a practical RMI connection limit imposed by the scalability of the VM and the performance of object
serialization. This is addressed in JDK 1.2. The actual number of active clients you will be able to support will depend on the workload
mix you have (i.e. the number of clients, how often they talk to the
server, and how much work must be done per call).
|
|
Q .
I'm using RMI on Win95, and the Naming.lookup() call is taking a long time, even for localhost. How do I fix it?
|
Ans
:
Try adding a
definition for the machine in your "hosts" file. Typically, this file
will be named c:\windows\hosts (if it doesn't exist, there should be a
file called c:\windows\hosts.sam). The hosts file is searched by your
TCP/IP stack before it resorts to DNS, so adding an entry in this file
can speed up your lookups considerably. The hosts file is used to map IP addresses to symbolic addresses. To enter the name
"localhost" with address 127.0.0.1 (the IP loopback address), enter the following line
in your hosts file. 127.0.0.1 localhost
|
|
Q .
Why does < Windows RMI/my java debugger/IDE/other> hang for a couple of minutes if my Windows PC is not dialed up to the Internet?
|
Ans
:
Java has networking support built in. When the Java program starts
the Winsock DLL automatically gets loaded. The first thing this does is
to try to resolve the fully qualified domain name for your machine
under the name "localhost". If your system doesn't have this name mapped, it will try to query a nameserver on the internet, which is
typically (on a PC) your dialup ISP. So it either prompts you to
connect to the ISP, or waits till the attempt times out.
Some people say you can avoid the Win95 problem by giving your system another way to resolve DNS names. This tip has never worked for me.
Edit the hosts file for your system so that localhost and the full
domain name are both mentioned. On Windows 95 systems the hosts file
is: %windir%\HOSTS (for example, C:\WINDOWS\HOSTS). On Windows NT systems the hosts file is:
%windir%\System32\DRIVERS\ETC\HOSTS (for
example, C:\WINNT\System32\DRIVERS\ETC\HOSTS).
One gotcha under Win95 is that if the last entry in the hosts file is not concluded with a carriage-return/line-feed then the hosts file will
not be read at all. So if my system is called goober.best.com change
the hosts file from
127.0.0.1 localhost
to
127.0.0.1 good.mysite.com localhost
Showing more of the file:
# Hosts file
127.0.0.1 localhost
129.146.77.177 good
Another alternative is to dial up with a PPP connection to your ISP whenever you want to run networking programs.
Fundamentally the experience of some people has been that networking is not completely satisfactory on Windows95 using Winsock 1.1, and is
subject to sporadic unexplained failures. You could try downloading
Winsock 2.0. To get Winsock 2.0, you need to drag in all the other junk
from Microsoft Windows Sockets 2.0 Software Development Kit. This free
software can be downloaded from the following addresses:
http://www.microsoft.com/win32dev/netwrk/winsock2/ws295sdk.html or
ftp://ftp.microsoft.com/bussys/WinSock/winsock2/
The patches needed to improve Win95 networking are already in Win98.
|
|
Q . If I create an RMI server, which is accessed by multiple clients, will the server always execute in the same thread, or always in different threads, or can I
control this?
|
Ans
:
The RMI specification leaves this up to the Java implementation. The RMI programmer has no control over this at all. This means the JDK/JRE implementor
can make a choice which they believe appropriate, and the application programmer must code their server to be thread-safe, on the assumption that it will be
accessed by multiple threads.
It may seem that adding synchronisation will decrease your server performance, but on the contrary it gives you the opportunity to gain greater performance
and throughput. By ensuring that locks are held only where necessary, multiple threads can be executing server code which will means multiple requests can be
serviced simulataneously, and in an multi-processor environment performance can be much better.
Note: There can be differences in terminology as to what constitutes a client: it can be a remote reference to a remote object; it can be a BM/runtime, so
including all the remote references to a remote object held from that VM, or it can be all the VMs on a given host which hold remote references to an RMI
server.
In all of these cases RMI may execute in separate threads. The JavaSoft reference implementation apparently has a single thread for all references from a
single client VM but this should *not* be relied upon.
|
|
Q . What properties does RMI use?
|
Ans
:
Here is a list of the documented properties in the RMI specification:
java.rmi.server.codebase
java.rmi.server.hostname
java.rmi.server.disableHttp
java.rmi.server.hostname
java.rmi.dgc.leaseValue
java.rmi.server.logCalls
java.rmi.server.useCodebaseOnly
java.rmi.loader.packagePrefix
java.rmi.registry.packagePrefix
java.rmi.server.packagePrefix
For full details please refer to the RMI specification.
|
|
Q . Why does it take a long time to bind to an RMI server?
|
Ans
:
Delays of tens of seconds have been reported on MS Windows platforms. These are believed to be entirely due to DNS lookup delays or misconfigurations. You
should try to "ping" the host using the name as written in the code.
Remember this can include your local host, if no explicit host name is mentioned in the rebind() call. "localhost - 127.0.0.1" probably ought to be there
too.
|
Q . I modify an RMI program, recompile, re-generate the stubes and restart server and client. I get an error like: EchoImpl.main: an exception occurred: Stream
Input Exception
|
Ans
:
You also need to restart the RMI registry, which will still have the original class versions loaded.
|
|
Q .
When I try to bind my RMI server to the RMI registry I get an error "Connection refused"
|
Ans
:
Are you trying to bind to a registry on a different host? The registry will only accept server connections from the same host as a security measure. It
will check this by doing a lookup to ensure that the incoming host address is the same as its own host address, so name service misconfigurations can also
cause this problem.
|
|
Q . Can I throw an Exception from an RMI server to an RMI client?
|
Ans
:
Yes, absolutely you can. In fact throwing an exception is the preferred Java way of signaling a problem.
Declare your own exception classes and remember to mark them serialisable:
eg. public class MyException extends java.io.Exception implements java.io.Serializable { .... }
Just be sure *not* to catch the exception on the server side before it can be serialised and rethrown in the client VM. One mistake that has been seen is a
too generic "catch (Exception e)" on the server side!
|
|
Q . I don't want to run a separate process for the RMI registry, since I only have the one RMI server process, and should always be running. Can I do this?
|
Ans
:
Yes, there is an API call to do this:
public static Registry java.rmi.registry.LocateRegistry.createRegistry();
A call, LocateRegistry.createRegistry(1099); would create a registry listening on the default registry port of 1099.
You can then start just the one VM process which will act as both registry and server.
|
Q .I am trying to run an applet that makes RMI calls into a server and the server makes RMI calls into the applet. When I try to run this applet in appletviewer
I get the following exception:
***Security Exception: socket.listen:0 ***
sun.applet.AppletSecurityException:socket.socket.listen: 0
at sun.applet.AppletSecurity.checkListen(AppletSecurity.java:337)
at java.net.ServerSocket.(ServerSocket.java:75) ....
|
Ans
:
Your applet wants to be an RMI server as well as an RMI client. A listening socket is needed to be an RMI server: so that you can respond to incoming
requests from an RMI client. RMI applets are limited by the standard applet sandbox which means that they can't establish a listening socket.
In the case of an applet there is a partial solution, so long as it already has an estabilished socket connection with its applet host to an RMI server
there. RMI can "multiplex" the existing socket connection. Thus your RMI server can make RMI "callbacks" to an RMI client applet.
|
|
Q . I am not sure about RMI performance - is it an enterprise solution?
|
Ans
:
Well first off, to many people "enterprise solution" means interoperability and for those requirements, a CORBA implementation such as JOE/NEO is a more
appropriate solution.
For those looking for an all Java solution, RMI can be considered an enterprise solution. Focus on performance started late in the 1.1 delivery cycle, as
functionality was more important up until then, and was improved significantly for JDK 1.1 FCS, and will continue to improve.
An RMI server should be able to handle hundreds of simultaneous connections. This is a larger requirement than almost any intranet application. One technical
limit is determined by two open socket descriptors per connection reaching the UNIX per process limit of 1024 at around 500 connections, on Solaris at least.
If RMI server connections are held for a long time, this can eat into your store of socket descriptors, but this is on a per VM basis, and multiple VM's
possible hosted across multiple server hosts, in a traditional load-balancing manner can help alleviate some of this.
Throughput is application dependent: (de)marshalling large sets of method arguments can be CPU intensive, but the processing power needed by your server is
completely up to your application.
|
|
Q .
Does RMI use HTTP?
|
Ans
:
Yes, for loading classes, and also as a fall back when a direct socket connect for method invocation is prevented by a firewall. This is slow but better
than nothing.
|
|
Q . Why is a method invocation so slow?
|
Ans
:
Well, initial creation of a remote reference can be slow, if you need to do a host lookup, and establish a TCP connection. Slow here means in the 500ms
ballpark. Thereafter performance is mostly determined by the object serialisation protocol, and how many arguments you need to marshall. Less than 10ms per
call is achievable across a LAN. The same code could manage 2ms per call within the same machine. All this assumes your network bandwidth and latency are not
the bottleneck.
|
|
Q .How do I make an applet an RMI server?
|
Ans
:
You need a callback.
|
|
Q . How do I make a class a RemoteObject if it can't extend Unicast Remote Server because it already extends another class?
|
Ans
:
You need to explicitly export the object:
UnicastRemoteObject.exportObject(this);
where this is the object you want to make a Remote Object. It must also implement Remote and Serializable. The RMI example in
docs\gude\rmi\examples\stock does this since it extends Applet. In the applet case another solution is to create a different class which you instantiate in your code.
|
|
Q .
Are there any tricks/quirks to using rmic?
|
Ans
:
When running rmic it is important to set up CLASSPATH and to use the -d compiler option. rmic has a slightly different (anomalous!) behavior than
javac. It does not automatically add the current working directory to CLASSPATH so you do need to explicitly set CLASSPATH. To make matters worse, a different bug
means that its attempt to tell you it can't find the .class because it is not searching relative to "." comes out all wrong, as : error: Class {0} not found.
The -d option is needed so that the compiled classes are placed in the correct subdirectory for their package, if you are using packages.
|
|
Q . rmigregistry is taking up some of my CPU time, eeven though no new bind requests are coming in, why?
|
Ans
:
The garbage collector runs periodically. If this is a big issue, you can disable it by with the -noasyncgc, as follows:
rmiregistry -J-noasyncgc
the -J is the standard way of having command which do not directly invoke the java interpreter of forwarding arguments to the interpreter.
|
|
Q .
I can't run the "hello" example applet provided for RMI, what's wrong?
|
Ans
:
Here is a step by step guide:
Download JDK1.1.1 to your system (PC or Sun), and install it.
Download the JDK documentation
Set your path to include JDK1.1.1\bin or where ever you installed JDK
Make sure you do NOT have CLASSPATH set
Make sure you do NOT have any other version of JDK on your PATH
cd into \JDK1.1.1\docs\guide\rmi\hello
type "run.bat" on win32, or "run" on Solaris
|
|
Q . Why can't I get dynamic loading to work?
|
Ans
:
RMI uses the standard Java class-loading mechanisms.
This means classes are loaded only from either local CLASSPATH, or via HTTP from a web server. If you want an RMI application to automatically find and load
the classes used in RMI calls, you probably want to use the HTTP approach. You can facilitate this with the property java.rmi.server.codebase, the value of
which is a URL in the same sense as codebase for regular Java applets.
|
|
Q . Is there a way to turn on more RMI debugging info?
|
Ans
:
There are a few properties you can set to +ve integers to get some logging, the first of these is boolean, the rest are integers.
java.rmi.server.logCalls
sun.rmi.transport.tcp.logLevel
sun.rmi.transport.proxy.logLevel
sun.rmi.server.logLevel
sun.rmi.dgc.logLevel
|
|
Q . I get an error message using RMI which includes the following, "java.io.StreamCorruptedException: Type code out of range, is 1", what's wrong?
|
Ans
:
The object serialisation protocols in the two Java runtimes you are using are incompatible. Probably you mixing some very early version of RMI on 1.0.2
with the later, stable versions.
|
|
|