最近看到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();
			}
		}
	}
}

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

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);
}

HelloRpcImpl实现类:

public class HelloRpcImpl implements HelloRpc {

	@Override
	public String hello(String name) {
		return "hello "+name;
	}

}

Main函数操作:

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框架的实现原理有一定的了解,比如和我之前发表的Hessian源码分析有一些相似的地方。示例源码地址github,当然这个实现只是作为一些简单的原理说明,还有很多不足的地方。

简单RPC之Socket实现的更多相关文章

  1. 简单RPC实现之Netty实现

    所谓RPC就是远程方法调用(Remote  Process Call ),简单的来说就是通过MQ,TCP,HTTP或者自己写的网络协议来传输我要调用对方的什么接口,对方处理之后再把结果返回给我.就这么 ...

  2. RPC笔记之初探RPC:DIY简单RPC框架

    一.什么是RPC RPC(Remote Procedure Call)即远程过程调用,简单的说就是在A机器上去调用B机器上的某个方法,在分布式系统中极其常用. rpc原理其实很简单,比较容易理解,在r ...

  3. rpc、socket、mq

    关于RPC与MQ异同的理解 相同:1.都利于大型系统的解耦:2.都提供子系统之间的交互,特别是异构子系统(如java\node等不同开发语言):不同:1.RPC侧重功能调用,因此多半是同步的:备注:也 ...

  4. RPC和Socket

    RPC和Socket的区别 rpc是通过什么实现啊?socket! RPC(Remote Procedure Call,远程过程调用)是建立在Socket之上的,出于一种类比的愿望,在一台机器上运行的 ...

  5. Java实现简单RPC框架(转)

    一.RPC简介 RPC,全称Remote Procedure Call, 即远程过程调用,它是一个计算机通信协议.它允许像本地服务一样调用远程服务.它可以有不同的实现方式.如RMI(远程方法调用).H ...

  6. winsock2之最简单的win socket编程

    原文:winsock2之最简单的win socket编程 server.cpp #include <WINSOCK2.H> #include <stdio.h> #pragma ...

  7. UEditor编辑器和php简单的实现socket通信

    一.UEditor编辑器 使用这个编辑器是需要先下载编辑器文件,记得下载的时候放入自己的网站中,既然是php中使用,自然我下载的就是php的UEditor编辑器了,然后是utf-8的 其实使用很简单, ...

  8. 简单的异步Socket实现——SimpleSocket_V1.1

    简单的异步Socket实现——SimpleSocket_V1.1 笔者在前段时间的博客中分享了一段简单的异步.net的Socket实现.由于是笔者自己测试使用的.写的很粗糙.很简陋.于是花了点时间自己 ...

  9. RPC和Socket,RMI和RPC之间的关系

    远程通信机制RPC与RMI的关系 http://blog.csdn.net/zolalad/article/details/25161133       1.RPC RPC(Remote Proced ...

随机推荐

  1. ●BZOJ 4826 [Hnoi2017]影魔

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=4826 题解: 主席树,单调栈 以前还没做过这种维护信息的题,感觉好奇妙. 每对相邻的两个数所 ...

  2. getBoundingClientRect方法获取元素在页面中的相对位置

    获取元素位置可以用 offset 或 getBoundingClientRect,使用 offset 因为兼容性不好,比较麻烦,offset获取位置会形成"回溯".而 getBou ...

  3. AJAX 向后台发送带 List 集合的对象

    现有基类: public class School { int name; int address; List<Student> students = new ArrayList<S ...

  4. OLE:对象的类没有在注册数据库中注册

    我在网上下载了破解版的SAS9.3,用了一段时间之后,今天打开就填出一个提示框:OLE:对象的类没有在注册数据库中注册 激活该对象所需的应用程序不可用.是否用"转换--"将其转换为 ...

  5. NDK编程的一个坑—Arm平台下的类型转换

    最近在做DNN定点化相关的工作,DNN定点化就是把float表示的模型压缩成char表示,虽然会损失精度,但是由于DNN训练的模型值比较接近且范围较小,实际上带来的性能损失非常小.DNN定点化的好处是 ...

  6. 学习笔记:Zookeeper 应用案例(上下线动态感知)

    1.Zookeeper 应用案例(上下线动态感知) 8.1 案例1--服务器上下线动态感知 8.1.1 需求描述 某分布式系统中,主节点可以有多台,可以动态上下线 任意一台客户端都能实时感知到主节点服 ...

  7. Swift基础之如何使用iOS 9的Core Spotlight框架

    本文由CocoaChina译者KingOfOnePiece(博客)翻译 作者:GABRIEL THEODOROPOULOS?校对:hyhSuper 原文:How To Use Core Spotlig ...

  8. ActionContext.getContext()用法

    为了避免与Servlet API耦合在一起,方便Action类做单元测试,Struts 2对HttpServletRequest.HttpSession和ServletContext进行了封装,构造了 ...

  9. ICL Auto Vectorization

    简介 此文简单介绍如何使用intel c++编译器实现向量化加速. 全文如下安排: base : 待优化的源代码. vectorization : 第一个向量化版本. aligned : 内存对其对向 ...

  10. PGM:贝叶斯网的参数估计

    http://blog.csdn.net/pipisorry/article/details/52578631 本文讨论(完备数据的)贝叶斯网的参数估计问题:贝叶斯网的MLE最大似然估计和贝叶斯估计. ...