RMI代表远程方法调用,顾名思义,它是Java程序调用另一台计算机上运行的对象的方法的协议。它提供了一个API(应用程序编程接口),用于从一个程序(称为服务器)导出一个对象,并从另一个程序(称为客户机)调用该对象的方法,可能运行在不同的计算机上。
javarmi注册表是javarmi系统的一个关键组件,它为服务器注册服务和客户机查找这些服务提供了一个集中的目录。在本文中,我们将学习如何实现一个服务器来公开对象,以及如何实现一个客户端来调用服务器上的方法,以及如何在RMI注册表中注册和查找服务。
为了了解javarmi系统如何工作的复杂性,让我们实现一个简单的服务器对象,提供一个接受名称并返回问候语的方法。以下是对象接口的定义:
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Greeting extends Remote
{
public String greet(String name) throws RemoteException;
}
接口的名称称为问候语。它提供了一个名为greet()的方法,它接受一个名称并返回一个合适的问候语。
要将此接口标记为可导出,它需要扩展java.rmi.Remote文件接口。该方法还需要声明一个throws子句列表java.rmi.RemoteException异常除了任何特定于应用程序的例外。这使得客户机代码可以处理(或传播)远程方法调用错误,例如找不到主机、连接失败等。
声明接口(客户端使用)后,我们实现服务器端对象,并提供greet()方法,如图所示。它使用一个简单的格式字符串来格式化问候语。
public class GreetingObject implements Greeting
{
private String fmtString = "Hello, %s";
public String greet(String name)
{
return String.format(this.fmtString, name);
}
}
现在让我们将所有这些部分整理在一起,并实现服务器的main()方法。让我们来看看每一个相关的步骤。
Greeting greeting = new GreetingObject();
Greeting stub = (Greeting)UnicastRemoteObject.exportObject(greeting, 0);
String name = "Greeting";
Registry registry = LocateRegistry.getRegistry(port);
registry.rebind(name, stub);
完整的主方法。
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
public class Main
{
static public void main(String[] args) throws Exception
{
if ( args.length == 0 ) {
System.err.println("usage: java Main port#");
System.exit(1);
}
int index = 0;
int port = Integer.parseInt(args[index++]);
String name = "Greeting";
Greeting greeting = new GreetingObject();
Greeting stub = (Greeting)UnicastRemoteObject.exportObject(greeting, 0);
Registry registry = LocateRegistry.getRegistry(port);
registry.rebind(name, stub);
System.out.println("Greeting bound to \"" + name + "\"");
}
}
现在让我们看看如何构建服务器。为了简单起见,我们在Linux上使用命令行构建,而不是使用Maven之类的构建工具。
下面将源文件编译为目标目录中的类文件。
rm -rf target
mkdir target
javac -d target src/server/*.java
将类文件收集到JAR文件中执行。
jar cvf target/rmi-server.jar -C target server
我们还收集将客户机编译为库JAR所需的接口文件。
jar cvf target/rmi-lib.jar -C target server/Greeting.class
现在让我们来看看如何实现用于调用服务器对象方法的客户机。
Registry registry = LocateRegistry.getRegistry(host, port);
Greeting greeting = (Greeting) registry.lookup(name);
System.out.println(name + " reported: " + greeting.greet(myName));
完整的客户端代码:
package client;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import server.Greeting;
public class Client
{
static public void main(String[] args) throws Exception
{
if ( args.length != 3 ) {
System.err.println("usage: java Client host port myName");
System.exit(1);
}
int index = 0;
String host = args[index++];
int port = Integer.parseInt(args[index++]);
String myName = args[index++];
String name = "Greeting";
Registry registry = LocateRegistry.getRegistry(host, port);
Greeting greeting = (Greeting) registry.lookup(name);
System.out.println(name + " reported: " + greeting.greet(myName));
}
}
现在让我们运行服务器程序,以便它可以开始服务请求。
java -cp target/rmi-server.jar server.Main 1099
# throws
Exception in thread "main" java.rmi.ConnectException: Connection refused to host: xxx; nested exception is:
java.net.ConnectException: Connection refused
这个例外是什么?连接被拒绝。
出现此异常的原因是:请从服务器代码中注意,它试图连接到端口1099上的本地注册表。如果失败了,你会得到这个例外。
解决方案是运行RMI注册表。RMI注册表是Java虚拟机附带的一个程序,称为RMI注册表。它应该位于Java虚拟机安装的bin目录中。运行它非常简单:
/usr/lib/jvm/jdk1.8.0_71/bin/rmiregistry
默认情况下,注册表侦听端口1099。要使其侦听另一个端口,请按如下所示指定端口号:
/usr/lib/jvm/jdk1.8.0_71/bin/rmiregistry 1100
使用netstat命令检查指定端口上是否确实存在侦听器:
netstat -an -t tcp -p | grep LISTEN
...
tcp6 0 0 :::1100 :::* LISTEN 23450/rmiregistry
现在让我们再次尝试运行服务器。
java -cp target/rmi-server.jar server.Main 1100
# throws
java.rmi.UnmarshalException: error unmarshalling arguments
...
Caused by: java.lang.ClassNotFoundException: server.Greeting
...
又是个例外!这次是什么?
服务器无法加载接口类服务器。问候语. 这是因为RMI注册表无法加载所需的类。所以需要指定所需类的位置。一种方法是指定CLASSPATH环境变量:
CLASSPATH=../../junk/target/rmi-lib.jar /usr/lib/jvm/jdk1.8.0_71/bin/rmiregistry 1100
尝试再次运行服务器时,给出了以下内容:
java -cp target/rmi-server.jar server.Main 1100
# prints
Greeting bound to "Greeting"
现在服务器正在运行。
在所有的部分都被组装和执行之后,运行客户机就很简单了。它需要合适的罐子来执行。其中包括包含main()方法的类和接口类。它接受指示RMI注册表运行位置的参数和问候语的名称。
java -cp target/rmi-client.jar:target/rmi-lib.jar client.Client localhost 1100 Peter
# prints
Greeting reported: Hello, Peter
javarmi提供了一个API和工具来简化远程代码的执行。您可以实现一个向javarmi注册表注册服务对象的服务器。客户机可以查询注册表并获取服务对象存根以调用服务方法。正如这个例子所说明的,这一切都非常简单。
您在项目中使用javarmi吗?你有什么经历?你有没有别的选择?请在下面的评论中告诉我们。
...如果所有这些都让你有了定制的心情,那么就来看看我们关于如何改变桌面的外观和感觉的技巧吧。完成后,您的系统将感觉全新。 ...
...在在哪里)是一个旅行者的社交网络。无论你是想要一些关于廉价酒店的建议,需要了解外国城市的交通系统,还是只想在度假时找个人一起去喝一杯,韦恩都能帮上忙。 ...
...s,然后弹出Aboutyou部分来验证您的基本信息。然后,去“关于你的宝宝”部分。 ...
...程时事通讯、发送到您收件箱的微型学习课程,以及10个关于各种主题的精彩时事通讯,所有这些都是非常好的建议,所以一定要查看它们! ...
...首席工程师Dhia Mahjoub在USENIX Enigma 2017的演讲中解释了更多关于流程的内容: ...
...。不管你是新手还是母语人士,这都会让人困惑,尤其是关于正确用法的复杂规则。谢天谢地,这里有一些优秀的语法和标点符号网站,可以解释你需要知道的一切。 ...
...你可以进一步定制你的搜索结果。另外,如果你需要更多关于搜索内容的想法,你可以参考这些免费的网站来找到下一本书。 ...
...来进行一些额外的设置。您可以在我们的指南中阅读所有关于将本地组策略调整应用于特定用户的内容。 您还应该意识到组策略是一个非常强大的工具,因此值得花一些时间来了解它的功能。另外,如果你在公司网络上,帮每...
...果你不使用快速操作按钮,你可以很容易地隐藏他们使用注册表黑客。 相关:如何使用和自定义Windows 10操作中心 如何通过编辑注册表删除快速操作按钮 您可以自定义快速操作按钮上可用的操作,也可以隐藏整个操作中心。但...