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

简单RPC之Socket实现
2016年10月28日 10:54:47

阅读数:2663

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

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

  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. public static ConcurrentHashMap<String, Object> classMap = new ConcurrentHashMap<String,Object>();
  15. public static void main(String [] args) throws Exception{
  16. System.err.println("server start");
  17. RPCServer.invoker(8080);
  18. }
  19. public static void invoker(int port) throws Exception{
  20. ServerSocket server = new ServerSocket(port);
  21. for(;;){
  22. try{
  23. final Socket socket = server.accept();
  24. new Thread(new Runnable() {
  25. ObjectOutputStream output =  null;
  26. @Override
  27. public void run() {
  28. try{
  29. try {
  30. output = new ObjectOutputStream(socket.getOutputStream());
  31. ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
  32. String className = input.readUTF();
  33. String methodName = input.readUTF();
  34. Class<?>[] parameterTypes = (Class<?>[])input.readObject();
  35. Object[] arguments = (Object[])input.readObject();
  36. Object claszz = null;
  37. if(!classMap.containsKey(className)){
  38. try {
  39. claszz = Class.forName(className).newInstance();
  40. classMap.put(className, claszz);
  41. } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
  42. e.printStackTrace();
  43. }
  44. }else {
  45. claszz = classMap.get(className);
  46. }
  47. Method method = claszz.getClass().getMethod(methodName, parameterTypes);
  48. Object result = method.invoke(claszz, arguments);
  49. output.writeObject(result);
  50. } catch (IOException | ClassNotFoundException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
  51. output.writeObject(e);
  52. }finally {
  53. output.close();
  54. }
  55. }catch(Exception e){
  56. e.printStackTrace();
  57. }finally {
  58. try {
  59. socket.close();
  60. } catch (IOException e) {
  61. e.printStackTrace();
  62. }
  63. }
  64. }
  65. }).start();
  66. }catch (Exception e) {
  67. e.printStackTrace();
  68. }
  69. }
  70. }
  71. }

RPC 客户端代码,这里利用了代理机制的特性,在执行具体的方法时执行远程调用,执行方法时会调用invoke方法,这样就可以通过Socket向RPCServer发送需要执行的方法的信息,并且获取执行后的结果并返回。

  1. public class RPCProxy {
  2. @SuppressWarnings("unchecked")
  3. public static <T> T create(Object target){
  4. return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), new InvocationHandler(){
  5. @SuppressWarnings("resource")
  6. @Override
  7. public Object invoke(Object proxy, Method method, Object[] args)
  8. throws Throwable {
  9. Socket socket = new Socket("localhost", 8080);
  10. ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
  11. try {
  12. output.writeUTF(target.getClass().getName());
  13. output.writeUTF(method.getName());
  14. output.writeObject(method.getParameterTypes());
  15. output.writeObject(args);
  16. ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
  17. try {
  18. Object result = input.readObject();
  19. if (result instanceof Throwable) {
  20. throw (Throwable) result;
  21. }
  22. return result;
  23. } finally {
  24. input.close();
  25. }
  26. } finally {
  27. output.close();
  28. socket.close();
  29. }
  30. }
  31. });
  32. }
  33. }

HelloRpc接口:

  1. public interface HelloRpc {
  2. String hello(String name);
  3. }

HelloRpcImpl实现类:

  1. public class HelloRpcImpl implements HelloRpc {
  2. @Override
  3. public String hello(String name) {
  4. return "hello "+name;
  5. }
  6. }

Main函数操作:

  1. public class Main {
  2. public static void main(String [] args){
  3. HelloRpc helloRpc = new HelloRpcImpl();
  4. helloRpc = RPCProxy.create(helloRpc);
  5. System.err.println(helloRpc.hello("rpc"));
  6. }
  7. }

执行结果:

hello rpc

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

最新文章

  1. 关于Wireshark &quot;The NPF driver isn’t running……&quot;解决办法
  2. oracle 数据库信息查询
  3. Windows Azure HandBook (3) 浅谈Azure安全性
  4. HttpRuntime类的缓存以及redis,memercache
  5. [转] Mac OX上安装MongoDb
  6. 开发支付宝支付用DELPHI实现 RSA签名
  7. linux经常使用命令:打包、复制等
  8. Android官方架构组件介绍之LifeCycle
  9. [置顶] Xamarin android中使用signalr实现即时通讯
  10. Hibernate【查询、连接池、逆向工程】
  11. 内核调试工具 — kdump &amp; crash
  12. 操作系统与cpu
  13. sql 一对多查询
  14. linux下如何按行将文件切割成多个小文件
  15. HTML5 Geolocation API地理定位整理(二)
  16. avalon 路由问题
  17. 正则表达式(Java,C#,C++)
  18. (转)MYSQL线程池总结(一)
  19. PHP中关于取模运算及符号
  20. Effective C++ .10,11 operator=的约定与注意

热门文章

  1. 抽象窗口工具包AWT (Abstract Window Toolkit) 是 API为Java 程序提供的建立 图形用户界面
  2. 目标跟踪之卡尔曼滤波---理解Kalman滤波的使用
  3. Hadoop大数据处理读书笔记
  4. 常用 Git 命令文档和命令
  5. Ubuntu修改默认root及密码
  6. (转)java synchronised关键字
  7. android去权限反编译,签名,zipalign优化
  8. PAXOS: libevent_paxos
  9. 【BZOJ4378】[POI2015]Logistyka 树状数组
  10. 【BZOJ4421】[Cerc2015] Digit Division 动态规划