分布式系统基础--通信框架RMI

文章最前: 我是Octopus,这个名字来源于我的中文名--章鱼;我热爱编程、热爱算法、热爱开源。所有源码在我的个人github ;这博客是记录我学习的点点滴滴,如果您对 Python、Java、AI、算法有兴趣,可以关注我的动态,一起学习,共同进步。

相关文章:

  1. 分布式系统基础--Http协议
  2. 分布式系统基础--序列化
  3. 分布式系统基础--通信框架RMI
  4. 分布式系统基础--TCP/IP协议

文章目录:

了解 Java RMI

Java RMI 代码实践

通信原理

实现自己的 RPC 框架


什么是 RPC
        RPC(Remote Procedure Call,远程过程调用),一般用来实现部署在不同机器上的系统之间的方法调用,使得程序能够像访问本地系统资源一样,通过网络传输去访问远端系统资源;对于客户端来说, 传输层使用什么协议,序列化、反序列化都是透明的。


了解 Java RMI


        RMI 全称是 remote method invocation – 远程方法调用,一种用于远程过程调用的应用程序编程接口,是纯 java 的网络分布式应用系统的核心解决方案之一。RMI 目前使用 Java 远程消息交换协议 JRMP(Java Remote  Messageing Protocol) 进行通信,由于 JRMP 是专为 Java对象制定的,是分布式应用系统的百分之百纯 java 解决方案,用 Java RMI 开发的应用系统可以部署在任何支持 JRE的平台上;缺点是,由于 JRMP是专门为 java对象指定的,因此 RMI 对于非 JAVA 语言开发的应用系统的支持不足,不能与非 JAVA 语言书写的对象进行通信。


Java RMI 代码实践

1.Student.java

package rmidemo;

import java.io.Serializable;

/**
 * @author zhangyu
 * @version V1.0
 * @ClassName: Student
 * @Description: student学生bean
 * @date 2019/1/15 10:13
 **/


public class Student implements Serializable {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

2.StudentService.java

package rmidemo;

import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.List;

/**
 * @author zhangyu
 * @version V1.0
 * @ClassName: StudentService
 * @Description: TOTO
 * @date 2019/1/15 10:15
 **/


public interface StudentService extends Remote {
    List<Student> getList() throws RemoteException;
}

3.StudentServiceImp.java

package rmidemo;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.List;

/**
 * @author zhangyu
 * @version V1.0
 * @ClassName: StudentServiceImpl
 * @Description: TOTO
 * @date 2019/1/15 10:16
 **/


public class StudentServiceImpl extends UnicastRemoteObject implements StudentService {


    protected StudentServiceImpl() throws RemoteException {
    }

    @Override
    public List<Student> getList() throws RemoteException {
        List<Student> list = new ArrayList<>();
        Student student = new Student();
        student.setName("张宇");
        student.setAge(18);
        Student student2 = new Student();
        student2.setName("张飞");
        student2.setAge(20);
        list.add(student);
        list.add(student2);
        return list;
    }
}

4.SetService.java

package rmidemo;

import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;

/**
 * @author zhangyu
 * @version V1.0
 * @ClassName: SetService
 * @Description: 开启服务的方法
 * @date 2019/1/15 10:23
 **/


public class SetService {
    public static void main(String[] args) {
        try {
            StudentService studentService = new StudentServiceImpl();
            LocateRegistry.createRegistry(8080); //定义端口号
            Naming.rebind("rmi://127.0.0.1:8080/StudentService", studentService);
            System.out.println("服务已经启动!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

5.SetService.java

package rmidemo;

import java.rmi.Naming;
import java.util.List;

/**
 * @author zhangyu
 * @version V1.0
 * @ClassName: GetService
 * @Description: 远程调用方法
 * @date 2019/1/15 10:27
 **/


public class GetService {
    public static void main(String[] args) {
        try {
            StudentService studentService = (StudentService) Naming.lookup("rmi://127.0.0.1:8080/StudentService");
            List<Student> list = studentService.getList();
            for (Student s : list) {
                System.out.println("姓名:" + s.getName() + ",年龄" + s.getAge());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

        远程对象必须实现 UnicastRemoteObject,这样才能保证客户端访问获得远程对象时,该远程对象会把自身的一个拷贝以 Socket 形式传输给客户端,客户端获得的拷贝称为“stub” , 而 服 务 器 端 本 身 已 经 存 在 的 远 程 对 象 成 为“skeleton”,此时客户端的 stub 是客户端的一个代理,用于与服务器端进行通信,而 skeleton 是服务端的一个代理,用于接收客户端的请求之后调用远程方法来响应客户端的请求。

                     

                                                                                                     调用图 

通信原理

         在 RMI Client 实施正式的 RMI 调用前,它必须通过 LocateRegistry 或者 Naming 方式到 RMI 注册表寻找要调用的 RMI 注册信息。找到 RMI 事务注册信息后,Client 会从 RMI 注册表获取这个 RMI Remote Service 的Stub 信息。这个过程成功后, RMI Client 才能开始正式的调用过程。另外要说明的是 RMI Client 正式调用过程,也不是由 RMIClient 直接访问 Remote Service,而是由客户端获取的Stub 作为 RMI Client 的代理访问 Remote Service 的代理Skeleton,如上图所示的顺序。也就是说真实的请求调用是在 Stub-Skeleton 之间进行的。Registry 并不参与具体的 Stub-Skeleton 的调用过程,只负责记录“哪个服务名”使用哪一个 Stub,并在 RemoteClient 询问它时将这个 Stub 拿给 Client(如果没有就会报错)。

                               
 

实现自己的 RPC 框架


     关于手动实现自己的rpc框架就是基于前面的序列化和反序列,socket通信为基础实现的;

代码位置:https://github.com/zhangyu345293721/rpc

参考博客:https://www.cnblogs.com/xt0810/p/3640167.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值