写一个RPC服务
定义:RPC(Remote Procedure Call Protocol)——远程过程调用协议 ,RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层 ,RPC使得开发包括网络分布式多程序在内的应用程序更加容易。
我的理解:与其说把RPC 看作是一种协议,倒不如把 它看作是一种 客户机/服务器交互的模式,但是 RPC一定是基于 TCP 或者 其他 通信协议的
下面我们来看一下一个RPC调用的流程涉及哪些通信细节:
- 服务消费方(client)调用以本地调用方式调用服务;(1)
- client stub接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体;(2)
- client stub找到服务地址,并将消息发送到服务端;(3)
- server stub收到消息后进行解码;(4)
- server stub根据解码结果调用本地的服务;(5)
- 本地服务执行并将结果返回给server stub;(6)
- server stub将返回结果打包成消息并发送至消费方;(7)
- client stub接收到消息,并进行解码;(8)
- 服务消费方得到最终结果。(9)
RPC的目标就是要2~8这些步骤都封装起来,让用户对这些细节透明。
2|01.2 手动实现
1.2.1 先做一个空接口实现序列化接口
public interface IRpcService extends Serializable{ }
1.2.2 做一个需要被远程调用的接口 以及对应的接口实现类
注:这个地方 我没有采用dom4j 解析配置文件的形式 进行接口注册 有时间的朋友可以多加一层
public class Client { @SuppressWarnings("unchecked") public static <T extends IRpcService>T getRemoteProxyObj(final Class<? extends IRpcService> serviceInterface,final InetSocketAddress addr){ return (T) Proxy.newProxyInstance(serviceInterface.getClassLoader(), new Class<?>[]{serviceInterface}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Socket socket = null; ObjectOutputStream output = null; ObjectInputStream input = null; try { //1.创建Socket客户端,根据指定地址连接远程服务提供者 socket = new Socket(); socket.connect(addr); //2.将远程服务调用所需的接口类、方法名、参数列表等编码后发送给服务提供者 output = new ObjectOutputStream(socket.getOutputStream()); output.writeUTF(serviceInterface.getName()); output.writeUTF(method.getName()); output.writeObject(method.getParameterTypes()); output.writeObject(args); //3.同步阻塞等待服务器返回应答 获取应答后返回 input = new ObjectInputStream(socket.getInputStream()); return input.readObject(); } finally{ if(socket != null){ socket.close(); } if(output != null){ output.close(); } if(input != null){ input.close(); } } } }); } }
1.2.5 测试
注:测试之前 需要开启服务端
public class RpcTest { public static void main(String[] args) throws IOException { IHelloService service = Client.getRemoteProxyObj(IHelloService.class, new InetSocketAddress(8080)); System.out.println(service.sayHi("张三", "新年快乐!")); } }
本文意在通过实现简单的RPC,去真正意义上对RPC框架的实现原理有初步的了解,而不是人云亦云。
此RPC实现有诸多缺点,但是 我们只要明白RPC的基座 其他的RPC框架只是完善基座以及扩展而已 。