0x01、什么是RMI

RMI(Remote Method Invocation)即Java远程方法调用,RMI用于构建分布式应用程序,RMI实现了Java程序之间跨JVM的远程通信。顾名思义,远程方法调用:客户端比如说是在手机,然后服务端是在电脑;同时都有java环境,然后我要在手机端调用服务端那边的某个方法,这就是,远程方法调用;

使用RMI的时候,客户端对远程方法的调用就跟对同一个Java虚拟机(也就是本地)上的方法调用是一样的。一般调用和RMI调用有一点不同,虽然对客户端来说看起来像是本地的,但是客户端的stub会通过网络发出调用,所以会抛出异常;其中还是会涉及到Socket和串流的问题,一开始是本地调用,然后就代理(stub)会转成远程,中间的信息是如何从Java虚拟机发送到另外一台Java虚拟机要看客户端和服务端的辅助设施对象所用的协议而定;使用RMI的时候,需要选择协议:JRMP或IIOP协议;JRMP是RMI的原生的协议,也就是默认JRMP协议。而IIOP是为了CORBA而产生的~~~

远程方法调用,具体怎么实现呢?远程服务器提供具体的类和方法,本地会通过某种方式获得远程类的一个代理,然后通过这个代理调用远程对象的方法,方法的参数是通过序列化与反序列化的方式传递的,所以,

1. 只要服务端的对象提供了一个方法,这个方法接收的是一个Object类型的参数

2. 且远程服务器的classpath中存在可利用pop链,那么我们就可以通过在客户端调用这个方法,并传递一个精心构造的对象的方式来攻击rmi服务。

某种方式获得远程对象的代理,那么具体是怎么的实现机制呢?RMI模式中除了有Client与Server,还借助了一个Registry(注册中心)。

Server Registry Client
提供具体的远程对象 一个注册表,存放着远程对象的位置(ip、端口、标识符) 远程对象的使用者

其中Server与Registry可以在同一服务器上实现,也可以布置在不同服务器上,现在一个完整的RMI流程可以大概描述为:

  1. Registry先启动,并监听一个端口,一般为1099
  2. Server向Registry注册远程对象
  3. Client从Registry获得远程对象的代理(这个代理知道远程对象的在网络中的具体位置:ip、端口、标识符),然后Client通过这个代理调用远程方法,Server也是有一个代理的,Server端的代理会收到Client端的调用的方法、参数等,然后代理执行对应方法,并将结果通过网络返回给Client。

两图胜千言:

其实跟上图都类似

0x02、RMI的框架与解析

