服务端代码

package com.peiyu.rpcs.bios;

import java.io.IOException;

public interface IRpcServers {

    void start() throws IOException;

    /**
* 服务注册
* @param serviceInterface 服务接口
* @param impl 服务实现类
*/
void register(Class serviceInterface, Class impl);
}

实现类

package com.peiyu.rpcs.bios;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit; public class RpcServesrImpl implements IRpcServers {
private int port;
public static final HashMap<String, Class> serviceRegistry = new HashMap<String, Class>();
private static final ThreadPoolExecutor executor = new ThreadPoolExecutor(20, 20, 100, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(100)); public RpcServesrImpl(int port) {
this.port = port;
} /**
* 启动服务
*/
@Override
public void start() throws IOException {
ServerSocket server = new ServerSocket();
server.bind(new InetSocketAddress(port));
System.out.println("Bio rpc 服务启动开始###端口###" + port);
try {
while (true) {
System.out.println("等待客户端接入");
executor.execute(new ServersTask(server.accept()));
}
} catch (Exception e) {
if (server != null) {
server.close();
}
}
} @Override
public void register(Class serviceInterface, Class impl) {
serviceRegistry.put(serviceInterface.getName(), impl);
} static class ServersTask implements Runnable {
Socket client = null; public ServersTask(Socket socket) {
this.client = socket;
} ObjectInputStream input = null;//输入流
ObjectOutputStream output = null;//输出流 @Override
public void run() {
//接收客户端发送来的字节流,并转化成对象,反射调用服务实现者,获取执行结果
try {
input = new ObjectInputStream(this.client.getInputStream());
String interfaceName = input.readUTF();
String methodName = input.readUTF();
Class<?>[] parameterType = (Class<?>[]) input.readObject();
Object[] args = (Object[]) input.readObject();
Class serverClass = serviceRegistry.get(interfaceName);//这里有问题服务器端去注册中心拉取实现类??
//但是如果不考虑注册中心,当作本地映射还挺好,
//省的使用反射来通过接口来找实现类.
if (serverClass == null) {
throw new ClassNotFoundException(interfaceName + " not found");
}
Method method = serverClass.getMethod(methodName, parameterType);
Object result = method.invoke(serverClass.newInstance(), args);
//执行结果反序列化返回给客户端
output = new ObjectOutputStream(this.client.getOutputStream());
output.writeObject(result);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (output != null) {
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (input != null) {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (this.client != null) {
try {
this.client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} }
}
}

mainapp

package com.peiyu.rpcs.bios;

import java.io.IOException;

public class MainApp {
public static void main(String[] args) throws Exception {
IRpcServers server = new RpcServesrImpl(8080);
server.register(IOrderService.class, IOrderServiceImpl.class);
server.start();
} }

一个接口一个实现类

package com.peiyu.rpcs.bios;

public interface IOrderService {
String getOrderDtoByUserId(int i); }
package com.peiyu.rpcs.bios;

public class IOrderServiceImpl implements IOrderService{

    @Override
public String getOrderDtoByUserId(int i) {
// TODO Auto-generated method stub return 100*i+"";
} }

客户端

package com.peiyu.rpcs.bios;

public class CLIENT {
public static void main(String[] args) {
long start =System.currentTimeMillis();
for (int i=0;i<200;i++){
try {
IOrderService orderService= ProxyFactory.create(IOrderService.class,"127.0.0.1",8080);
System.out.println(orderService.getOrderDtoByUserId(i));
}catch (Exception e){
e.printStackTrace();
}
}
long end=System.currentTimeMillis();
System.out.println("总耗时:"+(end-start)); } }

代理

package com.peiyu.rpcs.bios;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.Socket; public class ProxyFactory<T> { public static <T> T create(final Class<?> serviceInterface, final String ip, final int port) {
//将本地的接口调用转换成JDK的动态代理,在动态代理中实现接口的远程调用
return (T) Proxy.newProxyInstance(serviceInterface.getClassLoader(), new Class<?>[]{serviceInterface}, new ProxyHandler(ip, port, serviceInterface));
} static class ProxyHandler implements InvocationHandler {
private String ip;
private int port;
private Class<?> serviceInterface; public ProxyHandler(String ip, int port, Class<?> serviceInterface) {
this.ip = ip;
this.port = port;
this.serviceInterface = serviceInterface;
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Socket socket = null;
ObjectOutputStream output = null;
ObjectInputStream input = null;
try {
// 创建Socket客户端,根据指定地址连接远程服务提供者
socket = new Socket(ip, port);
// 将远程服务调用所需的接口类、方法名、参数列表等编码后发送给服务提供者
output = new ObjectOutputStream(socket.getOutputStream());
output.writeUTF(serviceInterface.getName());
output.writeUTF(method.getName());
output.writeObject(method.getParameterTypes());
output.writeObject(args);
// 同步阻塞等待服务器返回应答,获取应答后返回
input = new ObjectInputStream(socket.getInputStream());
return input.readObject();
} finally {
if (socket != null) {
socket.close();
}
if (output != null) {
output.close();
}
if (input != null) {
input.close();
}
}
}
}
}

本地接口

package com.peiyu.rpcs.bios;

public interface IOrderService {
String getOrderDtoByUserId(int i); }

总结与注意点:

1:output.writeUTF(serviceInterface.getName());这里面是 包名+接口名

2:这个是网上的代码,有些问题,注册中心serviceRegistry = new HashMap<String, Class>();写在了服务端,应该是客户端拉取才对,是不是客户端传output.writeUTF(com.peiyu.rpcs.bios.IOrderServiceImpl);才对呢?我想是,待考证(错误)

3.这个RPC如果不用serviceRegistry 映射,则需要通过接口找到实现类,这个就很麻烦

补充: 从注册中心拉取的是

//从ZK中获取地址 127.0.0.1:12345
String discover = serviceDiscovery.discover(rpcRequest.getClassName());

 客户端拉取的是ip地址+端口号,比如说俩个服务,zookeeper存储接口名和地址,

192.168.126.166:20880 和192.168.166.188:20880, 客户端选择一个ip地址就实现了负载均衡,这样客户端还还是向其中一个服务发送端口,服务的从Map<接口,实现类.Class>来get一个impl.整个思想就完成了

                                               atzhang

手写RPC的更多相关文章

  1. 手写RPC框架指北另送贴心注释代码一套

    Angular8正式发布了,Java13再过几个月也要发布了,技术迭代这么快,框架的复杂度越来越大,但是原理是基本不变的.所以沉下心看清代码本质很重要,这次给大家带来的是手写RPC框架. 完整代码以及 ...

  2. 看了这篇你就会手写RPC框架了

    一.学习本文你能学到什么? RPC的概念及运作流程 RPC协议及RPC框架的概念 Netty的基本使用 Java序列化及反序列化技术 Zookeeper的基本使用(注册中心) 自定义注解实现特殊业务逻 ...

  3. java 从零开始手写 RPC (03) 如何实现客户端调用服务端?

    说明 java 从零开始手写 RPC (01) 基于 socket 实现 java 从零开始手写 RPC (02)-netty4 实现客户端和服务端 写完了客户端和服务端,那么如何实现客户端和服务端的 ...

  4. java 从零开始手写 RPC (04) -序列化

    序列化 java 从零开始手写 RPC (01) 基于 socket 实现 java 从零开始手写 RPC (02)-netty4 实现客户端和服务端 java 从零开始手写 RPC (03) 如何实 ...

  5. java 从零开始手写 RPC (05) reflect 反射实现通用调用之服务端

    通用调用 java 从零开始手写 RPC (01) 基于 socket 实现 java 从零开始手写 RPC (02)-netty4 实现客户端和服务端 java 从零开始手写 RPC (03) 如何 ...

  6. java 从零开始手写 RPC (07)-timeout 超时处理

    <过时不候> 最漫长的莫过于等待 我们不可能永远等一个人 就像请求 永远等待响应 超时处理 java 从零开始手写 RPC (01) 基于 socket 实现 java 从零开始手写 RP ...

  7. 手写RPC框架(六)整合Netty

    手写RPC框架(六)整合Netty Netty简介: Netty是一个基于NIO的,提供异步,事件驱动的网络应用工具,具有高性能高可靠性等特点. 使用传统的Socket来进行网络通信,服务端每一个连接 ...

  8. 基于netty手写RPC框架

    代码目录结构 rpc-common存放公共类 rpc-interface为rpc调用方需要调用的接口 rpc-register提供服务的注册与发现 rpc-client为rpc调用方底层实现 rpc- ...

  9. 手写RPC框架(netty+zookeeper)

    RPC是什么?远程过程调用,过程就是业务处理.计算任务,像调用本地方法一样调用远程的过程. RMI和RPC的区别是什么?RMI是远程方法调用,是oop领域中RPC的一种实现,我们熟悉的restfull ...

随机推荐

  1. 【Azure 机器人】微软Azure Bot 编辑器系列(6) : 添加LUIS,理解自然语言 (The Bot Framework Composer tutorials)

    欢迎来到微软机器人编辑器使用教程,从这里开始,创建一个简单的机器人. 在该系列文章中,每一篇都将通过添加更多的功能来构建机器人.当完成教程中的全部内容后,你将成功的创建一个天气机器人(Weather ...

  2. StackOverflow上面 7个最好的Java答案

    StackOverflow发展到目前,已经成为了全球开发者的金矿.它能够帮助我们找到在各个领域遇到的问题的最有用的解决方案,同时我们也会从中学习到很多新的东西.这篇文章是在我们审阅了StackOver ...

  3. Luatools v2烧录教程(适用于2G、4G Cat.1、4G Cat.4模块)

    目录,可以根据需要直接点击跳转: 下载LuaTools工具 2G模块烧写教程(Air2xx系列.Air8xx系列) 连接模块 刷入AT版本的lod 刷入任意的lod固件 下载lua脚本文件 [4G 模 ...

  4. 【模拟7.22】visit(卢卡斯定理&&中国剩余定理)

    如此显然的组合数我把它当DP做,我真是.... 因为起点终点已经确定,我们发现如果我们确定了一个方向的步数其他方向也就确定了 组合数做法1: 设向右走了a步,然后向左走了b=a-n步,设向上为c,向下 ...

  5. 源码学习之void 0

    今天看源码的时候看到 void 0 这样的写法,平时在业务代码里基本没有这样的写法,于是学习了一下. 在控制台运行了一下void 0,得到返回值是undefined. 在MDN上搜了一下void,了解 ...

  6. 理解vertical-align

    vertical-align 支持的属性值及组成 inherit 线类baseline, top, middle, bottom 文本类text-top, text-bottom 上标下标类sub, ...

  7. js笔记8

    1.js数据类型 基本数据类型:string.undefined.null.boolean.nember 引用数据类型:object.array.function 二者的区别? 基本的数据类型就是简单 ...

  8. 虚拟机安装Windows7旗舰版-超详细图文

    虚拟机安装Windows7旗舰版 ----就是想弄一个自己用的CTF+渗透测试的工具集成系统,本来想着用真实机弄就好了,但还是出于安全的考虑,还是再装个虚拟机吧~ 1.先到MSDN找好安装包:http ...

  9. Pytest学习笔记9-失败重跑

    前言 在进行自动化测试的过程中,我们一定会有这样的需求:希望失败的用例可以自动重跑 在pytest中,提供了pytest-rerunfailures插件可以实现自动重跑的效果 插件安装 pip命令安装 ...

  10. 7.8、如何制作openstack镜像

    1.创建openstack-linux镜像: 下载已经做好的的镜像:https://docs.openstack.org/image-guide/obtain-images.html#centos ( ...