📄 tij0170.html
字号:
command becomes:
</FONT><P></DIV><DIV ALIGN=LEFT><TT><FONT FACE="Courier New" SIZE=3 COLOR="Black">Naming.bind("//colossus:2005/PerfectTime",
pt);
</FONT></TT><P></DIV><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">If
you are using the default port 1099, you don’t need to specify a port, so
you could say:
</FONT><P></DIV><DIV ALIGN=LEFT><TT><FONT FACE="Courier New" SIZE=3 COLOR="Black">Naming.bind("//colossus/PerfectTime",
pt);
</FONT></TT><P></DIV><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">In
a future release of the JDK (after 1.1) when the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>localhost</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
bug is fixed, you will be able to perform local testing by leaving off the IP
address and using only the identifier:
</FONT><P></DIV><DIV ALIGN=LEFT><TT><FONT FACE="Courier New" SIZE=3 COLOR="Black">Naming.bind("PerfectTime",
pt);
</FONT></TT><P></DIV><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">The
name for the service is arbitrary; it happens to be PerfectTime here, just like
the name of the class, but you could call it anything you want. The important
thing is that it’s a unique name in the registry that the client knows to
look for to procure the remote object. If the name is already in the registry,
you’ll get an <A NAME="Index2886"></A><A NAME="Index2887"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>AlreadyBoundException</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
To prevent this, you can always use <A NAME="Index2888"></A><A NAME="Index2889"></A><A NAME="Index2890"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>rebind( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
instead of
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>bind( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
since
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>rebind( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
either adds a new entry or replaces the one that’s already there.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Even
though
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>main( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
exits, your object has been created and registered so it’s kept alive by
the registry, waiting for a client to come along and request it. As long as the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>rmiregistry</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is running and you don’t call
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Naming.unbind( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
<A NAME="Index2891"></A><A NAME="Index2892"></A><A NAME="Index2893"></A>on
your name, the object will be there. For this reason, when you’re
developing your code you need to shut down the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>rmiregistry</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and restart it when you compile a new version of your remote object.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">You
aren’t forced to start up
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>rmiregistry</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
as an external process. If you know that your application is the only one
that’s going to use the registry, you can start it up inside your program
with the line:
</FONT><P></DIV><DIV ALIGN=LEFT><TT><FONT FACE="Courier New" SIZE=3 COLOR="Black">LocateRegistry.createRegistry(2005);</FONT></TT><P></DIV><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Like
before, 2005 is the port number we happen to be using in this example. This is
the equivalent of running
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>rmiregistry
2005
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
from a command line, but it can often be more convenient when you’re
developing RMI code since it eliminates the extra steps of starting and
stopping the registry. Once you’ve executed this code, you can
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>bind( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
using
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Naming</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
as before.
</FONT><a name="_Toc408018788"></a><P></DIV>
<A NAME="Heading546"></A><H3 ALIGN=LEFT>
Creating
stubs and skeletons
</H3>
<DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">If
you compile and run
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>PerfectTime.java</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
it won’t work even if you have the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>rmiregistry</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
running correctly. That’s because the framework for RMI isn’t all
there yet. You must first create the <A NAME="Index2894"></A><A NAME="Index2895"></A>stubs
and <A NAME="Index2896"></A><A NAME="Index2897"></A>skeletons
that provide the network connection operations and allow you to pretend that
the remote object is just another local object on your machine.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">What’s
going on behind the scenes is complex. Any objects that you pass into or return
from a remote object must
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>implement
<A NAME="Index2898"></A><A NAME="Index2899"></A>Serializable</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
(if you want to pass remote references instead of the entire objects, the
object arguments can
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>implement
Remote
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">),
so you can imagine that the stubs and skeletons are automatically performing
serialization and deserialization as they “marshal” all of the
arguments across the network and return the result. Fortunately, you
don’t have to know any of this, but you
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>do</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
have to create the stubs and skeletons. This is a simple process: you invoke the <A NAME="Index2900"></A><A NAME="Index2901"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>rmic</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
tool on your compiled code, and it creates the necessary files. So the only
requirement is that another step be added to your compilation process.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">The
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>rmic</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
tool is particular about packages and <A NAME="Index2902"></A><A NAME="Index2903"></A>classpaths,
however.
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>PerfectTime.java</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is in the package
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>c15.Ptime</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
and even if you invoke
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>rmic</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
in the same directory in which
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>PerfectTime.class</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is located,
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>rmic</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
won’t find the file, since it searches the classpath. So you must specify
the location off the class path, like so:
</FONT><P></DIV><DIV ALIGN=LEFT><TT><FONT FACE="Courier New" SIZE=3 COLOR="Black">rmic
c15.PTime.PerfectTime
</FONT></TT><P></DIV><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">You
don’t have to be in the directory containing
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>PerfectTime.class</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
when you execute this command, but the results will be placed in the current
directory.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">When
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>rmic</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
runs successfully, you’ll have two new classes in the directory:
</FONT><P></DIV>
<font color="#990000"><PRE>PerfectTime_Stub.<font color="#0000ff">class</font>
PerfectTime_Skel.<font color="#0000ff">class</font></PRE></font><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">corresponding
to the stub and skeleton. Now you’re ready to get the server and client
to talk to each other.
</FONT><a name="_Toc408018789"></a><P></DIV>
<A NAME="Heading547"></A><H3 ALIGN=LEFT>
Using
the remote object
</H3>
<DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">The
whole point of RMI is to make the use of remote objects simple. The only extra
thing that you must do in your client program is to look up and fetch the
remote interface from the server. From then on, it’s just regular Java
programming: sending messages to objects. Here’s the program that uses
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>PerfectTime</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">:</FONT><P></DIV>
<font color="#990000"><PRE><font color="#009900">//: DisplayPerfectTime.java</font>
<font color="#009900">// Uses remote object PerfectTime</font>
<font color="#0000ff">package</font> c15.ptime;
<font color="#0000ff">import</font> java.rmi.*;
<font color="#0000ff">import</font> java.rmi.registry.*;
<font color="#0000ff">public</font> <font color="#0000ff">class</font> DisplayPerfectTime {
<font color="#0000ff">public</font> <font color="#0000ff">static</font> <font color="#0000ff">void</font> main(String[] args) {
System.setSecurityManager(
<font color="#0000ff">new</font> RMISecurityManager());
<font color="#0000ff">try</font> {
PerfectTimeI t =
(PerfectTimeI)Naming.lookup(
"<font color="#009900">//colossus:2005/PerfectTime");</font>
<font color="#0000ff">for</font>(<font color="#0000ff">int</font> i = 0; i < 10; i++)
System.out.println("Perfect time = " +
t.getPerfectTime());
} <font color="#0000ff">catch</font>(Exception e) {
e.printStackTrace();
}
}
} <font color="#009900">///:~ </PRE></font></font><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">The
ID string is the same as the one used to register the object with
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Naming</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
and the first part represents the URL and port number. Since you’re using
a URL, you can also specify a machine on the Internet.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">What
comes back from
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Naming.lookup( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
must be cast to the remote interface,
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>not</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
to the class. If you use the class instead, you’ll get an exception.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">You
can see in the method call
</FONT><P></DIV><DIV ALIGN=LEFT><TT><FONT FACE="Courier New" SIZE=3 COLOR="Black">t.getPerfectTime( )</FONT></TT><P></DIV><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">that
once you have a handle to the remote object, programming with it is
indistinguishable from programming with a local object (with one difference:
remote methods throw <A NAME="Index2904"></A><A NAME="Index2905"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>RemoteException</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">).</FONT><a name="_Toc408018790"></a><P></DIV>
<A NAME="Heading548"></A><H3 ALIGN=LEFT>
Alternatives
to RMI
</H3>
<DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">RMI
is just one way to create objects that can be distributed across a network. It
has the advantage of being a “pure Java” solution, but if you have
a lot of code written in some other language, it might not meet your needs. The
two most compelling alternatives are Microsoft’s <A NAME="Index2906"></A>DCOM
(which, according to Microsoft’s plan, will eventually be hosted on
platforms other than Windows) and <A NAME="Index2907"></A><A NAME="Index2908"></A>CORBA,
which is supported in Java 1.1<A NAME="Index2909"></A>
and was designed from the start to be cross-platform. You can get an
introduction to distributed objects in Java (albeit with a clear bias towards
CORBA) in
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>Client/Server
Programming with Java and CORBA
</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
by Orfali & Harkey (John Wiley & Sons, 1997). A more serious treatment
of CORBA is given by
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>Java
Programming with CORBA
</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
by
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>
</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Andreas
Vogel
</FONT><P><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">and
Keith Duddy (John Wiley & Sons, 1997).
</FONT><a name="_Toc375545499"></a><a name="_Toc408018791"></a><P></DIV>
<HR><DIV ALIGN=LEFT><A NAME="fn69" HREF="#fnB69">[69]</A><FONT FACE="Carmina Md BT" SIZE=2 COLOR="Black">
Many brain cells died in agony to discover this information.
</FONT><P></DIV>
<div align="right">
<a href="tij_c.html">Contents</a> | <a href="tij0169.html">Prev</a> | <a href="tij0171.html">Next</a>
</div>
</body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -