实战RPC是什么?如何实现?
Posted ITSK
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了实战RPC是什么?如何实现?相关的知识,希望对你有一定的参考价值。
本篇文章主要分享一下RPC相关知识,包括:RPC是什么?调用过程具体是什么样的以及如何实现?
RPC是什么?
-
客户端(Client):服务调用方; -
服务端(Server):服务提供者; -
客户端存根(Client Stub):存放服务端的地址消息,再将客户端的请求参数打包成网络消息,然后通过网络远程发送给服务方; -
服务端存根(Server Stub):接收客户端发送过来的消息,将消息解包,并调用本地的方法。
-
客户端(Client)以本地调用方式调用服务(依赖服务接口,以接口的方式调用)。 -
客户端存根(Client Stub)接收到调用请求后,负责将方法、参数等组装成能够进行网络传输的消息体(将消息体对象序列化为二进制)。 -
客户端通过Socket将消息发送到服务端。 -
服务端存根(Server Stub)收到消息后对消息进行解码(将消息对象反序列化)。 -
服务端存根(Server Stub)根据解码结果调用本地的服务(利用反射原理)。 -
本地服务执行并将结果返回给服务端存根(Server Stub)。 -
服务端存根(Server Stub)将返回结果打包成消息(将结果消息对象序列化)。 -
服务端(Server)通过Socket将消息发送到客户端。 -
客户端存根(Client Stub)接收到结果消息,并进行解码(将结果消息反序列化)。 -
客户端(Client)得到最终结果。
RPC框架调用分类
RPC调用主要分为两种:同步调用和异步调用
1、同步调用:
① 同步调用:客户端调用服务端方法,等待直到服务端返回结果或者超时,再继续自己的操作。
我们基于Java 实现一个简单的RPC调用例子:基本工作流程如下:
① 客户端发起调用请求;
② 将调用的内容序列化后通过网络发给服务端;
③ 服务端接收到调用请求,执行具体服务并获得结果;
④ 将结果序列化后通过网络返回给客户端。
具体代码如下:
服务端的接口:
public interface IUserService {
String getUserName(String name);
}
public class UserServiceImpl implements IUserService {
@Override
public String getUserName(String name) {
return name;
}
}
服务端的服务类:
public class RpcServer {
//定义一个服务接口注册表:key:接口名 value:对应的接口实现类
private static final HashMap<String, Class<?>> serviceRegistry = new HashMap<String, Class<?>>();
//服务监听的端口
private int port;
public RpcServer(int port) {
this.port = port;
}
/**
* 注册服务
*
* @param service 接口的class对象
* @param serviceImpl 接口实现类的class对象
* @return
*/
public RpcServer registryServices(Class service, Class serviceImpl) {
serviceRegistry.put(service.getName(), serviceImpl);
return this;
}
/**
* 处理请求、返回结果
*
* @throws IOException
*/
public void run() throws IOException {
//创建并启动监听port端口的服务
ServerSocket serverSocket = new ServerSocket();
serverSocket.bind(new InetSocketAddress(port));
System.out.println("start server");
Socket socket = null;
ObjectInputStream ois = null;
ObjectOutputStream oos = null;
try {
while (true) {
//监听请求该服务端的客户端(阻塞等待)
socket = serverSocket.accept();
//读取客户端请求内容:接口名称、方法名、请求参数
ois = new ObjectInputStream(socket.getInputStream());
String serviceName = ois.readUTF();
String methodName = ois.readUTF();
Class<?>[] parameterTypes = (Class<?>[]) ois.readObject();
Object[] arguments = (Object[]) ois.readObject();
//在接口服务注册表中通过接口名获取对应的接口实现类
Class<?> serviceClazz = serviceRegistry.get(serviceName);
if (null == serviceClazz) {
throw new ClassNotFoundException("接口 serviceName 不存在。。。");
}
//通过反射获取接口实现类的方法对象
Method method = serviceClazz.getMethod(methodName, parameterTypes);
//通过反射调用服务
Object result = method.invoke(serviceClazz.newInstance(), arguments);
//将结果返回给客户端
oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(result);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != socket) {
socket.close();
}
if (null != oos) {
oos.close();
}
if (null != ois) {
ois.close();
}
}
}
public static void main(String[] args) throws IOException {
new RpcServer(8888).registryServices(IUserService.class, UserServiceImpl.class).run();
}
}
public class RpcClientProxy<T> implements InvocationHandler {
//要请求的接口
private Class<T> serviceInterface;
//请求的接口的地址:ip+端口
private SocketAddress address;
public RpcClientProxy(Class<T> serviceInterface, String ip, int port) {
this.serviceInterface = serviceInterface;
address = new InetSocketAddress(ip, port);
}
/**
* 获取要调用的接口的代理类
*
* @return
*/
public T getClientIntance() {
return (T) Proxy.newProxyInstance(serviceInterface.getClassLoader(), new Class<?>[]{serviceInterface}, this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Socket socket = null;
ObjectOutputStream oos = null;
ObjectInputStream ois = null;
try {
socket = new Socket();
//连接到指定服务端
socket.connect(address);
oos = new ObjectOutputStream(socket.getOutputStream());
//将远程服务调用所需的接口类、方法名、参数列表等编码后发送给服务提供者
oos.writeUTF(serviceInterface.getName());
oos.writeUTF(method.getName());
oos.writeObject(method.getParameterTypes());
oos.writeObject(args);
//同步阻塞等待服务器返回结果,获取返回结果后直接返回
ois = new ObjectInputStream(socket.getInputStream());
return ois.readObject();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != socket) {
socket.close();
}
if (null != oos) {
oos.close();
}
if (null != ois) {
ois.close();
}
}
return null;
}
public static void main(String[] args) {
RpcClientProxy<IUserService> rpcClientProxy = new RpcClientProxy<IUserService>(IUserService.class, "127.0.0.1", 8888);
IUserService userServiceProxy = rpcClientProxy.getClientIntance();
System.out.println(userServiceProxy.getUserName("张三"));
}
}
本文总结到这里,想要交流的小伙伴欢迎评论区留言哦
欢迎关注ITSK,每天进步一点点,我们追求在交流中收获成长和快乐
以上是关于实战RPC是什么?如何实现?的主要内容,如果未能解决你的问题,请参考以下文章
服务化实战之 dubbodubboxmotanthriftgrpc等RPC框架选型