㈠ 哪些端口是通过java RMI连接使用
RMI的优势
这种机制给分布计算的系统设计、编程都带来了极大的方便。只要按照RMI规则设计程序,可以不必再过问在RMI之下的网络细节了,如:TCP和Socket等等。任意两台计算机之间的通讯完全由RMI负责。调用远程计算机上的对象就像本地对象一样方便。
1、面向对象:
RMI可将完整的对象作为参数和返回值进行传递,而不仅仅是预定义的数据类型。也就是说,可以将类似Java Hash表这样的复杂类型作为一个参数进行传递。
2、可移动属性:
RMI可将属性从客户机移动到服务器,或者从服务器移动到客户机。
3、设计方式:
对象传递功能使你可以在分布式计算中充分利用面向对象技术的强大功能,如二层和三层结构系统。如果用户能够传递属性,那么就可以在自己的解决方案中使用面向对象的设计方式。所有面向对象的设计方式无不依靠不同的属性来发挥功能,如果不能传递完整的对象——包括实现和类型——就会失去设计方式上所提供的优点。
4、安全性:
RMI使用Java内置的安全机制保证下载执行程序时用户系统的安全。RMI使用专门为保护系统免遭恶意小程序侵害而设计的安全管理程序。
5、便于编写和使用
RMI使得Java远程服务程序和访问这些服务程序的Java客户程序的编写工作变得轻松、简单。远程接口实际上就是Java接口。为了实现RMI的功能必须创建远程对象任何可以被远程调用的对象必须实现远程接口。但远程接口本身并不包含任何方法。因而需要创建一个新的接口来扩展远程接口。新接口将包含所有可以远程调用的方法。远程对象必须实现这个新接口,由于新的接口扩展了远程接口,实现了新接口,就满足了远程对象对实现远程接口的要求,所实现的每个对象都将作为远程对象引用。
一个国外的PPT上还还总结到:
Java RMI Advantages:
Full object support
Cross platform. capabilities
Robust communications
Large objects
Security for client and servers
Distribution/updates of codes
RMI的劣势
从上面的过程来看,RMI对服务器的IP地址和端口依赖很紧密,但是在开发的时候不知道将来的服务器IP和端口如何,但是客户端程序依赖这个IP和端口。这也是RMI的局限性之一。这个问题有两种解决途径:一是通过DNS来解决,二是通过封装将IP暴露到程序代码之外。
RMI的局限性之二是RMI是Java语言的远程调用,两端的程序语言必须是Java实现,对于不同语言间的通讯可以考虑用Web Service或者公用对象请求代理体系(CORBA)来实现。
一个国外的PPT上也总结到:
Java RMI Disadvantages:
Java RMI only supports Java
Proprietary protocol by single vendor
Requires RMI-lookup
Requires non-standard port
RMI与Socket的比较
RMI技术比较socket的网络编程主要有以下几个方面:
第一、RMI是面向对象的,而后者不是。
第二、RMI是与语言相绑定的。比如当你使用Java RMI技术的时候,客户端与服务器端都必须使用Java开发。而socket的网络编程是使用独立于开发语言的,甚至独立于平台。基于socket的网络编程,客户端与服务器端可以使用不同开发语言和不同的平台。
第三、从网络协议栈的观点来看,RMI与socket的网络编程处于不同层次上。基于socket的网络编程位于TCP协议之上,而RMI在TCP协议之上,又定义了自己的应用协议,其传输层采用的是Java远程方法协议(JRMP)。可见,在网络协议栈上,基于RMI的应用位置更高一些,这也决定了,与socket的网络编程相比,RMI会丧失一些灵活性和可控性,但是好处是它带给了应用开发者更多的简洁,方便和易用。比如:如果你用的是RMI,你不需要关心消息是怎么序列化的,你只需要像本地方法调用一样,使用RMI。代价是:应用开发者无法很好地控制消息的序列化机制。
第四、这是最后一点不同,我认为也是比较重要的一点,就是两种方法的性能比较,其往往决定着你将使用那种技术来开发你的应用。
实验的结果是:RMI与TCP based socket相比,传输相同的有效数据,RMI需要占用更多的网络带宽(protocol overhead)。从这里,我们可以得出一个一般性的结论:RMI主要是用于远程方法的”调用“(RMI是多么的名符其实:)),其技术内涵强调的是 “调用”,基于此,我能想到的是:移动计算,和远程控制,当你的应用不需要在client与server之间传输大量的数据时,RMI是较好的选择,它简洁、易于开发。但是,一旦你的应用需要在client与server之间传输大量的数据,极端的,比如FTP应用,则RMI是不适合的,我们应该使用 socket。
PS: RMI的效率还是很高的,一般情况下会比Hessian更高效,比Web Service更是高效很多;当然和socket这种东东相比,当然要低效一点了,socket更底层一些啊。RMI的具体实现,依然是依赖于底层的Socket编程。
一个简单的RMI系统,一般可以分成4个文件,下面来介绍各个文件的创建和作用
第一步:创建一个远程对象接口
import java.rmi.Remote;
import java.rmi.RemoteException;
/*
* 这个接口继承自Remote,每一个定义的方法都必须抛出一个RemoteException异常对象
* 我们可供远程调用的方法就是通过这里开公开
*/ public interface IRMI extends Remote{
public String invoke() throws RemoteException;
} 12345678910
第二步:创建接口的具体实现类
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
/*
* 远程对象的实现
* 公开方法的具体实现就是这里定义的
*/ public class IRMIImpl extends UnicastRemoteObject implements IRMI {
protected IRMIImpl() throws RemoteException {
super(); // 这个实现必须有一个显式的构造函数,并且要抛出一个RemoteException异常
}
private static final long serialVersionUID = 6131922116577454476L;
public String invoke() throws RemoteException { //该方法公开
return "hello,world!";
}
public String tryInvoke() throws RemoteException{ //该方法未公开,若要公开请在接口中定义
return "try to remote me";
}
}
第三步:创建RMI服务器
import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
/*
* 远程对象的注册类 该类应该在服务器端执行,执行之后
* 该机器将变为RMI服务器 客户端可以通过正确的url来访问
* 服务器上的远程对象,执行对外报露的方法
*/ public class RMIServer {
static int port = 8888;
/*
* 创建一个Registry对象.
* LocateRegistry用于获取名字服务或创建名字服务.
* 调用LocateRegistry.createRegistry(int port)方法可以在某一特定端口创建名字服务,从而用户无需再手工启动rmiregistry
* @return 返回一个Registry对象
*/
private static Registry createRegistry() {
Registry registry = null;
try {
registry = LocateRegistry.getRegistry(port); //如果该端口未被注册,则抛异常
registry.list(); //拿到该端口注册的rmi对象
} catch (final Exception e) {
try {
registry = LocateRegistry.createRegistry(port);//捕获异常,端口注册
} catch (final Exception ee) {
ee.printStackTrace();
}
}
return registry;
}
/**
* 将对象注册到rmi服务器上
*/
public static void bind() {
Registry registry = createRegistry();
try {
IRMIImpl impl = new IRMIImpl();
registry.rebind("mytask", impl); //这就是绑定,client里lookup必须和"mytast"一样才能远程调用impl
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
try {
bind();
} catch (Exception e) {
e.printStackTrace();
}
}
}
上面是一种比较好的写法,如果只是要测试,可以直接在main()方法中写:
ImplementClass ic = new ImplementClass(); //具体实现类
Registry r = LocateRegistry.createRegistry(8888);
r.bind("mytask", ic);
//Naming.rebind("rmi://localhost:8888/mytask", ic); 可替换上句 1234
1.注册一个端口 2.在注册端口绑定taskName和implementClass 3.客户端就可以通过url和taskName来找到implementClass。
第四步:创建RMI客户端
import java.rmi.Naming;
public class RMIClient {
/**
* 调用远程对象中的方法
* @throws Exception
*/
public static void getRemoteObject() throws Exception{
/*得到远程发布的服务
返回与指定 name 关联的远程对象的引用(一个stub)*/
IRMI obj = (IRMI)Naming.lookup("rmi://localhost:"+RMIServer.port+"/mytask"); //注:通过接口拿
System.out.println(obj.invoke()); //调用远程服务的方法
}
public static void main(String[] args) {
try {
getRemoteObject();
} catch (Exception e) {
e.printStackTrace();
}
}
} 24
运行RMI系统:启动RMI服务器,启动客户端即可。
㈡ Java RMI调用远程程序抛出异常
背景要求:定时监控远程主机上mongodb数据库内存使用的情况,当内存使用过大时暂停逻辑处理线程后启动内存空间的释放处理线程,释放完成后再启动逻辑处理线程。
操作系统:CentOS 64bit (Linux)
步骤(代码省略):
1.创建Socket远程服务器
2.创建客户端
配置:
#查找对象stub端口
RMI_PORT=9902
#服务端口
RMI_SERV_RMI_PORT=9903
#注册服务地址端口要和查找对象stub端口一致
RMI_URL=rmi://192.168.0.118:9902/MongoServer
#绑定IP
RMI_IP=192.168.0.118
#检查内存shell
RMI_MEMQUERY_COMMAND=sh /home/test/BI/smartshow14/MongoDBRMIServer/memquery.sh
#释放内存shell
RMI_MEMFREE_COMMAND=sh /home/test/BI/smartshow14/MongoDBRMIServer/memclear.sh
#释放内存容量阀值,单位M
RMI_MEM_CAPACITY_LIMIT=3000
3.启动服务器
客户端线程通过 rmi://192.168.0.118:9902/MongoServer 访问时出现异常:
--定时扫描MONGODB内存线程--:开始运行!
java.rmi.UnmarshalException: error unmarshalling return; nested exception is:
java.lang.ClassNotFoundException: com.linkage.iface.IMongoDBScan (no security manager: RMI class loader disabled)
at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source)
at java.rmi.Naming.lookup(Naming.java:84)
at com.linkage.querytool.QueryRMICaller.ramCapacityScan(QueryRMICaller.java:87)
at com.linkage.querytool.MongoDBARMScanThread$TimerWorkTask.run(MongoDBARMScanThread.java:94)
at java.util.TimerThread.mainLoop(Timer.java:512)
at java.util.TimerThread.run(Timer.java:462)
Caused by: java.lang.ClassNotFoundException: com.linkage.iface.IMongoDBScan (no security manager: RMI class loader disabled)
at sun.rmi.server.LoaderHandler.loadProxyClass(LoaderHandler.java:535)
at java.rmi.server.RMIClassLoader$2.loadProxyClass(RMIClassLoader.java:628)
at java.rmi.server.RMIClassLoader.loadProxyClass(RMIClassLoader.java:294)
at sun.rmi.server.MarshalInputStream.resolveProxyClass(MarshalInputStream.java:238)
at java.io.ObjectInputStream.readProxyDesc(ObjectInputStream.java:1530)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1492)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1731)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
... 6 more
--定时扫描MONGODB内存线程--:处理结束!
=======================================================================================================
--定时扫描MONGODB内存线程--:开始运行!
java.security.AccessControlException: access denied (java.net.SocketPermission 192.168.0.118:9902 connect,resolve)
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:374)
at java.security.AccessController.checkPermission(AccessController.java:546)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
at java.lang.SecurityManager.checkConnect(SecurityManager.java:1034)
at java.net.Socket.connect(Socket.java:524)
at java.net.Socket.connect(Socket.java:478)
at java.net.Socket.<init>(Socket.java:375)
at java.net.Socket.<init>(Socket.java:189)
at sun.rmi.transport.proxy.RMIDirectSocketFactory.createSocket(RMIDirectSocketFactory.java:22)
at sun.rmi.transport.proxy.RMIMasterSocketFactory.createSocket(RMIMasterSocketFactory.java:128)
at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:595)
at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:198)
at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:184)
at sun.rmi.server.UnicastRef.newCall(UnicastRef.java:322)
at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source)
at java.rmi.Naming.lookup(Naming.java:84)
at com.linkage.querytool.QueryRMICaller.ramCapacityScan(QueryRMICaller.java:89)
at com.linkage.querytool.MongoDBARMScanThread$TimerWorkTask.run(MongoDBARMScanThread.java:94)
at java.util.TimerThread.mainLoop(Timer.java:512)
at java.util.TimerThread.run(Timer.java:462)
--定时扫描MONGODB内存线程--:处理结束!
============================================================================================================
--定时扫描MONGODB内存线程--:开始运行!
java.security.AccessControlException: access denied (java.lang.RuntimePermission createSecurityManager)
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:374)
at java.security.AccessController.checkPermission(AccessController.java:546)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
at java.lang.SecurityManager.<init>(SecurityManager.java:282)
at java.rmi.RMISecurityManager.<init>(RMISecurityManager.java:45)
at com.linkage.querytool.QueryRMICaller.ramCapacityScan(QueryRMICaller.java:88)
at com.linkage.querytool.MongoDBARMScanThread$TimerWorkTask.run(MongoDBARMScanThread.java:94)
at java.util.TimerThread.mainLoop(Timer.java:512)
at java.util.TimerThread.run(Timer.java:462)
--定时扫描MONGODB内存线程--:处理结束!
==========================================================================================================
以上异常都有可能出现,通过以下方式可解除问题:
1.在客户端程序前打开安全管理器:
try {
System.setSecurityManager(new java.rmi.RMISecurityManager());
mds = (IMongoDBScan) Naming.lookup(urlStr);
} catch (MalformedURLException e) {
//..........
}
2.修改/usr/java/jdk1.6.0_21/jre/lib/security/java.policy后重启
grant {
permission java.security.AllPermission;
}
㈢ java RMI是什么意思啊
RMI 指的是远程方法调用 (Remote Method Invocation)。它是一种机制,能够让在某个 Java 虚拟机上的对象专调用另一个 Java 虚拟机中的属对象上的方法。可以用此方法调用的任何对象必须实现该远程接口。调用这样一个对象时,其参数为 "marshalled" 并将其从本地虚拟机发送到远程虚拟机(该远程虚拟机的参数为 "unmarshalled")上。该方法终止时,将编组来自远程机的结果并将结果发送到调用方的虚拟机。如果方法调用导致抛出异常,则该异常将指示给调用方。
㈣ android 怎么使用java rmi
1、定义一个远程接口
IHello.java代码如下:
importjava.rmi.Remote;
{
publicStringsayHello(Stringname)throwsjava.rmi.RemoteException;
}
2、实现远程的接口(服务端就在此远程接口的实现类中)
HelloImpl.java代码如下:
importjava.rmi.RemoteException;
importjava.rmi.server.UnicastRemoteObject;
{
//这个实现必须有一个显式的构造函数,并且要抛出一个RemoteException异常
protectedHelloImpl()throwsRemoteException{
super();
}
/**
*说明清楚此属性的业务含义
*/
=4077329331699640331L;
publicStringsayHello(Stringname)throwsRemoteException{
return"Hello"+name+"^_^";
}
publicstaticvoidmain(String[]args){
try{
IHellohello=newHelloImpl();
java.rmi.Naming.rebind("rmi://localhost:1099/hello",hello);
System.out.print("Ready");
}catch(Exceptione){
e.printStackTrace();
}
}
}
3、新建RMI客户端调用程序
Hello_RMI_Client.java代码如下:
importjava.rmi.Naming;
publicclassHello_RMI_Client{
publicstaticvoidmain(String[]args){
try{
IHellohello=(IHello)Naming.lookup("rmi://localhost:1099/hello");
System.out.println(hello.sayHello("zhangxianxin"));
}catch(Exceptione){
e.printStackTrace();
}
}
}
4、编译并运行
4.1 用javac命令编译IHello.java、HelloImpl.java、Hello_RMI_Client.java
>javac*.java
4.2用rmic命令生成桩和框架文件
>rmicHelloImpl
成功执行完上面的命令可以发现生成一个HelloImpl_stub.class文件,如果JDK是使用Java2SDK,那么还可以发现多出一个HelloImpl_Skel.class文件。如果服务端程序与客户端程序在同一台机器上并在同一目录中,则可以省略掉接口实现类生成的桩和框架文件,但这就失去了使用RMI的意义,而如果要在不同的JVM上运行时,客户端程序就必须得依靠服务端运程方法实现的桩和框架文件以及接口类。
4.3运行注册程序RMIRegistry,必须在包含刚写的类的目录下运行这个注册程序。
>rmiregistry
注册程序开始运行了,不要管他,现在切换到另外一个控制台运行服务器
4.4运行服务器HelloImpl
>javaHelloImpl
当启动成功出现Ready......这个服务器就开始工作了,把接口的实现加载到内存等待客户端的联接。现在切换到第三个控制台,启动我们的客户端。
4.5启动客户端:为了在其他的机器运行客户端程序你需要一个远程接口(IHello.class)和一个stub(HelloImpl_Stub.class)。使用如下命令运行客户端
>javaHello_RMI_Client
当运行成功会在控制台打印:Hellozhangxianxin(www.tiecou.com) ^_^
备注:如果不想在控制台上开启RMI注册程序RMIRegistry的话,可在RMI服务类程序中添加LocateRegistry.createRegistry(1099); 如下所示:
修改后的HelloImpl.java代码如下:
importjava.rmi.RemoteException;
importjava.rmi.registry.LocateRegistry;
importjava.rmi.server.UnicastRemoteObject;
{
//这个实现必须有一个显式的构造函数,并且要抛出一个RemoteException异常
protectedHelloImpl()throwsRemoteException{
super();
}
=4077329331699640331L;
publicStringsayHello(Stringname)throwsRemoteException{
return"Hello"+name+"^_^";
}
publicstaticvoidmain(String[]args){
try{
IHellohello=newHelloImpl();
LocateRegistry.createRegistry(1099);//加上此程序,就可以不要在控制台上开启RMI的注册程序,1099是RMI服务监视的默认端口
java.rmi.Naming.rebind("rmi://localhost:1099/hello",hello);
System.out.print("Ready");
}catch(Exceptione){
e.printStackTrace();
}
}
}
㈤ 什么是 rmi
RMI采用JRMP(Java Remote Method Protocol)通讯协议,是构建在TCP/IP协议上的一种远程调用方法。
更详细请点击:
http://www.hur.cn/web/program/java/JAVA06/200511/2377.html