简单RPC之Socket实现

本文介绍了一个简单的RPC框架实现过程,包括服务端与客户端代码。服务端通过反射执行远程调用,客户端利用代理机制完成方法调用。示例展示了HelloRpc接口及其实现类的远程调用过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近看到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,当然这个实现只是作为一些简单的原理说明,还有很多不足的地方。







介绍RCP的实现原理 目录 1. 前言 2 2. 基本概念 3 2.1. IDL 3 2.2. 代理(Proxy) 3 2.3. 存根(Stub) 4 3. 三要素 4 3.1. 网络通讯 4 3.2. 消息编解码 5 3.3. IDL编译器 5 4. flex和bison 5 4.1. 准备概念 5 4.1.1. 正则表达式(regex/regexp) 6 4.1.2. 符号∈ 6 4.1.3. 终结符/非终结符/产生式 6 4.1.4. 记号(Token) 6 4.1.5. 形式文法 7 4.1.6. 上下文无关文法(CFG) 7 4.1.7. BNF 8 4.1.8. 推导 8 4.1.9. 语法树 8 4.1.10. LL(k) 9 4.1.11. LR(k) 9 4.1.12. LALR(k) 9 4.1.13. GLR 9 4.1.14. 移进/归约 9 4.2. flex和bison文件格式 9 4.2.1. 定义部分 10 4.2.2. 规则部分 10 4.2.3. 用户子例程部分 10 4.3. flex基础 10 4.3.1. flex文件格式 11 4.3.2. 选项 11 4.3.3. 名字定义 11 4.3.4. 词法规则 12 4.3.5. 匹配规则 12 4.3.6. %option 13 4.3.7. 全局变量yytext 13 4.3.8. 全局变量yyval 13 4.3.9. 全局变量yyleng 13 4.3.10. 全局函数yylex 13 4.3.11. 全局函数yywrap 13 4.4. bison基础 14 4.4.1. bison文件格式 14 4.4.2. %union 14 4.4.3. %token 15 4.4.4. 全局函数yyerror() 15 4.4.5. 全局函数yyparse() 15 4.5. 例1:单词计数 15 4.5.1. 目的 15 4.5.2. flex词法文件wc.l 16 4.5.3. Makefile 16 4.6. 例2:表达式 17 4.6.1. 目的 17 4.6.2. flex词法exp.l 17 4.6.3. bison语法exp.y 17 4.6.4. Makefile 19 4.6.5. 代码集成 19 4.7. 例3:函数 20 4.7.1. 目的 20 4.7.2. func.h 20 4.7.3. func.c 21 4.7.4. IDL代码func.idl 22 4.7.5. flex词法func.l 22 4.7.6. bison语法func.y 24 4.7.7. Makefile 27 5. 进阶 27 5.1. 客户端函数实现 27 5.2. 服务端函数实现 28 5.2.1. Stub部分实现 28 5.2.2. 用户部分实现 29 6. 参考资料 29
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值