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. 解决高版本vm打开虚拟机报错

    问题: 打开虚拟机的文件目录,找到.vmx 文件 用记事本打开重命名后的“.vmx.txt”文件 找到行:policy.vm.mvmtid = "52 10 08 ed ff 34 ed d ...

  2. JS由Number与new Number的区别引发的思考

    在回答园子问题的时候发现了不少新东西,写下来分享一下 == 下面的图就是此篇的概览,另外文章的解释不包括ES6新增的Symbol,话说这货有包装类型,但是不能new... 基于JS是面向对象的,所以我 ...

  3. vue之filter用法

    1.全局写法: 全局过滤器必须写在vue实例创建之前. Vue.filter('testfilter', function (value,text) { // 返回处理后的值 return value ...

  4. 紫书 例题 10-18 UVa 11346(连续概率)

    就是面积计算,没什么好说的. #include<cstdio> #include<cmath> #define REP(i, a, b) for(int i = (a); i ...

  5. 【Henu ACM Round#20 B】Contest

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 根据时间和原分数. 算出对应的分数就可以了. [代码] #include <bits/stdc++.h> using n ...

  6. 開始EEPlat之旅

    怎样開始EEPlat之旅 EEPlat分为社区版和商业版:功能上分为企业版和PaaS版.下面为社区企业版的開始之旅. 第一步:安装project,有两种:war包和代码project.(眼下googl ...

  7. Linux系统编程——进程间通信:信号中断处理

    什么是信号? 信号是 Linux 进程间通信的最古老的方式.信号是url=474nN303T2Oe2ehYZjkrggeXCaJPDSrmM5Unoh4TTuty4wSgS0nl4-vl43AGMFb ...

  8. HDU44979 GCD and LCM (素因子分解+计数)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4497 题意: 求有多少种(x,y,z)使得最小公倍数为l,最大公约数为g 分析: 我们将l,g进行素因 ...

  9. vue2.0-transition配合animate.css

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. VS链接数据库

    可以用VS链接数据库,并进行数据库操作.前提是安装了Sqlserver,活着连接线上的数据库服务器.