RPC之一:基于TCP协议实现RPC

先看代码

服务接口

public interface SayHelloService {

	String sayHello(String hello);
}

 

作为服务提供方,要对服务接口给出实现

public class SayHelloServiceImpl implements SayHelloService {

	@Override
	public String sayHello(String hello) {
		if ("hello".equals(hello)) {
			return "hello";
		} else {
			return "bye bye";
		}
	}
}

 

消费者代码,很简单,先与本地的8888端口建立一个TCP连接,然后获取输出流,向另一端发送一些数据,这里的另一端就是我们的提供方了。

public class Consumer {

	public static void main(String[] args) throws Exception {
		String interfaceName = SayHelloService.class.getName();
		Method method = SayHelloService.class.getMethod("sayHello", String.class);
		Object[] arguments = {"hello"};

        // 将调用接口名、方法名、方法形参、方法实参传到另一端
		Socket socket = new Socket("localhost", 8888);
		ObjectOutputStream outputStream = new ObjectOutputStream(socket.getOutputStream());
		outputStream.writeUTF(interfaceName);
		outputStream.writeUTF(method.getName());
		outputStream.writeObject(method.getParameterTypes());
		outputStream.writeObject(arguments);

        // 从另一端读取方法执行结果
		ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
		Object result = input.readObject();
		System.out.println(result);
	}
}

 

服务提供方监听端口,建立和远端的TCP连接,接收数据,进行处理

public class Producer {

	private static final Map<String, Object> SERVICE_INSTANCE_MAP = new HashMap<>();

	static {
		SERVICE_INSTANCE_MAP.put(SayHelloService.class.getName(), new SayHelloServiceImpl());
	}

	public static void main(String[] args) throws Exception {
		ServerSocket server = new ServerSocket(8888);
		while (true) {
			Socket accept = server.accept();

			// 获取远端传来的接口名、方法名、方法形参、方法实参
			ObjectInputStream inputStream = new ObjectInputStream(accept.getInputStream());
			String interfaceName = inputStream.readUTF();
			String methodName = inputStream.readUTF();
			Class<?>[] parameterTypes = (Class<?>[]) inputStream.readObject();
			Object[] arguements = (Object[]) inputStream.readObject();

			// 通过接口名获取JVM中的Class对象
			Class<?> serviceInterfaceClass = Class.forName(interfaceName);
			// 获取接口实现的实例对象
			Object instance = SERVICE_INSTANCE_MAP.get(interfaceName);
			// 获取要执行的方法
			Method method = serviceInterfaceClass.getMethod(methodName, parameterTypes);
			// 执行
			Object result = method.invoke(instance, arguements);

			// 给远端返回接口
			ObjectOutputStream outputStream = new ObjectOutputStream(accept.getOutputStream());
			outputStream.writeObject(result);
		}
	}
}

 

测试:先启动Producer,再启动Consumer,Consumer的控制台可以看到打印结果

 

好,现在我们回顾一下整个流程。所谓RPC,远程过程调用,其实就是两台机器之间的两个JVM进程进行通信,我们这里使用TCP建立连接,连接建立好就可以相互发送数据了。

同一个JVM进程内的方法调用一般有两种,一种是调用类的静态方法,一种是调用实例对象的普通方法,但不管是哪种调用方式,我们使用的都是JVM可以处理的对象。而在网络中传输的是二进制流,1001000这种形式的,JVM是不认识的,服务提供方就要通过一些手段将这些二进制数据还原为JVM可以认识的对象然后再进行处理,服务提供方将二进制流还原为对象的过程就是反序列化。消费者需要将对象转换为二进制流在网络中传输,这个过程就是序列化。序列化和反序列化的本质和作用这就清楚了。

服务提供方再利用反射执行方法的调用,然后再将执行结果序列化返回给消费者,消费者再反序列化获取到执行结果打印出来,我们就用最简单的方式实现了一个RPC调用。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值