IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> 【手写RPC框架(三)】实现服务注册 -> 正文阅读

[网络协议]【手写RPC框架(三)】实现服务注册

一、实现简单服务注册功能

\quad\quad RPC框架一般由服务端,消费端,注册中心三部分组成。注册中心负责持久化服务名称,IP地址以及端口等。本次只实现简单的服务注册功能。
\quad\quad 本篇文章实现简单的注册中心,即注册中心中仅仅存放服务,没有存放地址、端口信息。而接口、实现类和序列化在前面两篇文章中已经实现,不再赘述。

1.1 服务端

1.1.1 发布rpc服务

  • 将端口信息和服务信息提交注册中心
public class RpcBootStrap {
    public static void main(String[] args) throws IOException {
        CalculatorService calculator=new CalculatorServiceImpl();
        RpcProvider.export(8081,calculator);
    }
}

1.2 注册中心

  • 服务端发布服务后,以列表形式在注册中心进行注册,只存放服务信息并传入服务地址
  • 根据服务地址,监听socket端口,是否收到客户端请求信息。
  • 若收到客户端请求,开启新的线程,首先检查注册中心中是否有客户端请求的服务,若无则返回没有服务。
  • 若有,则处理序列化后的请求信息(此时数据是通过网络发到服务端处理的),通过反射调用服务端相关服务方法,并返回服务信息处理结果。

1.2.1 实现rpc服务注册

public class RpcProvider {
    //负责存储服务列表
    private static List<Object> serviceList;

    //发布一个rpc服务
    public static void export(int port,Object... service) throws IOException {
        serviceList= Arrays.asList(service);
        ServerSocket server = new ServerSocket(port);
        Socket client=null;
        while (true){
            client=server.accept();
            new Thread(new ServerThread(client,serviceList)).start();
        }
    }

1.2.2 注册服务同时,开启线程,监听客户端请求

  • 此时服务端客户端通过socket进行RPC通信
  • 接收客户端请求服务信息
  • 检查注册中心是否存有客户端存有的请求服务信息
  • 若有通过反射调用相关服务,并将计算结果序列化后传回客户端
public class ServerThread implements Runnable{
    private Socket client=null;
    private List<Object> serviceList=null;
    public ServerThread(Socket client,List<Object> services){
        this.client=client;
        this.serviceList=services;
    }
    public void run(){
        ObjectInputStream objectInputStream=null;
        ObjectOutputStream objectOutputStream=null;
        try{
            objectInputStream=new ObjectInputStream(client.getInputStream());
            objectOutputStream=new ObjectOutputStream(client.getOutputStream());
            RpcSerializable rpcSerializable=(RpcSerializable)objectInputStream.readObject();
            // 读取类名
            Class serviceClass=(Class) rpcSerializable.getClassName();
            Object obj=getService(serviceClass);
            if(obj==null){
                throw new Exception("not service");
            }
            // 读取方法名
            String methodName=rpcSerializable.getMethodName();
            // 读取方法入参类型
            Class<?>[] parameterTypes=rpcSerializable.getParameterTypes();
            // 读取方法调用入参
            Object[] parameters=rpcSerializable.getArguments();
            System.out.println(String.format("收到消费者远程调用请求:类名 = {%s},方法名 = {%s},调用入参 = %s,方法入参列表 = %s",
                    serviceClass, methodName, Arrays.toString(parameters), Arrays.toString(parameterTypes)));
            Method method = obj.getClass().getMethod(methodName,parameterTypes);
            Object invoke = method.invoke(obj, parameters);
            System.out.println("方法调用结果:" + invoke);
            objectOutputStream.writeObject(invoke);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public Object getService(Class servicesClass){
        for(Object obj:serviceList){
            boolean isFather=servicesClass.isAssignableFrom(obj.getClass());
            if(isFather){
                return obj;
            }
        }
        return null;
    }
}

1.3 客户端

  • 客户端向注册中心订阅服务地址并发送服务请求

1.3.1 实现代理类,在代理类中请求服务

  • ip、port作为参数
public class ProxyHandler implements InvocationHandler {
    private String ip;
    private int port;

    public ProxyHandler(String ip, int port) {
        this.ip = ip;
        this.port = port;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Exception {
        Socket socket = new Socket(ip,port);
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
        RpcSerializable rpcSerializable = new RpcSerializable(proxy.getClass().getInterfaces()[0], method.getName(), method.getParameterTypes(), args);
        objectOutputStream.writeObject(rpcSerializable);
        ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream());
        return inputStream.readObject();
    }
}

1.3.2 获取代理对象

public class RpcConsumer {
    public static <T> T getService(Class<T> clazz,String ip,int port) {
        ProxyHandler proxyHandler =new ProxyHandler(ip,port);
        return (T) Proxy.newProxyInstance(RpcConsumer.class.getClassLoader(), new Class<?>[] {clazz}, proxyHandler);
    }
}

1.4 通过RPC远程调用(测试示例,客户端)

public class RpcTest {
    public static void main(String[] args) {
        CalculatorService calculator= RpcConsumer.getService(CalculatorService.class,"127.0.0.1",8081);
        int res=calculator.add(100,86);

        System.out.println(res);
    }
}
  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-05-06 11:19:09  更:2022-05-06 11:19:44 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 1:29:37-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码