RMI之由浅入深(一)
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流程可以大概描述为:
- Registry先启动,并监听一个端口,一般为1099
- Server向Registry注册远程对象
- Client从Registry获得远程对象的代理(这个代理知道远程对象的在网络中的具体位置:ip、端口、标识符),然后Client通过这个代理调用远程方法,Server也是有一个代理的,Server端的代理会收到Client端的调用的方法、参数等,然后代理执行对应方法,并将结果通过网络返回给Client。
两图胜千言:
其实跟上图都类似
0x02、RMI的框架与解析
RMI调用远程方法的大致如下:
RMI客户端
在调用远程方法时会先创建Stub(sun.rmi.registry.RegistryImpl_Stub)
。Stub
会将Remote
对象传递给远程引用层(java.rmi.server.RemoteRef)
并创建java.rmi.server.RemoteCall(远程调用)
对象。RemoteCall
序列化RMI服务名称
、Remote
对象。RMI客户端
的远程引用层
传输RemoteCall
序列化后的请求信息通过Socket
连接的方式传输到RMI服务端
的远程引用层
。RMI服务端
的远程引用层(sun.rmi.server.UnicastServerRef)
收到请求会请求传递给Skeleton(sun.rmi.registry.RegistryImpl_Skel#dispatch)
。Skeleton
调用RemoteCall
反序列化RMI客户端
传过来的序列化。Skeleton
处理客户端请求:bind
、list
、lookup
、rebind
、unbind
,如果是lookup
则查找RMI服务名
绑定的接口对象,序列化该对象并通过RemoteCall
传输到客户端。RMI客户端
反序列化服务端结果,获取远程对象的引用。
而更通俗点来说:
- 客户端请求代理
- Stub编码处理消息
- 消息传输
- 到达管家skeleton并处理信息
- 管家skeleton把信息提交给server
- server接收到请求
- server把请求的结果给管家
- 管家skeleton把结果转交给stub
- 代理Stub对结果解码
- 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之由浅入深(一)的更多相关文章
- RabbitMQ由浅入深入门全总结(一)
写在最前面 距离上一次发文章已经很久了,其实这段时间一直也没有停笔,只不过在忙着找工作还有学校结课的事情,重新弄了一下博客,后面也会陆陆续续会把文章最近更新出来~ 这篇文章有点长,就分了两篇Q PS: ...
- PropertyGrid控件由浅入深(二):基础用法
目录 PropertyGrid控件由浅入深(一):文章大纲 PropertyGrid控件由浅入深(二):基础用法 控件的外观构成 控件的外观构成如下图所示: PropertyGrid控件包含以下几个要 ...
- PropertyGrid控件由浅入深(一):文章大纲
Winform中PropertyGrid控件是一个非常好用的对象属性编辑工具,对于Key-Value形式的数据的处理也是非常的好用. 因为Property控件设计良好,在很小的空间内可以展示很多的内容 ...
- tomcat RMI 停不掉
项目采用jfinal框架,做了一个RMI的服务,对其它程序提供服务.实现上,写了一个RmiPlugin package com.wisdombud.cloudtalk.plugin; import j ...
- 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 | ...
- RMI(远程接口调用)
1. RMI的原理: RMI系统结构,在客户端和服务器端都有几层结构. 方法调用从客户对象经占位程序(Stub).远程引用层(Remote Reference Layer)和传输层(Transport ...
- Java RMI之HelloWorld篇
Java RMI 指的是远程方法调用 (Remote Method Invocation).它是一种机制,能够让在某个 Java 虚拟机上的对象调用另一个 Java 虚拟机中的对象上的方法.可以用此方 ...
- 【转】能否用讲个故事的方式,由浅入深,通俗易懂地解释一下什么是天使投资,VC,PE.
能否用讲个故事的方式,由浅入深,通俗易懂地解释一下什么是天使投资,VC,PE 今天在知乎上看到一篇文章,觉得值得一转的,Here. 我给楼主讲个完整点的故事吧.长文慎点,前方高能,自备避雷针.18岁以 ...
- Spring远程调用技术<1>-RMI
在java中,我们有多种可以使用的远程调用技术 1.远程方法调用(remote method invocation, RMI) 适用场景:不考虑网络限制时(例如防火墙),访问/发布基于java的服务 ...
随机推荐
- PyQt(Python+Qt)学习随笔:Designer中的QDialogButtonBox的按钮改变缺省文字的方法
在Qt Designer中可以预先定义标准按钮,相关支持的标准按钮请见<PyQt(Python+Qt)学习随笔:Designer中的QDialogButtonBox的StandardButton ...
- 几句话说明 .NET MVC中ViewData, ViewBag和TempData的区别
ViewData和TempData是字典类型,赋值方式用字典方式, ViewData["myName"] ViewBag是动态类型,使用时直接添加属性赋值即可 ViewBag.my ...
- Oracle函数:trunc、round、ceil和floor
1.trunc函数 1).trunc(date) 格式:trunc(date,fmt) trunc用于截取时间,即便你指定不同的格式类型,返回的类型始终都是时间类型. 示例: with dates a ...
- (数据科学学习手札99)掌握pandas中的时序数据分组运算
本文示例代码及文件已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 我们在使用pandas分析处理时间序列数据 ...
- Scrum 冲刺第一天
一.团队信息 1.团队名称 挑战极限队 2.团队成员 张博愉(3118005074) 张润柏(3118005075) 郑堉涵(3118005077) 周伟建(3118005079) 林梓琦(31180 ...
- Java集合源码分析(八)——WeakHashMap
简介 WeakHashMap 继承于AbstractMap,实现了Map接口. 和HashMap一样,WeakHashMap 也是一个散列表,它存储的内容也是键值对(key-value)映射,而且键和 ...
- 三、Zookeeper简介
一.简介 zookeeper 主要使用场景:分布式系统的分布式协同服务.协同工作就是通过某种方式,让着节点的信息能够同步和共享,依赖于进程间的通信.通信方式有俩种. 通过网络进行信息共享 现实工作中, ...
- 零基础的Java小白如何准备初级开发的面试
对于各位Java程序员来说,只要能有实践的机会,哪怕工资再低,公司情况再一般,只要自己上心努力,就可能在短时间内快速提升,甚至在工作2年后进大厂都有希望,因为项目里真实的开发实践环境是平时学习不能模拟 ...
- scala&&spark学习参考文章
http://www.cnblogs.com/xing901022/p/5944297.html 牛逼
- Docker安装rocketmq踩坑指南
Docker 网络 Docker容器运行的时候有host.bridge.none三种网络可供配置. 默认是bridge,即桥接网络,以桥接模式连接到宿主机:host是宿主网络,即与宿主机共用网络:no ...