自己实现一个简单的RPC

  闲话不多说,上来撸代码

  1. rpc_client

  • 首先,需要拿到服务器端的接口
package com.swh.ami.highVersion.socket.client;

import java.io.Serializable;

public interface ILearnService {

    String learn(String name);
}
  • 创建接口代理
package com.swh.ami.highVersion.socket.client;

import java.lang.reflect.Proxy;

public class RpcClientProxy {
    //  通过代理来创建"实现类"来调用接口中的方法
    public   <T> T  clientProxy(final Class<T> interfaceCls,final String host,final int post){
       return (T)Proxy.newProxyInstance(RpcClientProxy.class.getClassLoader(),
                new Class[]{interfaceCls},
                new RpcClientInvercation(host,post));
    }
}
  • 实现InvocationHandler接口
package com.swh.ami.highVersion.socket.client;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * 实现InvocationHandler接口,实现invoke方法,以便于动态代理生成的代理对象回调
 * 因为客户端没有调用方法的实现只有接口,所以代理对象回调时会把需要调用的对象信息(对象名称,方法,参数)
 * 通过socket传到服务器端,然后服务器端通过反射的方式执行方法并将结果返回给客户端
 */
public class RpcClientInvercation implements InvocationHandler{
    private String host;
    private int port;

    public RpcClientInvercation(String host, int port) {
        this.host = host;
        this.port = port;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        RequestDataInfo dataInfo = new RequestDataInfo();
        dataInfo.setClassName(method.getDeclaringClass().getName());
        dataInfo.setMethodName(method.getName());
        dataInfo.setParameters(args);
        return new ManagementSocket().handlerSocket(dataInfo, host, port);
    }
}
  • 创建管理客户端socket
package com.swh.ami.highVersion.socket.client;

import java.io.*;
import java.net.Socket;

/**
 * 创建socket连接远程客户端并把调用信息传到服务器
 * 同时接口远程服务器返回的信息
 */
public class ManagementSocket {

    private Socket newSocket(String host, int port) {
        try {
            System.out.println("创建一个新的连接");
            return new Socket(host, port);
        } catch (IOException e) {
            throw new RuntimeException("连接异常");
        }

    }

    public Object handlerSocket(RequestDataInfo requestDataInfo, String host, int port) {
        Socket socket = null;
        OutputStream outputStream = null;
        ObjectOutputStream objectOutputStream = null;
        InputStream inputStream = null;
        ObjectInputStream objectInputStream = null;
        try {
            socket = newSocket(host, port);
            outputStream = socket.getOutputStream();
            objectOutputStream = new ObjectOutputStream(outputStream);
            objectOutputStream.writeObject(requestDataInfo);
            outputStream.flush();
            inputStream = socket.getInputStream();
            objectInputStream = new ObjectInputStream(inputStream);
            return objectInputStream.readObject();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                if (objectInputStream != null) {
                    objectInputStream.close();
                }
                if(inputStream!=null){
                    inputStream.close();
                }
                if(objectOutputStream!=null){
                    objectOutputStream.close();
                }
                if(outputStream!=null){
                    outputStream.close();
                }
                if(socket!=null){
                    socket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }


}
  • 传输的对象信息
package com.swh.ami.highVersion.socket.client;

import java.io.Serializable;

public class RequestDataInfo implements Serializable{

    private static final long serialVersionUID = 3121764803401713947L;

    private String className;

    private String methodName;

    private Object[] parameters;

    public String getClassName() {
        return className;
    }

    public void setClassName(String className) {
        this.className = className;
    }

    public String getMethodName() {
        return methodName;
    }

    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }

    public Object[] getParameters() {
        return parameters;
    }

    public void setParameters(Object[] parameters) {
        this.parameters = parameters;
    }
}
  • 客户端的调用
package com.swh.ami.highVersion.socket.client;

import java.io.*;

public class SocketClientA {
    public static void main(String[] args) throws IOException {
        RpcClientProxy rpcClientProxy = new RpcClientProxy();
        // 此处使用动态代理的目的是,易于扩展,当新增其他服务接口的时候只需要修改接口的进来就可以了
        ILearnService iLearnService = rpcClientProxy.clientProxy(ILearnService.class, "127.0.0.1", 10222);
        String learn = iLearnService.learn("111");
        System.out.println(learn);
    }
}

2.rpc_server