RMI调用远程方法的大致如下:

  1. RMI客户端在调用远程方法时会先创建Stub(sun.rmi.registry.RegistryImpl_Stub)
  2. Stub会将Remote对象传递给远程引用层(java.rmi.server.RemoteRef)并创建java.rmi.server.RemoteCall(远程调用)对象。
  3. RemoteCall序列化RMI服务名称Remote对象。
  4. RMI客户端远程引用层传输RemoteCall序列化后的请求信息通过Socket连接的方式传输到RMI服务端远程引用层
  5. RMI服务端远程引用层(sun.rmi.server.UnicastServerRef)收到请求会请求传递给Skeleton(sun.rmi.registry.RegistryImpl_Skel#dispatch)
  6. Skeleton调用RemoteCall反序列化RMI客户端传过来的序列化。
  7. Skeleton处理客户端请求:bindlistlookuprebindunbind,如果是lookup则查找RMI服务名绑定的接口对象,序列化该对象并通过RemoteCall传输到客户端。
  8. RMI客户端反序列化服务端结果,获取远程对象的引用。

而更通俗点来说:

  1. 客户端请求代理
  2. Stub编码处理消息
  3. 消息传输
  4. 到达管家skeleton并处理信息
  5. 管家skeleton把信息提交给server
  6. server接收到请求
  7. server把请求的结果给管家
  8. 管家skeleton把结果转交给stub
  9. 代理Stub对结果解码
  10. Stub把解码的结果交给client。

    更容易的通俗易懂~~~

1、⾸先客户端连接Registry,并在其中寻找Name是Hello的对象

2、这个对应数据流中的Call消息;

3、然后Registry返回⼀个序列化的数据,这个就是找到的Name=Hello的对象,这个对应数据流中的ReturnData消息;

4、客户端反序列化该对象,发现该对象是⼀个远程对象,地址在 169.254.20.76:39098 ,这边可能会有疑问,这里面没有,怎么会知道端口号啥的



可以看出,其实端口是跟在远程地址的后面,只不过是16进制的,需要切换一下

5、于是再与这个地址建⽴TCP连接;在这个新的连接中,才执⾏真正远程⽅法调⽤,也就是 hello()

0x03、rmi测试代码

RMIDemo.java

import java.rmi.Remote;
import java.rmi.RemoteException; public interface rmiDemo extends Remote {
public String hello() throws RemoteException;
}

RMIDemoImpl.java

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject; public class RMIDemoImpl extends UnicastRemoteObject implements rmiDemo{ protected RMIDemoImpl() throws RemoteException {
System.out.println("构造方法");
} public String hello() throws RemoteException {
System.out.println("hello方法被调用");
return "hello,world";
}
}

RMIServer.java

import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry; public class RMIServer {
public static void main(String[] args) throws RemoteException {
rmiDemo hello = new RemoteHelloWorld();//创建远程对象
Registry registry = LocateRegistry.createRegistry(1099);//创建注册表
registry.rebind("hello",hello);//将远程对象注册到注册表里面,并且设置值为hello }
}

RMIClient.java

import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry; public class RMIServer {
public static void main(String[] args) throws RemoteException {
rmiDemo hello = new RemoteHelloWorld();//创建远程对象
Registry registry = LocateRegistry.createRegistry(1099);//创建注册表
registry.rebind("hello",hello);//将远程对象注册到注册表里面,并且设置值为hello }
}

网上参考学习,如若有错,请各位大佬指出

RMI之由浅入深(一)的更多相关文章

  1. RabbitMQ由浅入深入门全总结(一)

    写在最前面 距离上一次发文章已经很久了,其实这段时间一直也没有停笔,只不过在忙着找工作还有学校结课的事情,重新弄了一下博客,后面也会陆陆续续会把文章最近更新出来~ 这篇文章有点长,就分了两篇Q PS: ...

  2. PropertyGrid控件由浅入深(二):基础用法

    目录 PropertyGrid控件由浅入深(一):文章大纲 PropertyGrid控件由浅入深(二):基础用法 控件的外观构成 控件的外观构成如下图所示: PropertyGrid控件包含以下几个要 ...

  3. PropertyGrid控件由浅入深(一):文章大纲

    Winform中PropertyGrid控件是一个非常好用的对象属性编辑工具,对于Key-Value形式的数据的处理也是非常的好用. 因为Property控件设计良好,在很小的空间内可以展示很多的内容 ...

  4. tomcat RMI 停不掉

    项目采用jfinal框架,做了一个RMI的服务,对其它程序提供服务.实现上,写了一个RmiPlugin package com.wisdombud.cloudtalk.plugin; import j ...

  5. Exception thrown by the agent : java.rmi.server.ExportException: Port already in use

    今天有个应用一直起不来,感觉配置都对啊,奇了怪了.看日志发现如下: STATUS | wrapper | 2017/01/04 08:09:31 | Launching a JVM...INFO | ...

  6. RMI(远程接口调用)

    1. RMI的原理: RMI系统结构,在客户端和服务器端都有几层结构. 方法调用从客户对象经占位程序(Stub).远程引用层(Remote Reference Layer)和传输层(Transport ...

  7. Java RMI之HelloWorld篇

    Java RMI 指的是远程方法调用 (Remote Method Invocation).它是一种机制,能够让在某个 Java 虚拟机上的对象调用另一个 Java 虚拟机中的对象上的方法.可以用此方 ...

  8. 【转】能否用讲个故事的方式,由浅入深,通俗易懂地解释一下什么是天使投资,VC,PE.

    能否用讲个故事的方式,由浅入深,通俗易懂地解释一下什么是天使投资,VC,PE 今天在知乎上看到一篇文章,觉得值得一转的,Here. 我给楼主讲个完整点的故事吧.长文慎点,前方高能,自备避雷针.18岁以 ...

  9. Spring远程调用技术<1>-RMI

    在java中,我们有多种可以使用的远程调用技术 1.远程方法调用(remote method invocation, RMI)  适用场景:不考虑网络限制时(例如防火墙),访问/发布基于java的服务 ...

随机推荐

  1. 【面试题】GC Root都有哪些?

    那天去面试,面试官问我JVM垃圾回收,我是有备而来,上来就是一个可达性分析算法,然后就是一个复制算法,标记-清理,标记-整理,以及几个常见的垃圾回收器 详情见:https://www.cnblogs. ...

  2. 数据结构——创建链表或树节点的小trick(哑结点)

    一般创建链表时,我们可以创建一个哑结点,来保存头部  * struct ListNode {  *     int val;  *     ListNode *next;  *     ListNod ...

  3. WPF页面刷新

    WPF页面刷新: 在WPF项目中,类的属性变了,但界面值没有变,且我们也没有对类的属性做PropertyChanged的set处理. 如何实现呢? 首先我们需要实现一个INotifyPropertyC ...

  4. ACM训练赛:第20次

    这次的题思维都很强,等之后的考试结束会集中精力重新训练一些思维题. A - A simple question CodeForces - 520B 思路: 直接看的话,很容易发现如果 \(n > ...

  5. asp.net在线人数限制

    1.网站启动初始化在线人数变量 Application["WebsiteCount"] = 0; 2.新的会话进来 只有在全新的会话进来的时候,该方法才会执行.可以过滤掉某些不需要 ...

  6. 如何更简单的使用Polly

    Polly 弹性瞬时错误处理库 Polly是一个C#实现的弹性瞬时错误处理库 它可以帮助我们做一些容错模式处理,比如: 超时与重试(Timeout and Retry) 熔断器(Circuit Bre ...

  7. python爬虫--用xpath爬豆瓣电影

    步骤 将目标网站下的页面抓取下来 将抓取下来的数据根据一定规则进行提取   具体流程 将目标网站下的页面抓取下来 1. 倒库 import requests 2.头信息(有时候可不写) headers ...

  8. db2常用操作

    1. db2建立远程节点编目及删除 db2 catalog tcpip node nodeName remote remoteIp server remotePort db2 list node di ...

  9. ssl证书---验证等级分类

    DV SSL证书(domain Validation SSL): 指只验证网站域名所有权的简易型SSL证书,此类证书仅能起到网站机密信息加密的作用,无法向用户证明网站的真实身份.所以,不推荐在电子商务 ...

  10. [日常摸鱼]poj2420 A Star not a Tree?

    题意:给定$n$个点,找一个点使得这个点到所有点的距离之和最小,求出这个最小距离 传说中的模拟退火- #include<cstdio> #include<ctime> #inc ...