从零开始手写一个RPC-01

从零开始手写一个RPC-01

从零开始手写一个RPC,让每个人都能看懂。

第一次手写RPC,一定会有理解的偏差与代码上的不完善,但就是这样,与新手对同样问题的疑惑,才能更好理解这样写为什么会出错,那样为什么是对的。

学习建议:一定要手写代码,边写边想。

RPC的概念

RPC是指远程过程调用,举个例子,两台服务器A,B.一个应用在A服务器上想要调用B服务器的一个应用获取信息,由于不在同一个内存空间,不能直接通信,因为不知道对方的地址和端口号,在同一个服务器的两个应用也无法直接通信,因为他们不知道对方的端口号,因此需要通过网络来表达调用的语义和传达调用的数据。(理解网络的五层模型就会好理解很多)

贴一个网上找的图,就更好理解了。

在这里插入图片描述

01.一个简单明了的RPC调用

所需知识:

  • Java基础知识
  • Java socket 编程
  • 开发工具使用IDEA,项目使用Maven搭建,引入lombok包。

本节问题:

如何完成一个简单的RPC

一个简单地RPC调用就是客户端调用服务端的一个方法,服务端执行这个方法并返回数据给客户端。

过程:

1.首先创建一个Student类,在客户端和服务端都应该存在,客户端需要得到这个Student对象数据,服务端需要操作Student这个对象。

@Data//get(),set()方法
@AllArgsConstructor//有参构造
@NoArgsConstructor//无参构造
@Builder//链式编程
public class Student implements Serializable {
    private Integer id;
    private String name;
    private boolean sex;
}

2.定义客户端需要调用的,服务端需要提供的接口

public interface StudentService {
    Student getStudentByStudentId(Integer id);
}

3.服务端实现StudentService的功能

public class StudentServiceImpl implements StudentService {
    @Override
    public Student getStudentByStudentId(Integer id) {
        //我们在代码中生成数据
        System.out.println("客户端查询了"+id+"的学生");
        Random random = new Random();
        Student student = Student.builder()
                .id(random.nextInt())
                .name("zahngsan")
                .sex(random.nextBoolean())
                .build();
        return student;
    }
}

4.客户端建立Socket连接,传输Id给服务端,得到返回的Student对象

public class RPCClient {
    public static void main(String[] args) {
        try {
            // 建立Socket连接
            Socket socket = new Socket("127.0.0.1", 8890);
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
            ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
            // 传给服务器id
            objectOutputStream.writeInt(new Random().nextInt());
            objectOutputStream.flush();
            // 服务器查询数据,返回对应的对象
            Student student  = (Student) objectInputStream.readObject();
            System.out.println("服务端返回的student:"+student);

        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
            System.out.println("客户端启动失败");
        }
    }
}

5.服务端以BIO的方式监听Socket,如有数据,调用对应服务的实现类执行任务,将结果返回给客户端

public class RPCServer {
    public static void main(String[] args) {
        StudentServiceImpl studentService = new StudentServiceImpl();
        try {
            ServerSocket serverSocket = new ServerSocket(8890);
            System.out.println("服务端启动了");
            while (true) {
                Socket socket = serverSocket.accept();
                new Thread(() -> {
                    try {
                        ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
                        ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                        Integer id = ois.readInt();
                        Student student = studentService.getStudentByStudentId(id);
                        oos.writeObject(student);
                        oos.flush();
                    } catch (IOException e) {
                        e.printStackTrace();
                        System.out.println("从IO中读取数据错误");
                    }
                }).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("服务器启动失败");
        }
    }
}
总结:

这个例子以不到百行的代码,实现了客户端与服务端的一个远程过程调用,非常适合上手,当然它是及其不完善的,甚至连消息格式都没有统一,我们将在接下来的版本更新中逐渐完善它。

总结:

这个例子以不到百行的代码,实现了客户端与服务端的一个远程过程调用,非常适合上手,当然它是及其不完善的,甚至连消息格式都没有统一,我们将在接下来的版本更新中逐渐完善它。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值