hadoop17---RPC和Socket的区别

RPC是在Socket的基础上实现的,它比socket需要更多的网络和系统资源。RPC(Remote Procedure Call,远程过程调用)是建立在Socket之上的,出于一种类比的愿望,在一台机器上运行的主程序,可以调用另一台机器上准备好的子程序,就像LPC(本地过程调用).

简单RPC之Socket实现

最近看到Dubbo大神写得使用Socket实现的简单的RPC调用,对RPC的理解更简单了,然后根据大神的代码自己也重构了一下。

RPC Server端代码,主要是使用ServerSocket获得rpc调用客户端发送过来的类信息,方法信息及方法参数信息,通过反射在RPCServer端进行代码执行,最后将执行结果发送给Socket,第一步需要首先执行RPCServer。

[java] view plain copy
 
  1. import java.io.IOException;  
  2. import java.io.ObjectInputStream;  
  3. import java.io.ObjectOutputStream;  
  4. import java.lang.reflect.InvocationTargetException;  
  5. import java.lang.reflect.Method;  
  6. import java.net.ServerSocket;  
  7. import java.net.Socket;  
  8. import java.util.concurrent.ConcurrentHashMap;  
  9. /** 
  10.  * 服务端 
  11.  * @author tianjunwei 
  12.  */  
  13. public class RPCServer {  
  14.   
  15.     public static ConcurrentHashMap<String, Object> classMap = new ConcurrentHashMap<String,Object>();  
  16.       
  17.     public static void main(String [] args) throws Exception{  
  18.         System.err.println("server start");  
  19.         RPCServer.invoker(8080);  
  20.     }  
  21.     public static void invoker(int port) throws Exception{  
  22.           
  23.         ServerSocket server = new ServerSocket(port);  
  24.         for(;;){  
  25.                 try{  
  26.                     final Socket socket = server.accept();  
  27.                     new Thread(new Runnable() {  
  28.                         ObjectOutputStream output =  null;  
  29.                         @Override  
  30.                         public void run() {  
  31.                             try{  
  32.                                 try {  
  33.                                     output = new ObjectOutputStream(socket.getOutputStream());   
  34.                                     ObjectInputStream input = new ObjectInputStream(socket.getInputStream());  
  35.                                     String className = input.readUTF();  
  36.                                     String methodName = input.readUTF();  
  37.                                     Class<?>[] parameterTypes = (Class<?>[])input.readObject();    
  38.                                     Object[] arguments = (Object[])input.readObject();    
  39.                                     Object claszz = null;  
  40.                                     if(!classMap.containsKey(className)){  
  41.                                         try {  
  42.                                             claszz = Class.forName(className).newInstance();  
  43.                                             classMap.put(className, claszz);  
  44.                                         } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {  
  45.                                             e.printStackTrace();  
  46.                                         }  
  47.                                     }else {  
  48.                                         claszz = classMap.get(className);  
  49.                                     }  
  50.                                     Method method = claszz.getClass().getMethod(methodName, parameterTypes);    
  51.                                     Object result = method.invoke(claszz, arguments);    
  52.                                     output.writeObject(result);    
  53.                                 } catch (IOException | ClassNotFoundException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {  
  54.                                     output.writeObject(e);  
  55.                                 }finally {  
  56.                                     output.close();  
  57.                                 }  
  58.                             }catch(Exception e){  
  59.                                 e.printStackTrace();  
  60.                             }finally {  
  61.                                 try {  
  62.                                     socket.close();  
  63.                                 } catch (IOException e) {  
  64.                                     e.printStackTrace();  
  65.                                 }  
  66.                             }  
  67.                         }  
  68.                     }).start();  
  69.             }catch (Exception e) {  
  70.                 e.printStackTrace();  
  71.             }  
  72.         }  
  73.     }  
  74. }  

RPC 客户端代码,这里利用了代理机制的特性,在执行具体的方法时执行远程调用,执行方法时会调用invoke方法,这样就可以通过Socket向RPCServer发送需要执行的方法的信息,并且获取执行后的结果并返回。
[java] view plain copy
 
  1. public class RPCProxy {  
  2.       
  3.      @SuppressWarnings("unchecked")  
  4.     public static <T> T create(Object target){  
  5.            
  6.          return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), new InvocationHandler(){  
  7.   
  8.             @SuppressWarnings("resource")  
  9.             @Override  
  10.             public Object invoke(Object proxy, Method method, Object[] args)  
  11.                     throws Throwable {  
  12.                  Socket socket = new Socket("localhost", 8080);  
  13.                  ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());    
  14.                  try {    
  15.                      output.writeUTF(target.getClass().getName());  
  16.                      output.writeUTF(method.getName());    
  17.                      output.writeObject(method.getParameterTypes());    
  18.                      output.writeObject(args);    
  19.                      ObjectInputStream input = new ObjectInputStream(socket.getInputStream());    
  20.                      try {    
  21.                          Object result = input.readObject();    
  22.                          if (result instanceof Throwable) {    
  23.                              throw (Throwable) result;    
  24.                          }    
  25.                          return result;    
  26.                      } finally {    
  27.                          input.close();    
  28.                      }    
  29.                  } finally {    
  30.                      output.close();    
  31.                      socket.close();  
  32.                  }    
  33.             }  
  34.                
  35.          });  
  36.      }  
  37. }  

HelloRpc接口:

[java] view plain copy
 
  1. public interface HelloRpc {  
  2.     String hello(String name);  
  3. }  
HelloRpcImpl实现类:
[java] view plain copy
 
  1. public class HelloRpcImpl implements HelloRpc {  
  2.   
  3.     @Override  
  4.     public String hello(String name) {  
  5.         return "hello "+name;  
  6.     }  
  7.   
  8. }  

Main函数操作:
[java] view plain copy
 
  1. public class Main {  
  2.   
  3.     public static void main(String [] args){  
  4.         HelloRpc helloRpc = new HelloRpcImpl();  
  5.         helloRpc = RPCProxy.create(helloRpc);  
  6.         System.err.println(helloRpc.hello("rpc"));  
  7.     }  
  8. }  
执行结果:

hello rpc

通过以上这个示例我们可能会对一些RPC框架的实现原理有一定的了解,比如和我之前发表的Hessian源码分析有一些相似的地方。示例源码地址github,当然这个实现只是作为一些简单的原理说明,还有很多不足的地方。

原文地址:https://www.cnblogs.com/yaowen/p/9025475.html