最近看到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. NOIP 2013

    Prob.1 转圈游戏 找到循环节,然后快速幂.代码: #include<cstdio> #include<cstring> #include<iostream> ...

  2. HDU2256(矩阵)

    求(sqrt(2) + sqrt(3)) ^ 2n MOD 1024 强行盗图- -,这公式推得 .. #include <iostream> #include <cstdio> ...

  3. 【Bzoj 1835 基站选址】

    基站选址的区间里隐藏着DP优化的机密…… 分析:       不论是做过乘积最大还是石子合并,或者是其他的入门级别的区间DP题目的人呐,大米并认为读题后就能够轻松得出一个简洁明了的Dp转移方程.    ...

  4. SpringCloud学习之eureka集群配置

    一.集群方案及部署思路: 如果是单节点的注册中心,是无法保证系统稳定性的,当然现在项目部署架构不可能是单节点的. 集群节点的部署思路:通过运行多个实例并请求他们相互注册,来完成注册中心的高可用性(结伴 ...

  5. jqGrid移动滑块时冻结首列和第二列例子

    js代码如以下代码:在initAllGrid函数colModel1加入属性设置:frozen:true:然后在_initGrid('task_con_grid_div',colModel1)函数里面加 ...

  6. 2017-9-19 c语言预备作业

    题目一: (1)我对邹欣老师博客内容的看法 针对邹欣老师的第一种看法,也就是文中所谈的春蚕与园丁的例子.我认为在大学之前的阶段,师生关系可以如此比喻,因为在中学阶段教师与学生的关系,更多地是一个知识的 ...

  7. dfsdf

    This project was bootstrapped with Create React App. Below you will find some information on how to ...

  8. 开启CSP网页安全政策防止XSS攻击

     一.简介 CSP是网页安全政策(Content Security Policy)的缩写.是一种由开发者定义的安全性政策申明,通过CSP所约束的责任指定可信的内容来源,(内容可以是指脚本.图片.sty ...

  9. ConcurrentHashMap1.7和1.8的不同实现

    ConcurrentHashMap 在多线程环境下,使用HashMap进行put操作时存在丢失数据的情况,为了避免这种bug的隐患,强烈建议使用ConcurrentHashMap代替HashMap,为 ...

  10. Python 头部 #!/usr/bin/python 和 #!/usr/bin/env 的区别

    这个网址 https://www.cnblogs.com/scofi/p/4867851.html 讲述了Python 头部 #!/usr/bin/python 和 #!/usr/bin/env 的区 ...