0.RPC简介

  RPC,   英文全称:Remote Process Call.   中文全称:远程过程调用.

  客户端通过网络请求调用远程服务端对外暴露服务。常用的两种RPC协议:TCP、HTTP。

  举例描述:两台服务器A,B,一个应用部署在A服务器上,想要调用B服务器上应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。

  最简单的场景:通过百度搜索所需要的信息。

  当我们在百度的搜索栏中填入所需要查找的信息时,浏览器客户端会创建一个网络请求,将所要查询的信息标识传给百度的远程服务器端。服务器得到请求之后,调用自身内部的处理操作,再将查询到的信息返回给浏览器,浏览器解析展示给用户。

1.RPC的优缺点

  优点:

    a) 解决单应用的性能瓶颈。

    b) 实现应用之间的解耦,服务拆分。

    c)  提升功能代码的复用性。

  缺点:

    a) 网络交互

    b) 增加应用的复杂性

2.RPC实现流程

  • 首先,要解决通讯的问题,主要是通过在客户端和服务器之间建立TCP连接,远程过程调用的所有交换的数据都在这个连接里传输。连接可以是按需连接,调用结束后就断掉,也可以是长连接,多个远程过程调用共享同一个连接。
  • 第二,要解决寻址的问题,也就是说,A服务器上的应用怎么告诉底层的RPC框架,如何连接到B服务器(如主机或IP地址)以及特定的端口,方法的名称名称是什么,这样才能完成调用。比如基于Web服务协议栈的RPC,就要提供一个endpoint URI,或者是从UDDI服务上查找。如果是RMI调用的话,还需要一个RMI Registry来注册服务的地址。
  • 第三,当A服务器上的应用发起远程过程调用时,方法的参数需要通过底层的网络协议如TCP传递到B服务器,由于网络协议是基于二进制的,内存中的参数的值要序列化成二进制的形式,也就是序列化(Serialize)或编组(marshal),通过寻址和传输将序列化的二进制发送给B服务器。
  • 第四,B服务器收到请求后,需要对参数进行反序列化(序列化的逆操作),恢复为内存中的表达方式,然后找到对应的方法(寻址的一部分)进行本地调用,然后得到返回值。
  • 第五,返回值还要发送回服务器A上的应用,也要经过序列化的方式发送,服务器A接到后,再反序列化,恢复为内存中的表达方式,交给A服务器上的应用

  

3.Code实现

  定义接口:

/**
* Rpc接口
*
* @author apple
*/
public interface HelloService { String hello(String str); }

  接口实现:

public class HelloServiceImpl implements HelloService {

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

  RPC服务端:

public class RpcExporter {

    static Executor executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

    public static void exporter(String hostName,int port) throws Exception{

        ServerSocket server = new ServerSocket();

        server.bind(new InetSocketAddress(hostName, port));

        try{
while(true){
executor.execute(new ExporterTask(server.accept()));
}
}finally{
server.close();
} } private static class ExporterTask implements Runnable{ Socket client = null; public ExporterTask(Socket client){
this.client = client;
} @Override
public void run() { ObjectInputStream input = null;
ObjectOutputStream output = null; try {
input = new ObjectInputStream(client.getInputStream());
String interfaceName = input.readUTF();
Class<?> service = Class.forName(interfaceName);
String methodName = input.readUTF();
Class<?>[] parameterTypes = (Class<?>[])input.readObject();
Object[] arguments = (Object[])input.readObject();
Method method = service.getMethod(methodName, parameterTypes);
Object result = method.invoke(service.newInstance(),arguments);
output = new ObjectOutputStream(client.getOutputStream());
output.writeObject(result);
} catch (Exception e) {
e.printStackTrace();
}finally {
if(output != null){
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}finally{
output = null;
}
}
if(input != null){
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}finally{
input = null;
}
}
if(client != null){
try {
client.close();
} catch (IOException e) {
e.printStackTrace();
}finally{
input = null;
}
}
} } } }

  RPC客户端:

public class RpcImporter<S> {

    @SuppressWarnings("unchecked")
public S importer(final Class<?> serviceClass,final InetSocketAddress addr){ return (S) Proxy.newProxyInstance(serviceClass.getClassLoader(), new Class<?>[]{serviceClass.getInterfaces()[]}, new InvocationHandler() { @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Socket socket = null;
ObjectOutputStream output = null;
ObjectInputStream input = null; try{
socket = new Socket();
socket.connect(addr);
output = new ObjectOutputStream(socket.getOutputStream());
output.writeUTF(serviceClass.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();
}
}
});
} }

  测试类:

public class RpcTest {

