RPC是在Socket的基础上实现的,它比socket需要更多的网络和系统资源。RPC(Remote Procedure Call,远程过程调用)是建立在Socket之上的,出于一种类比的愿望,在一台机器上运行的主程序,可以调用另一台机器上准备好的子程序,就像LPC(本地过程调用).
简单RPC之Socket实现
最近看到Dubbo大神写得使用Socket实现的简单的RPC调用,对RPC的理解更简单了,然后根据大神的代码自己也重构了一下。
RPC Server端代码,主要是使用ServerSocket获得rpc调用客户端发送过来的类信息,方法信息及方法参数信息,通过反射在RPCServer端进行代码执行,最后将执行结果发送给Socket,第一步需要首先执行RPCServer。
- import java.io.IOException;
- import java.io.ObjectInputStream;
- import java.io.ObjectOutputStream;
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
- import java.net.ServerSocket;
- import java.net.Socket;
- import java.util.concurrent.ConcurrentHashMap;
- /**
- * 服务端
- * @author tianjunwei
- */
- public class RPCServer {
- public static ConcurrentHashMap<String, Object> classMap = new ConcurrentHashMap<String,Object>();
- public static void main(String [] args) throws Exception{
- System.err.println("server start");
- RPCServer.invoker(8080);
- }
- public static void invoker(int port) throws Exception{
- ServerSocket server = new ServerSocket(port);
- for(;;){
- try{
- final Socket socket = server.accept();
- new Thread(new Runnable() {
- ObjectOutputStream output = null;
- @Override
- public void run() {
- try{
- try {
- output = new ObjectOutputStream(socket.getOutputStream());
- ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
- String className = input.readUTF();
- String methodName = input.readUTF();
- Class<?>[] parameterTypes = (Class<?>[])input.readObject();
- Object[] arguments = (Object[])input.readObject();
- Object claszz = null;
- if(!classMap.containsKey(className)){
- try {
- claszz = Class.forName(className).newInstance();
- classMap.put(className, claszz);
- } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
- e.printStackTrace();
- }
- }else {
- claszz = classMap.get(className);
- }
- Method method = claszz.getClass().getMethod(methodName, parameterTypes);
- Object result = method.invoke(claszz, arguments);
- output.writeObject(result);
- } catch (IOException | ClassNotFoundException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
- output.writeObject(e);
- }finally {
- output.close();
- }
- }catch(Exception e){
- e.printStackTrace();
- }finally {
- try {
- socket.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }).start();
- }catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- }
- public class RPCProxy {
- @SuppressWarnings("unchecked")
- public static <T> T create(Object target){
- return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), new InvocationHandler(){
- @SuppressWarnings("resource")
- @Override
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- Socket socket = new Socket("localhost", 8080);
- ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
- try {
- output.writeUTF(target.getClass().getName());
- output.writeUTF(method.getName());
- output.writeObject(method.getParameterTypes());
- output.writeObject(args);
- ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
- try {
- Object result = input.readObject();
- if (result instanceof Throwable) {
- throw (Throwable) result;
- }
- return result;
- } finally {
- input.close();
- }
- } finally {
- output.close();
- socket.close();
- }
- }
- });
- }
- }
HelloRpc接口:
- public interface HelloRpc {
- String hello(String name);
- }
- public class HelloRpcImpl implements HelloRpc {
- @Override
- public String hello(String name) {
- return "hello "+name;
- }
- }
- public class Main {
- public static void main(String [] args){
- HelloRpc helloRpc = new HelloRpcImpl();
- helloRpc = RPCProxy.create(helloRpc);
- System.err.println(helloRpc.hello("rpc"));
- }
- }
执行结果:
hello rpc
通过以上这个示例我们可能会对一些RPC框架的实现原理有一定的了解,比如和我之前发表的有一些相似的地方。示例源码地址,当然这个实现只是作为一些简单的原理说明,还有很多不足的地方。