  • 服务器提供的服务方法
package com.swh.ami.highVersion.socket.client;

public interface ILearnService {

    String learn(String name);
}
package com.swh.ami.highVersion.socket.client;


public class LearnServiceImpl implements ILearnService {


    @Override
    public String learn(String name) {
        return "我要学习," + name;
    }
}

  • socket服务端接收,并处理
package com.swh.ami.highVersion.socket.client;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

/**
 *   socket  编程基础多线程版
 *
 *   ① 创建ServerSocket对象,绑定监听端口
 ② 通过accept()方法监听客户端请求
 ③ 连接建立后,通过输入流读取客户端发送的请求信息
 ④ 通过输出流向客户端发送乡音信息
 ⑤ 关闭相关资源
 */
public class SocketServiceThread {
    private Object serverName;
    private int port;

    public SocketServiceThread(Object serverName, int port) {
        this.serverName = serverName;
        this.port = port;
    }

    public  void publishServer() throws IOException {
        /**
         * ① 服务器端创建ServerSocket,循环调用accept()等待客户端连接
         ② 客户端创建一个socket并请求和服务器端连接
         ③ 服务器端接受苦读段请求,创建socket与该客户建立专线连接
         ④ 建立连接的两个socket在一个单独的线程上对话
         ⑤ 服务器端继续等待新的连接
         */
        // 创建serverSocket对象绑定监听端口
        ServerSocket serverSocket = new ServerSocket(port);

        Socket accept = null;
        int count = 0;
       while (true){
           accept = serverSocket.accept();
           ServiceThread serviceThread = new ServiceThread(accept,serverName);
           new Thread(serviceThread).start();
           count++;
           System.out.println(count);
       }
    }

}
package com.swh.ami.highVersion.socket.client;


import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;

public class ServiceThread implements Runnable{
    Socket socket = null;
    private Object serverName;

    public ServiceThread(Socket socket,Object serverName) {
        this.socket = socket;
        this.serverName = serverName;
    }

    @Override
    public void run() {
        // 创建serverSocket对象绑定监听端口
      
        try {

            InputStream inputStream = socket.getInputStream();

            ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);

            RequestDataInfo requestDataInfo = (RequestDataInfo) objectInputStream.readObject();
            Class[] classes = new Class[requestDataInfo.getParameters().length];
            Object[] parameters = requestDataInfo.getParameters();
            for (int i = 0 ;i<parameters.length;i++){
                classes[i]=parameters[i].getClass();
            }
            Object invoke = serverName.getClass().getMethod(requestDataInfo.getMethodName(), classes).invoke(serverName, parameters);
            System.out.println(invoke);
           /* Object invoke = Class.forName(requestDataInfo.getClassName())
                    .getMethod(requestDataInfo.getMethodName(), classes)
                    .invoke(requestDataInfo.getMethodName(), parameters);*/

            OutputStream outputStream = socket.getOutputStream();
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
            objectOutputStream.writeObject(invoke);
            objectOutputStream.flush();
            objectInputStream.close();
            outputStream.close();
            objectInputStream.close();
            inputStream.close();
            socket.close();
        }catch (Exception e){
            throw new RuntimeException(e);
        }

    }
}
  • 服务器也需要一个传输对象
package com.swh.ami.highVersion.socket.client;

import java.io.Serializable;

public class RequestDataInfo implements Serializable{

    private static final long serialVersionUID = 3121764803401713947L;

    private String className;

    private String methodName;

    private Object[] parameters;

    public String getClassName() {
        return className;
    }

    public void setClassName(String className) {
        this.className = className;
    }

    public String getMethodName() {
        return methodName;
    }

    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }

    public Object[] getParameters() {
        return parameters;
    }

    public void setParameters(Object[] parameters) {
        this.parameters = parameters;
    }
}
  • 服务端发布服务
package com.swh.ami.highVersion.socket.client;

import java.io.IOException;

public class DemoServer {
    public static void main(String[] args) throws IOException {
        ILearnService learnService = new LearnServiceImpl();
        SocketServiceThread serviceThread = new SocketServiceThread(learnService, 10222);
        serviceThread.publishServer();
    }
}

运行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值