    public static void main(String[] args) {

        new Thread(new Runnable() {

            @Override
public void run() { try {
RpcExporter.exporter("localhost", );
} catch (Exception e) {
e.printStackTrace();
} } }).start(); RpcImporter<HelloService> importer = new RpcImporter<HelloService>();
HelloService service = importer.importer(HelloServiceImpl.class, new InetSocketAddress("localhost", ));
while(true){
System.out.println(service.hello("word"));
try {
Thread.sleep();
} catch (InterruptedException e) {
e.printStackTrace();
}
} } }

  执行结果:

4.常用的RPC框架

  

  Java RMI

  Web Service

  Hessian

  Thrift

  Http Rest API

  Dubbo

5.参考资料

  

  谁能用通俗的语言解释一下什么是 RPC 框架?

https://www.zhihu.com/question/25536695

RPC简易学习的更多相关文章

  1. TensorFlow简易学习[3]:实现神经网络

    TensorFlow本身是分布式机器学习框架,所以是基于深度学习的,前一篇TensorFlow简易学习[2]:实现线性回归对只一般算法的举例只是为说明TensorFlow的广泛性.本文将通过示例Ten ...

  2. 基于Netty的RPC简易实现

    代码地址如下:http://www.demodashi.com/demo/13448.html 可以给你提供思路 也可以让你学到Netty相关的知识 当然,这只是一种实现方式 需求 看下图,其实这个项 ...

  3. 微软RPC技术学习小结

    RPC,即Remote Procedure Call,远程过程调用,是进程间通信(IPC, Inter Process Communication)技术的一种.由于这项技术在自己所在项目(Window ...

  4. HTML DOM简易学习笔记

    文字版:https://github.com/songzhenhua/github/blob/master/HTML DOM简易学习笔记.txt 学习地址:http://www.w3school.co ...

  5. JavaScript简易学习笔记

    学习地址:http://www.w3school.com.cn/js/index.asp 文字版: https://github.com/songzhenhua/github/blob/master/ ...

  6. HTML简易学习笔记

    文字版地址 https://github.com/songzhenhua/github/blob/master/HTML简易学习笔记.txt

  7. 简易RPC框架-学习使用

    *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...

  8. rpc简易实现-zookeeper

    一.RPC(Remote Procedure Call)—远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议.RPC协议假定某些传输协议的存在,如TCP或UDP, ...

  9. Dubbo简易学习

    0.  Dubbo简易介绍 DUBBO是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,是阿里巴巴SOA服务化治理方案的核心框架,每天为2,000+个服务提供3,000,000, ...

随机推荐

  1. 最短路径—Dijkstra 算法和Floyd 算法

    某省自从实行了很多年的畅通工程计划后,终于修建了很多路.不过路多了也不好,每次要从一个城镇到另一个城镇时,都有许多种道路方案可以选择,而某些方案要比另一些方案行走的距离要短很多.这让行人很困扰. 现在 ...

  2. 在angular4.X里使用mCustomScrollbar滚动条插件

    参考网上的方法https://stackoverflow.com/questions/36755625/how-to-import-jquery-and-mcustomscrollbar-plugin ...

  3. 洛谷——P1966 火柴排队

    https://www.luogu.org/problem/show?pid=1966 题目描述 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度. 现在将每盒中的火柴各自排成一列, 同一列 ...

  4. 零基础学python-3.3 标识符

    1.标识符的组成 1)有数字.下划线.英文字母组成 2)第一个字符仅仅能是字母或者下划线 3)大写和小写敏感 标识符通常是变量名称.方法名.类名等 2.keyword python里面有一系列的关键字 ...

  5. tp5框架知识点

    项目包含的关键点,后台,前台. 入口文件. 通用配置文件. 数据库配置文件. 共有文件,css,images,js. 控制器,模型,视图. 共有类. 共有函数. 属性,方法. 命名规范. 命名空间. ...

  6. LINQ查询基础

    一.什么是LINQ LINQ是Language Integrate Query的缩写,意为语言集成查询,是微软在.Net Framework 4.5版中推出的主要特性之一. 它为开发人员提供了统一的数 ...

  7. 异步Ajax

    Ajax异步刷新应用在Web开发中经常用到,在过去WebForm中通常是使用JQuery和一般处理程序或者aspx页面来实现: 在MVC中,虽然依然可以使用一般处理程序,但是一般还是通过在Contro ...

  8. POJ 3271 BFS (大坑)

    被某人拉进了坑 完完全全被坑一天的题-- 题意: 正解思路: 先把每一个点搜一遍 预处理出它能在一步之内到的所有点 并连边 然后用一个类似DP的东西把方案数加起来就搞定了 (其实 也不是很难) 但是 ...

  9. JAVA文件读取FileReader

    JAVA文件读取FileReader 导包import java.io.FileReader 创建构造方法public FileReader(String filename),参数是文件的路径及文件名 ...

  10. 【Henu ACM Round#16 B】 Bear and Colors

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] O(n^2)枚举每一个区间. 然后维护这个区间里面的"统治数字"是什么. 对于每个区间cnt[统治数字]++; ...