精华内容
下载资源
问答
  • JAVA RMI实例

    2021-03-13 20:02:44
    创建RMI程序的6个步骤:1、定义一个远程接口的接口,该接口中的每一个方法必须声明它将产生一个RemoteException异常。2、定义一个实现该接口的类。3、使用RMIC程序生成远程实现所需的残根和框架。4、创建一个服务器...

    创建RMI程序的6个步骤:

    1、定义一个远程接口的接口,该接口中的每一个方法必须声明它将产生一个RemoteException异常。

    2、定义一个实现该接口的类。

    3、使用RMIC程序生成远程实现所需的残根和框架。

    4、创建一个服务器,用于发布2中写好的类。

    5. 创建一个客户程序进行RMI调用。

    6、启动rmiRegistry并运行自己的远程服务器和客户程序

    1步

    定义一个远程接口的接口,该接口中的每一个方法必须声明它将产生一个RemoteException异常

    Java代码

    1.package rmi;

    2.

    3.import java.rmi.RemoteException;

    4.

    5./**

    6. * 第一步,定义一个远程接口,该接口中的每一个方法必须声明它将产生一个RemoteException异常

    7. */

    8.

    9.//接口里定义一个返回字符串的远程方法 SayHello(),这个远程接口 I_Hello必须是public的

    10.//它必须从java.rmi.Remote继承而来,接口中的每一个方法都必须抛出远程异常java.rmi.RemoteException。

    11.//

    12.//抛出这个异常的原因:由于任何远程方法调用实际上要进行许多低级网络操作,因此网络错误可能在调用过程中随时发生

    13.//因此,所有的RMI操作都应放到try-catch块中

    14.

    15.

    16.//需要从Remote继承

    17.public interface I_Hello extends java.rmi.Remote{

    18.

    19.    //需要抛出remote异常

    20.    public String SayHello() throws RemoteException;

    21.}

    package rmi;

    import java.rmi.RemoteException;

    /**

    * 第一步,定义一个远程接口,该接口中的每一个方法必须声明它将产生一个RemoteException异常

    */

    //接口里定义一个返回字符串的远程方法 SayHello(),这个远程接口 I_Hello必须是public的

    //它必须从java.rmi.Remote继承而来,接口中的每一个方法都必须抛出远程异常java.rmi.RemoteException。

    //

    //抛出这个异常的原因:由于任何远程方法调用实际上要进行许多低级网络操作,因此网络错误可能在调用过程中随时发生

    //因此,所有的RMI操作都应放到try-catch块中

    //需要从Remote继承

    public interface I_Hello extends java.rmi.Remote{

    //需要抛出remote异常

    public String SayHello() throws RemoteException;

    }

    2步

    定义一个实现该接口的类

    Java代码

    1.package rmi;

    2.

    3.import java.rmi.*;

    4.import java.rmi.server.UnicastRemoteObject;

    5.

    6./**

    7. * 第二步,定义一个实现远程接口的类

    8. */

    9.

    10.//实现接口的类必须继承UnicastRemoteObject类,扩展java.rmi.server.UnicastRemoteObject

    11.

    12.public class Hello extends UnicastRemoteObject //必须从UnicastRemoteObject 继承

    13.        implements I_Hello {

    14.    public Hello() throws RemoteException{ //需要一个抛出Remote异常的默认初始化方法

    15.    }

    16.

    17.    public String SayHello(){ //这个是实现I_Hello接口的方法

    18.        return "Hello world !!";

    19.    }

    20.}

    package rmi;

    import java.rmi.*;

    import java.rmi.server.UnicastRemoteObject;

    /**

    * 第二步,定义一个实现远程接口的类

    */

    //实现接口的类必须继承UnicastRemoteObject类,扩展java.rmi.server.UnicastRemoteObject

    public class Hello extends UnicastRemoteObject //必须从UnicastRemoteObject 继承

    implements I_Hello {

    public Hello() throws RemoteException{ //需要一个抛出Remote异常的默认初始化方法

    }

    public String SayHello(){ //这个是实现I_Hello接口的方法

    return "Hello world !!";

    }

    }

    3步

    使用RMIC程序生成远程实现所需的残根Stub 和 框架

    这一步是关键,也是最容易出问题的地方,需要多说几句:

    在RMI中,客户机上生成的调动调用参数和反调动返回值的代码称为残根。有的书上称这部分代码为“主干”。

    服务器上生成的反调动调用参数和进行实际方法调用调动返回值的代码称为框架

    2中的Hello编译好以后,我们就可以用RMIC命令来生成残根Stub

    操作是:在cmd下到Hello.class 所在目录,运行以下命令:rmic Hello

    命令执行完以后,将会在当前目录生成一个 Hello_Stub.class 这个就是我们远程调用时需要的类

    如果您是照着上面的方法做的,现在应该会遇到报的第一个错:Class xxx not found

    解决方法分两步

    首先,打开环境变量,将项目路径D:\workspace_bohai_FXM\ztest(项目名)\rmi(包名)添加到classpath中,在cmd下set一下,看看是否设置好了

    然后,cmd下输入要注意,如果你要rmic的.class文件在包下,就必须cd到目标.class文件所在包的目录下,此例

    是:D:\workspace_bohai_FXM\ztest>rmic

    rmi.Hello,在你的rmi目录下会生成两个文件Hello_Stub.class和Hello_Skel.class。

    Hello_Stub.class 这个就是我们远程调用时需要的类

    4步

    创建一个服务器,用于发布2中写好的类

    Java代码

    1.package rmi;

    2.

    3.import java.rmi.*;

    4.

    5./**

    6. * 4步,创建一个服务器,用于发布类Hello

    7. */

    8.

    9.public class RMI_Server {

    10.    public static void main(String[] args) {

    11.        try {

    12.            //实例化要发布的类

    13.            Hello hello = new Hello();

    14.            //绑定RMI名称 进行发布,即客户端通过这个名字查找的对象就是hello这个实例

    15.            Naming.rebind("RMI_Hello", hello);

    16.            System.out.println("=== Hello server Ready === ");

    17.        } catch (Exception exception) {

    18.            exception.printStackTrace();

    19.        }

    20.    }

    21.}

    package rmi;

    import java.rmi.*;

    /**

    * 4步,创建一个服务器,用于发布类Hello

    */

    public class RMI_Server {

    public static void main(String[] args) {

    try {

    //实例化要发布的类

    Hello hello = new Hello();

    //绑定RMI名称 进行发布,即客户端通过这个名字查找的对象就是hello这个实例

    Naming.rebind("RMI_Hello", hello);

    System.out.println("=== Hello server Ready === ");

    } catch (Exception exception) {

    exception.printStackTrace();

    }

    }

    }

    5步

    创建一个客户程序进行RMI调用

    Java代码

    1.package rmi;

    2.

    3./**

    4. * 5步,创建一个客户程序进行RMI调用

    5. */

    6.

    7.import java.rmi.*;

    8.

    9.public class RMI_Client {

    10.    public static void main(String[] args) {

    11.        try {

    12.            I_Hello hello = (I_Hello) Naming.lookup("RMI_Hello"); //通过RMI名称查找远程对象

    13.            //如果是异地的RMI调用请参照    rmi://127.0.0.1:1099/RMI_Hello

    14.            //端口1099是默认的RMI端口,如果你启动 rmiregistry 的时候,没有指定特殊的端口号,默认就是1099

    15.

    16.            System.out.println(hello.SayHello()); //核心句:调用远程对象的方法

    17.        } catch (Exception e) {

    18.            e.printStackTrace();

    19.        }

    20.    }

    21.

    22.}

    package rmi;

    /**

    * 5步,创建一个客户程序进行RMI调用

    */

    import java.rmi.*;

    public class RMI_Client {

    public static void main(String[] args) {

    try {

    I_Hello hello = (I_Hello) Naming.lookup("RMI_Hello"); //通过RMI名称查找远程对象

    //如果是异地的RMI调用请参照    rmi://127.0.0.1:1099/RMI_Hello

    //端口1099是默认的RMI端口,如果你启动 rmiregistry 的时候,没有指定特殊的端口号,默认就是1099

    System.out.println(hello.SayHello()); //核心句:调用远程对象的方法

    } catch (Exception e) {

    e.printStackTrace();

    }

    }

    }

    6步

    启动rmiRegistry并运行自己的远程服务器和客户程序

    cmd下运行命令rmiregistry,然后放在一边不用管他(第一个cmd窗口)

    然后通过cmd运行Server,直接在IDE里运行一般会报错:找不到Stub类,需要用下面的命令来运行,命令里指定了stub类的路径

    cmd到D:\workspace_bohai_FXM\ztest>目录下运行java.exe -Djava.rmi.server.codebase=file:/D:\workspace_bohai_FXM\ztest/ rmi.RMI_Server

    (注意:ztext是项目名,rmi是包,最后的那个ztest/后有一个空格)

    回车后cmd会显示:=== Hello server Ready ===

    (代表Server成功启动,第二个cmd窗口)

    然后在运行Client就会看到你千辛万苦远程方法调用的结果:Hello world !!

    上文转自:http://damiao-cn.iteye.com/blog/228948    原创不知是谁

    弄了好几个小时,最后还是跑起来了。

    报Hello_Stub.class这个找不到,网上查了哈,说要把Hello_Stub.class所在目录加到CLASSPATH里面,果然问题解决,再重新注册成功。

    JAVA的RMI和.NET的remoting大同小异,原理基本一样,都用于跨域访问对象。

    展开全文
  • java rmi+jndi

    2021-08-11 14:49:06
    java rmi+jndi fastjson和这篇文章都是公司内容分享,我要分享的内容 java rmi讲解 https://xz.aliyun.com/t/7930#toc-5 基本知识讲解 在Java反序列化漏洞挖掘或利用的时候经常会遇见RMI,本文会讲述什么是RMIRMI...

    java rmi+jndi

    fastjson和这篇文章都是公司内容分享,我要分享的内容

    java rmi讲解

    https://xz.aliyun.com/t/7930#toc-5

    基本知识讲解

    在Java反序列化漏洞挖掘或利用的时候经常会遇见RMI,本文会讲述什么是RMI、RMI攻击方法、JEP290限制、绕过JEP290限制。

    JAVA本身提供了一种RPC框架 RMI及Java 远程方法调用(Java Remote Method Invocation),可以在不同的Java 虚拟机之间进行对象间的通讯,RMI是基于JRMP协议(Java Remote Message Protocol Java远程消息交换协议)去实现的。

    RMI全称是Remote Method Invocation,远程⽅法调⽤。从这个名字就可以看出,他的⽬标和RPC其实是类似的,是让某个Java虚拟机上的对象调⽤另⼀一个Java虚拟机中对象上的方法,只不过RMI是Java独有的一种机制。

    名次解释:
    JRMP协议。=》Java Remote Message Protocol ,Java 远程消息交换协议。这是运行在Java RMI之下、TCP/IP之上的线路层协议。该协议要求服务端与客户端都为Java编写,就像HTTP协议一样,规定了客户端和服务端通信要满足的规范。
    rmi=〉远程方法调用

    在这里插入图片描述

    RMI主要分为三部分

    • RMI Registry注册中心
    • RMI Client 客户端
    • RMI Server服务端

    RMI Registry就像一个⽹网关,他⾃己是不执行远程方法的,但RMI Server可以在上面注册⼀个Name 到对象的绑定关系;RMI Client通过Name向RMI Registry查询,得到这个绑定关系,然后再连接RMI Server;最后,远程方法实际上在RMI Server上调⽤用。

    在这里插入图片描述

    在这里插入图片描述

    //RMIServer.java

    package org.vulhub.RMI;
    import java.rmi.Naming;
    import java.rmi.Remote;
    import java.rmi.RemoteException;
    import java.rmi.registry.LocateRegistry;
    import java.rmi.registry.Registry;
    import java.rmi.server.UnicastRemoteObject;
    public class RMIServer {
        public interface IRemoteHelloWorld extends Remote {
            public String hello() throws RemoteException;
        }
        public class RemoteHelloWorld extends UnicastRemoteObject implements
    IRemoteHelloWorld {
            protected RemoteHelloWorld() throws RemoteException {
                super();
    } 
            public String hello() throws RemoteException {
                System.out.println("call from");
                return "Hello world";
    } } 
        private void start() throws Exception {
            RemoteHelloWorld h = new RemoteHelloWorld();
            LocateRegistry.createRegistry(1099);
            Naming.rebind("rmi://127.0.0.1:1099/Hello", h);
        }
        public static void main(String[] args) throws Exception {
    	  	new RMIServer().start();
    	  }
    }
    

    一个RMI Server分为三部分:

    1. ⼀个继承了java.rmi.Remote的接⼝,其中定义我们要远程调用的函数,⽐如这里的hello()
    2. ⼀个实现了此接口的类
    3. ⼀个主类,用来创建Registry,并将上⾯的类实例化后绑定到⼀个地址。这就是我们所谓的Server 了。

    //RMIClient.java

    package org.vulhub.Train;
    import org.vulhub.RMI.RMIServer;
    import java.rmi.Naming;
    import java.rmi.NotBoundException;
    import java.rmi.RemoteException;
    public class TrainMain {
        public static void main(String[] args) throws Exception {
            RMIServer.IRemoteHelloWorld hello = (RMIServer.IRemoteHelloWorld)
    Naming.lookup("rmi://192.168.135.142:1099/Hello");
            String ret = hello.hello();
            System.out.println( ret);
        }
    } 
    

    怎么进行攻击

    思考两个问题

    1. 如果我们能访问RMI Registry服务,如何对其攻击?
    2. 如果我们控制了目标RMI客户端中 Naming.lookup 的第一个参数(也就是RMI Registry的地
      址),能不能进行攻击?

    原来Java对远程访问RMI Registry做了限制,只有来源地址是localhost的时候,才能调用rebind、 bind、unbind等方法。
    在这里插入图片描述

    不过list和lookup方法可以远程调用。 list方法可以列出目标上所有绑定的对象 :
    String[] s = Naming.list(“rmi://192.168.135.142:1099”);

    只要目标服务器上存在一些危险方法,我们通过RMI就可以对其进行调用,之前曾经有一个工具
    https://github.com/NickstaDB/BaRMIe,其中一个功能就是进行危险方法的探测。

    Jep290

    JEP290是Java为了应对反序列化而设置的一种过滤器,理想状态是让开发者只反序列化其想反序列化的类,这样我们使用类似CC这样的,就会因为无法反序列化Tranformer、HashMap等,从而没法触发漏洞。

    从代码中可以发现,这个过滤器设置了白名单,他会判断你要反序列化的类(或者反序列化类的父类)是否在以下列表中(仅用于RmiRegistry):

    String.class
    Remote.class
    Proxy.class
    UnicastRef.class
    RMIClientSocketFactory.class
    RMIServerSocketFactory.class
    ActivationID.class
    UID.class
    

    如果不在,则会标记为REJECTED,此时不会反序列化成功,反之则标记为ALLOWED,此时则可以反序列化成功。

    JNDI

    名词解释:

    • RMI(Remote Method Invocation) 即Java远程方法调用,一种用于实现远程过程调用的应用程序编程接口,常见的两种接口实现为JRMP(Java Remote Message Protocol,Java远程消息交换协议)以及CORBA。

    • JNDI (Java Naming and Directory Interface)是一个应用程序设计的API,为开发人员提供了查找和访问各种命名和目录服务的通用、统一的接口。JNDI支持的服务主要有以下几种:DNS、LDAP、 CORBA对象服务、RMI等。

    动态类加载
    RMI核心特点之一就是动态类加载,如果当前JVM中没有某个类的定义,它可以从远程URL去下载这个类的class,动态加载的对象class文件可以使用Web服务的方式进行托管。这可以动态的扩展远程应用的功能,RMI注册表上可以动态的加载绑定多个RMI应用。对于客户端而言,服务端返回值也可能是一些子类的对象实例,而客户端并没有这些子类的class文件,如果需要客户端正确调用这些子类中被重写的方法,则同样需要有运行时动态加载额外类的能力。客户端使用了与RMI注册表相同的机制。RMI服务端将URL传递给客户端,客户端通过HTTP请求下载这些类。
    这个概念比较重要,JNDI注入的利用方法中也借助了动态加载类的思路。

    关于JNDI
    JNDI (Java Naming and Directory Interface) 是一组应用程序接口,它为开发人员查找和访问各种资源提供了统一的通用接口,可以用来定位用户、网络、机器、对象和服务等各种资源。比如可以利用JNDI在局域网上定位一台打印机,也可以用JNDI来定位数据库服务或一个远程Java对象。JNDI底层支持RMI远程对象,RMI注册的服务可以通过JNDI接口来访问和调用。
    JNDI支持多种命名和目录提供程序(Naming and Directory Providers),RMI注册表服务提供程序(RMI Registry Service Provider)允许通过JNDI应用接口对RMI中注册的远程对象进行访问操作。将RMI服务绑定到JNDI的一个好处是更加透明、统一和松散耦合,RMI客户端直接通过URL来定位一个远程对象,而且该RMI服务可以和包含人员,组织和网络资源等信息的企业目录链接在一起。

    JNDI注入原理
    JNDI支持很多服务类型,当服务类型为RMI协议时,如果从RMI注册服务中lookup的对象类型为Reference类型或者其子类时,会导致远程代码执行,Reference类提供了两个比较重要的属性,className以及codebase url,classname为远程调用引用的类名,那么codebase url决定了在进行rmi远程调用时对象的位置,此外codebase url支持http协议,当远程调用类(通过lookup来寻找)在RMI服务器中的CLASSPATH中不存在时,就会从指定的codebase url来进行类的加载,如果两者都没有,远程调用就会失败。

    JNDI RCE漏洞产生的原因就在于当我们在注册RMI服务时,可以指定codebase url,也就是远程要加载类的位置,设置该属性可以让JNDI应用程序在加载时加载我们指定的类( 例如:http://www.iswin.org/xx.class) ,当JNDI应用程序通过lookup(RMI服务的地址)调用指定codebase url上的类后,会调用被远程调用类的构造方法,所以如果我们将恶意代码放在被远程调用类的构造方法中时,漏洞就会触发。

    JNDI接口在初始化时,可以将RMI URL作为参数传入,而JNDI注入就出现在客户端的lookup()函数中,如果lookup()的参数可控就可能被攻击。

    Hashtable env = new Hashtable();
    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");
    //com.sun.jndi.rmi.registry.RegistryContextFactory 是RMI Registry Service Provider对应的Factory
    env.put(Context.PROVIDER_URL, "rmi://kingx_kali:8080");
    Context ctx = new InitialContext(env);
    Object local_obj = ctx.lookup("rmi://kingx_kali:8080/test");
    

    整个利用流程如下:

    1. 目标代码中调用了InitialContext.lookup(URI),且URI为用户可控;

    2. 攻击者控制URI参数为恶意的RMI服务地址,如:rmi://hacker_rmi_server//name;

    3. 攻击者RMI服务器向目标返回一个Reference对象,Reference对象中指定某个精心构造的Factory类;

    4. 目标在进行lookup()操作时,会动态加载并实例化Factory类,接着调用factory.getObjectInstance()获取外部远程对象实例;

    5. 攻击者可以在Factory类文件的构造方法、静态代码块、getObjectInstance()方法等处写入恶意代码,达到RCE的效果;

    6. 攻击者为易受攻击的JNDI的lookup方法提供了绝对的RMI URL

    7. 服务器连接到受攻击者控制的RMI注册表,该注册表将返回恶意JNDI引用

    8. 服务器解码JNDI引用

    9. 服务器从攻击者控制的服务器获取Factory类

    10. 服务器实例化Factory类

    11. 有效载荷得到执行

    在JDK 6u132, JDK 7u122, JDK 8u113 中Java提升了JNDI 限制了Naming/Directory服务中JNDI Reference远程加载Object Factory类的特性。系统属性 com.sun.jndi.rmi.object.trustURLCodebase、com.sun.jndi.cosnaming.object.trustURLCodebase 的默认值变为false,即默认不允许从远程的Codebase加载Reference工厂类。

    利用fastjson漏洞做演示:
    演示可参考:
    https://medium.com/@m01e/java%E5%AE%89%E5%85%A8-jndi%E6%B3%A8%E5%85%A5-ab5134574323

    https://www.smi1e.top/java%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E5%AD%A6%E4%B9%A0%E4%B9%8Bjndi%E6%B3%A8%E5%85%A5/

    GitHub - threedr3am/learnjavabug: Java安全相关的漏洞和技术demo,原生Java、Fastjson、Jackson、Hessian2、XML反序列化漏洞利用和Spring、Dubbo、Shiro、CAS、Tomcat、RMI、Nexus等框架\中间件\功能的exploits以及Java Security Manager绕过、Dubbo-Hessian2安全加固等等实践代码。

    展开全文
  • Java RMI服务搭建

    2021-02-27 16:33:19
    什么是RMIRMI:远程方法调用(Remote Method Invocation)。如何建立RMI服务?建立服务端:Eclips新建Java Project,自定义名称,例如笔者项目名称:rmi-server。第1步. 首先建立两个基本的请求对象与响应对象,分别...

    什么是RMI?

    RMI:远程方法调用(Remote Method Invocation)。

    如何建立RMI服务?

    建立服务端:

    Eclips新建Java Project,自定义名称,例如笔者项目名称:rmi-server。

    第1步. 首先建立两个基本的请求对象与响应对象,分别为:BaseIn.java和BaseOut.java。

    BaseIn.java

    package api;

    import java.io.Serializable;

    /**

    *

    * 基本入参对象基类

    *

    */

    public class BaseIn implements Serializable {

    private static final long serialVersionUID = 1L;

    // 入参对象

    private Object params;

    // 调用类型

    private String invokeType;

    public BaseIn() {

    }

    public BaseIn(Object params, String invokeType) {

    super();

    this.params = params;

    this.invokeType = invokeType;

    }

    public Object getParams() {

    return params;

    }

    public void setParams(Object params) {

    this.params = params;

    }

    public String getInvokeType() {

    return invokeType;

    }

    public void setInvokeType(String invokeType) {

    this.invokeType = invokeType;

    }

    }

    BaseOut.java

    package api;

    import java.io.Serializable;

    /**

    *

    * 基本返回对象基类

    *

    */

    public class BaseOut implements Serializable {

    private static final long serialVersionUID = 1L;

    // 调用类型

    private String invokeType;

    // 交易状态

    private boolean status;

    // 业务消息

    private String msg;

    public BaseOut() {

    }

    public BaseOut(String invokeType, boolean status, String msg) {

    super();

    this.invokeType = invokeType;

    this.status = status;

    this.msg = msg;

    }

    public String getInvokeType() {

    return invokeType;

    }

    public void setInvokeType(String invokeType) {

    this.invokeType = invokeType;

    }

    public boolean isStatus() {

    return status;

    }

    public void setStatus(boolean status) {

    this.status = status;

    }

    public String getMsg() {

    return msg;

    }

    public void setMsg(String msg) {

    this.msg = msg;

    }

    }

    第2步. 然后定义一个Rmi请求的数据解析器接口与实现,分别为:IRmiApi.java和RmiApiImpl.java。

    IRmiApi.java 继承 java.rmi.Remote

    package api;

    import java.rmi.Remote;

    import java.rmi.RemoteException;

    /**

    *

    * RMI服务功能接口定义

    *

    */

    public interface IRmiApi extends Remote {

    /**

    * 方法处理响应器

    *

    * @param baseIn

    * @return

    * @throws RemoteException

    */

    T handler(BaseIn baseIn) throws RemoteException;

    }

    RmiApiImpl.java 继承 java.rmi.server.UnicastRemoteObject 并且要有构造方法

    package api;

    import java.rmi.RemoteException;

    import java.rmi.server.UnicastRemoteObject;

    public class RmiApiImpl extends UnicastRemoteObject implements IRmiApi {

    private static final long serialVersionUID = -1L;

    protected RmiApiImpl() throws RemoteException {

    super();

    }

    @SuppressWarnings("unchecked")

    @Override

    public T handler(BaseIn baseIn) throws RemoteException {

    // 定义响应对象

    T response = null;

    // 处理NullPoint

    if (baseIn == null) {

    return response;

    }

    System.out.println("接收到请求:" + baseIn.getInvokeType());

    // 具体处理流程

    if ("EXIT".equals(baseIn.getInvokeType())) {

    System.out.println("接收到服务退出指令...");

    System.out.println("服务停止成功!!!");

    System.exit(0);

    } else if ("getMyInfo".equals(baseIn.getInvokeType())) {

    response = (T) new BaseOut(baseIn.getInvokeType(), true,

    "获取我的消息-交易成功");

    } else {

    System.out.println("未知请求【" + baseIn.getInvokeType() + "】");

    }

    System.out.println("请求【" + baseIn.getInvokeType() + "】结束!");

    return response;

    }

    }

    第3步. 以上即完成了整体结构的实现,现在编写RMI服务启动入口(StartRmi.java)。

    StartRmi.java 启动服务入口

    package api;

    import java.net.MalformedURLException;

    import java.rmi.AlreadyBoundException;

    import java.rmi.Naming;

    import java.rmi.RemoteException;

    import java.rmi.registry.LocateRegistry;

    public class StartRmi {

    public static void main(String[] args) {

    try {

    System.out.println("RMI服务启动中...");

    // 实例化服务解析类

    IRmiApi api = new RmiApiImpl();

    // 注册端口

    LocateRegistry.createRegistry(9090);

    // 服务地址: rmi://ip:port/serverName

    String url = "rmi://127.0.0.1:9090/rmi";

    // 绑定服务解析器

    Naming.bind(url, api);

    System.out.println("启动完毕:" + url);

    } catch (RemoteException e) {

    e.printStackTrace();

    } catch (MalformedURLException | AlreadyBoundException e) {

    e.printStackTrace();

    }

    }

    }

    现在即可启动查看效果:

    控制台输出:

    RMI服务启动中...

    启动完毕:rmi://127.0.0.1:9090/rmi

    第4步. 启动完毕,已经完成大部分实现。但是怎么停止呢?编写停止功能(StopRmi.java)

    StopRmi.java

    package api;

    import java.net.MalformedURLException;

    import java.rmi.Naming;

    import java.rmi.NotBoundException;

    import java.rmi.RemoteException;

    import java.rmi.UnmarshalException;

    public class StopRmi {

    public static void main(String[] args) {

    String url = "rmi://127.0.0.1:9090/rmi";

    IRmiApi api;

    try {

    api = (IRmiApi) Naming.lookup(url);

    api.handler(new BaseIn(null, "EXIT"));

    } catch (UnmarshalException e) {

    String errMsg = e.getMessage();

    if (errMsg != null && errMsg.indexOf("Connection reset") != -1) {

    System.out.println("停止RMI服务成功!!!");

    } else {

    e.printStackTrace();

    }

    } catch (MalformedURLException | RemoteException | NotBoundException e) {

    e.printStackTrace();

    }

    }

    }

    运行测试:

    控制台输出:

    [Console StopRmi ]:

    停止RMI服务成功!!!

    [Console StartRmi]:

    RMI服务启动中...

    启动完毕:rmi://127.0.0.1:9090/rmi

    接收到请求:EXIT

    接收到服务退出指令...

    服务停止成功!!!

    到此,整个RMI服务端测试完毕!

    如何建立客户

    建立客户端:

    Eclips新建Java Project,自定义名称,例如笔者项目名称:rmi-client。

    第1步. 复制server端 BaseIn.java 和 BaseOut.java,并且保证包路径一致!!!

    - rmi-client

    - src

    - api

    * BaseIn.java

    * BaseOut.java

    第2步. 复制server端IRmiApi.java,并且保证包路径一致!!!

    - rmi-client

    - src

    - api

    * BaseIn.java

    * BaseOut.java

    * IRmiApi.java

    第3步. 建立请求发送器。

    ApiClient.java

    package app;

    import java.rmi.Naming;

    import api.BaseIn;

    import api.BaseOut;

    import api.IRmiApi;

    public class ApiClient {

    private static final String DEFAUTL_SERVER_URL = "rmi://127.0.0.1:9090/rmi";

    private static IRmiApi server = null;

    private ApiClient() {

    }

    private static void connet() throws Exception {

    if (server == null) {

    server = (IRmiApi) Naming.lookup(DEFAUTL_SERVER_URL);

    }

    }

    /**

    * 请求器

    *

    * @param baseIn

    * @return

    */

    public static T sendRequest(BaseIn baseIn) {

    try {

    connet();

    return server.handler(baseIn);

    } catch (Exception e) {

    String errMsg = e.getMessage();

    if (errMsg != null && errMsg.indexOf("Connection reset") != -1) {

    System.out.println("停止RMI服务成功!!!");

    } else {

    e.printStackTrace();

    }

    }

    return null;

    }

    }

    测试Test.java

    package app;

    import api.BaseIn;

    import api.BaseOut;

    public class Test {

    public static void main(String[] args) {

    // 调用业务服务

    BaseOut result = ApiClient.sendRequest(new BaseIn(null, "getMyInfo"));

    System.out.println(result);

    // 停止服务

    BaseOut off = ApiClient.sendRequest(new BaseIn(null, "EXIT"));

    System.out.println(off);

    }

    }

    重写BaseOut.java toString 方便打印:

    @Override

    public String toString() {

    return "BaseOut [invokeType=" + invokeType + ", status=" + status

    + ", msg=" + msg + "]";

    }

    控制台输出

    [Console rmi-client ]:

    BaseOut [invokeType=getMyInfo, status=true, msg=获取我的消息-交易成功]

    停止RMI服务成功!!!

    null

    [Console rmi-server]:

    RMI服务启动中...

    启动完毕:rmi://127.0.0.1:9090/rmi

    接收到请求:getMyInfo

    请求【getMyInfo】结束!

    接收到请求:EXIT

    接收到服务退出指令...

    服务停止成功!!!

    至此,RMI服务搭建完成!!!

    拓展练习

    运行jar包调用服务:

    服务端:rmi-server.jar

    获取地址:http://ovt5bckd8.bkt.clouddn.com/rmi-server.jar

    客户端:rmi-client.jar

    获取地址:http://ovt5bckd8.bkt.clouddn.com/rmi-client.jar

    运行示例:

    [rmi-server.jar]

    D:\>java -jar rmi-server.jar

    RMI服务启动中...

    启动完毕:rmi://127.0.0.1:9090/rmi

    接收到请求:getMyInfo

    请求【getMyInfo】结束!

    接收到请求:EXIT

    接收到服务退出指令...

    服务停止成功!!!

    D:\>

    [rmi-client.jar]

    D:\>java -jar rmi-client.jar

    BaseOut [invokeType=getMyInfo, status=true, msg=获取我的消息-交易成功]

    停止RMI服务成功!!!

    null

    D:\>

    展开全文
  • RMI实现RPC

    2021-02-03 09:34:27
    目录一、RMI简介二、执行流程三、API介绍四、代码实现1. 服务端(提供服务)2. 客户端(使用服务) 一、RMI简介 RMI(Remote Method Invocation) 远程方法调用。 RMI是从JDK1.2推出的功能,它可以实现在一个Java应用...

    一、RMI简介

    • RMI(Remote Method Invocation) 远程方法调用。
    • RMI是从JDK1.2推出的功能,它可以实现在一个Java应用中可以像调用本地方法一样调用另一个服务器中Java应用(JVM)中的内容。
    • RMI 是Java语言的远程调用,无法实现跨语言。

    二、执行流程

    在这里插入图片描述

    • Registry(注册表)是放置所有服务器对象的命名空间。 每次服务端创建一个对象时,它都会使用bind()或rebind()方法注册该对象。 这些是使用称为绑定名称的唯一名称注册的。

    • 要调用远程对象,客户端需要该对象的引用。即通过服务端绑定的名称从注册表中获取对象(lookup()方法)。

    三、API介绍

    • Remote​java.rmi.Remote
      定义了此接口为远程调用接口。如果接口被外部调用,需要继承此接口。

      public interface Remote{}
      
    • RemoteExceptionjava.rmi.RemoteException
      继承了Remote接口的接口中,如果方法是允许被远程调用的,需要抛出此异常。

    • UnicastRemoteObjectjava.rmi.server.UnicastRemoteObject
      此类实现了Remote接口和Serializable接口。
      自定义接口实现类除了实现自定义接口还需要继承此类。

    • LocateRegistryjava.rmi.registry.LocateRegistry
      可以通过LocateRegistry在本机上创建Registry,通过特定的端口就可以访问这个Registry。

    • Namingjava.rmi.Naming
      Naming定义了发布内容可访问RMI名称。也是通过Naming获取到指定的远程方法。

    四、代码实现

    1. 服务端(提供服务)

    新建一个Maven项目:
    在这里插入图片描述

    创建Service接口,接口要继承Remote接口,方法要抛出RemoteException异常。

    package com.veeja.service;
    
    import java.rmi.Remote;
    import java.rmi.RemoteException;
    
    /**
     * @Author veeja
     * 2021/2/3 9:58
     */
    public interface DemoService extends Remote {
    
        String demo(String param) throws RemoteException;
    
    }
    

    Service实现类:

    package com.veeja.service.impl;
    
    import com.veeja.service.DemoService;
    
    import java.rmi.RemoteException;
    import java.rmi.server.UnicastRemoteObject;
    
    /**
     * 
     * 继承 UnicastRemoteObject,
     * 实现 DemoService
     * 
     * @Author veeja
     * 2021/2/3 10:02
     */
    public class DemoServiceImpl extends UnicastRemoteObject implements DemoService {
    
        /**
         * 将构造方法变为public,就不会报错了
         */
        public DemoServiceImpl() throws RemoteException {
    
        }
    
        /**
         * 方法的实现,很简单, 将传进来的字符串+abc返回
         *
         * @param param
         * @return
         * @throws RemoteException
         */
        @Override
        public String demo(String param) throws RemoteException {
            return param + "abc";
        }
    }
    

    Server:

    package com.veeja;
    
    import com.veeja.service.DemoService;
    import com.veeja.service.impl.DemoServiceImpl;
    
    import java.net.MalformedURLException;
    import java.rmi.AlreadyBoundException;
    import java.rmi.Naming;
    import java.rmi.RemoteException;
    import java.rmi.registry.LocateRegistry;
    
    /**
     * @Author veeja
     * 2021/2/3 10:21
     */
    public class DemoServer {
    
        public static void main(String[] args) {
            try {
                // 创建接口实例
                DemoService demoService = new DemoServiceImpl();
                // 创建注册变
                LocateRegistry.createRegistry(8989);
                // 绑定服务
                Naming.bind("rmi://localhost:8989/demoService", demoService);
                System.out.println("服务器已启动...");
            } catch (RemoteException e) {
                e.printStackTrace();
            } catch (AlreadyBoundException e) {
                e.printStackTrace();
            } catch (MalformedURLException e) {
                e.printStackTrace();
            }
        }
    }
    
    

    然后我们运行一下上面的main方法:
    在这里插入图片描述

    2. 客户端(使用服务)

    新建一个Maven项目:
    在这里插入图片描述
    引入DemoService接口:

    package com.veeja.service;
    
    import java.rmi.Remote;
    import java.rmi.RemoteException;
    
    /**
     * @Author veeja
     * 2021/2/3 9:58
     */
    public interface DemoService extends Remote {
    
        String demo(String param) throws RemoteException;
    
    }
    
    

    调用远程方法:

    package com.veeja;
    
    import com.veeja.service.DemoService;
    
    import java.net.MalformedURLException;
    import java.rmi.Naming;
    import java.rmi.NotBoundException;
    import java.rmi.RemoteException;
    
    /**
     * @Author veeja
     * 2021/2/3 10:44
     */
    public class ClientDemo {
        public static void main(String[] args) {
            try {
                DemoService demoService = (DemoService) Naming.lookup("rmi://localhost:8989/demoService");
                String result = demoService.demo("aaa");
                System.out.println(result);
            } catch (NotBoundException e) {
                e.printStackTrace();
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }
    

    执行结果:

    aaaabc
    
    展开全文
  • RMI服务器与RMI注册表

    2021-07-17 00:33:21
    On Oracle's FAQ page about Java RMI, it says:While the Java Remote Method Invocation (Java RMI) server cantheoretically be on any host, it is usually the same host as that onwhich the registry is runn...
  • JavaRMI应用

    2021-02-28 08:09:29
    JavaRMI应用作者:未知文章来源:www.jspcn.net发布日期:2005年01... 其 中,RMI 最 典 型 地 展 现 了Java 平 台 强 大 的 分 布 计 算 能 力。 本 文 用 一 个 简 单 的 例 子 说 明RMI 给 分 布 计 算 带 来 的 ...
  • 一 .RMI概述RMI(Remote Method Invocation)RMI是分布式对象软件包,它简化了在多台计算机上的JAVA应用之间的通信。必须在jdk1.1以上RMI用到的类java.rmi.Remote 所有可以被远程调用的对象都必须实现该接口java.rmi....
  • rmirmi是什么

    2021-06-13 12:45:08
    rmirmi是什么rmi时间:2021-05-30阅读:()RPC与RMI的区别RMI和RPC之间最主要的区别在于方法是如何别调用的。在RMI中,远程接口使每个远程方法都具有方法签名。如果一个方法在服务器上执行,但是没有相匹配的签名被添加...
  • RMI执行过程

    2021-07-20 16:44:45
    RMI 是Java编程语言里一种用于实现远程过程调用的应用程序编程接口。它使客户机上的运行的程序可以调用远程服务器上的对象。远程方法调用特性使Java编程人员能够在网络环境中分布操作。RMI全部的宗旨就是尽可能地...
  • Java安全初探-RMI

    2021-02-27 16:27:06
    Java RMI初识Java RMI 定义Java RMI(Java Remote Method Invocation),即Java远程方法调用。是Java编程语言里,一种用于实现远程过程调用的应用程序编程接口。 Java RMI 使用 JRMP(Java Remote Message Protocol,...
  • 1. RMI远程调用 java RMI (Java Remote Method Invocation)即远程方法调用,是分布式编程中的一种编程思想,java jdk1.2就开始支持RMI,通过RMI可以实现一个虚拟机中的对象调用另一个虚拟机上中的对象的方法,并且...
  • Java安全之RMI反序列化

    2021-01-13 19:57:46
    Java安全之RMI反序列化0x00 前言在分析Fastjson漏洞前,需要了解RMI机制和JNDI注入等知识点,所以本篇文来分析一下RMI机制。在Java里面简单来说使用Java调用远程Java程序使用的就是RMI,调用C的程序调用的是JNI,...
  • Java RMI 使用

    2021-03-14 20:46:45
    service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmilocalhost:8082RMI方法实现https://blog.csdn.net/MAOZEXIJR/article/details/78841094JMX学习笔记(四) JMX RMIhttps://blog.csdn.net/java_huashan/article/...
  • 19-Feb-2019 10:04:43.069 警告 [RMI TCP Connection(4)-127.0.0.1] org.apache.tomcat.util.descriptor.web.WebXml.setVersion Unknown version string [4.0]. Default version will be used.19-Feb-2019 10:04:43....
  • 远程通信协议RMI原理

    2021-01-22 17:12:10
    在分布式服务框架中,一个最基础的问题就是远程服务是怎么通讯的,在Java领域中有很多可实现远程通讯的技术,例如:RMI、MINA、ESB、Burlap、Hessian、SOAP、EJB和JMS 等,这些名词之间到底是些什么关系呢,它们背后...
  • Eclipse下开发RMI

    2021-03-08 21:59:02
    什么是RMI远程方法调用是一种计算机之间对象互相调用对方函数,启动对方进程的一种机制,使用这种机制,某一台计算机上的对象在调用另外一台计算机上的方法时,使用的程序语法规则和在本地机上对象间的方法调用的...
  • 深入了解javaRMI

    2021-02-13 01:22:55
    前言:JavaRMI的使用并不麻烦,让我真正感兴趣的是stubs和skeletons,更让我感兴趣的是RMI框架如何让客户端感觉像在调用本地方法一样去使用远程对象的方法。(阅读本文建议先了解rmi的基本用法,可参考附件demo)本篇...
  • RMI技术例子下面以一个例子说明怎么使用RMI技术。这个例子演示了怎样将一个文件上传到服务器和怎样将一个文件从服务器上下载下来。使用RMI技术共有6个步骤要走: (1)定义和实现远端接口中的参数 (2) 定义和实现远端...
  • RMI : Remote Method Invocation,远程方法调用 RPC : Remote Procedure Call Protocol, 远程过程调用协议 ESB : Enterprise Service Bus, 企业服务总线 SOA : Service-Oriented Architecture, 面向服务的架构 1. ...
  • 也是从接触fastjson的时候才接触RMI这个东西。也经常与JNDi搞混。这篇文章先分析RMI的底层,等研究过了再加上。 什么是RMI RMI即远程方法调用,通俗的来说就是客户端可以调用服务端的方法。和RPC差不多,RMI是java...
  • RMI开发中的codebase

    2021-04-15 16:08:14
    codebase问题其实是一个怎样从网络上下载类的问题,我想不只是在Jini和RMI程序开发中要用到。只要需要从网络上下载类,就要涉及到codebase问题。例如applet等。但是因为我对applet程序不是很熟悉,所以我就只谈Jini...
  • JNDI(Java Naming and Directory Interface,Java命名和目录接口)是一组在Java应用中访问命名和...可参考RMI注册表,例如在RMI中通过rmi://10.100.0.1:10086/userRmiServices来映射RMI注册表中的userRmiServices远
  • Java RMI 使用例子

    2021-02-28 08:09:10
    1.创建协议接口(UserService)/****/packagecom.junge.demo.rmi.protocol.service;importjava.io.Serializable;importjava.rmi.Remote;importjava.rmi.RemoteException;importcom.junge.demo.rmi.protocol.model.User...
  • RMI-spring RMI固定随机数据端口 RMI在启动时,会启动两个端口一个是应用端口,就是你的应用指定的端口,另一个是RMI随机分配的数据传输端口。如果LINUX开通的防火墙,必须同时开放这两个端口,才能正常访问服务。...
  • RMI反序列化漏洞分析

    2020-12-23 03:38:41
    原创:Xman21合天智汇一、RMI简介首先看一下RMI在wikipedia上的描述:Java远程方法调用,即Java RMI(Java Remote Method Invocation)是Java编程语言里,一种用于实现远程过程调用的应用程序编程接口。它使客户机上...
  • RMI2. JRMP3. JNDI4.实现的效果5. 利用方式终结参考文章 1. RMI RMI是一种行为,一种跨越主机进行远程方法调用的行为。 通俗点理解当前主机的一个java文件调用了远程某个主机上的某个java文件中的某个方法,这种...
  • at sun.rmi.transport.tcp.TCPTransport.exportObject(Unknown Source) at sun.rmi.transport.tcp.TCPEndpoint.exportObject(Unknown Source) at sun.rmi.transport.LiveRef.exportObject(Unknown Source) at sun....
  • Java RMI应用程序

    2021-02-28 08:08:48
    要编写Java的RMI应用程序,必须遵循以下步骤:定义远程接口开发实现类(远程对象)开发服务器程序开发客户端程序编译应用程序执行应用程序定义远程接口远程接口提供特定远程对象的所有方法的描述。客户端可与此远程...
  • 2.需具备以下知识:javase servelt web rmi spring maven一、关于RMI请参考另外一篇文章:https://www.cnblogs.com/liandy001/p/11182055.html二、Spring的远程技术远程方法调用(RMI):通过使用RmiProxyFactoryB...
  • JNDI注入(RMI攻击实现和LDAP攻击实现)

    千次阅读 2021-12-12 15:29:32
    } } 服务端的代码是这样的,意思是,注册一个rmi服务,端口为1099,自己的实现类为url的部分,最后去绑定(bind)这个服务为一个名字 下面还需要一段执行命令的代码,挂载在web页面上让server端去请求 package ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 137,837
精华内容 55,134
关键字:

rmi

友情链接: 1718501021.rar