RPC(Remote Procedure Call Protocol)

1.定义

RPC:Remote Procedure Call protocol,远程过程调用协议,通俗来讲即两台服务器A,B,一个应用部署在A服务器上,想要调用B服务器上应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。

2.要解决的问题

正如定义所述,RPC从本质上来讲,只是一种网络通信,由于互联网的高速发展,同一台机器之间需要进行进程之间的通信,然后不同机器之间的进程也需要通信,RPC要解决的问题就是这个,RPC是分布式、集群的基础吧。

3.如何实现

引用如下的图,来说明RPC的实现原理
PicMissing
从分层的角度来看,个人觉得RPC涉及到了应用层和传输层,这个图例一眼就能看懂,无需多言,如果要自己实现一个这样的框架,应该考虑哪些问题呢?

(A)在Server和Client之间建立TCP通信连接,可以是按需连接,也可以是长连接。

(B)Client如何找到Server,既然是通信,总需要一些向IP、Port之类的东西,还有与Server端的哪个进程的哪个方法通信等问题。

(C)方法的参数传递方式,Client需要把所谓的实参通过网络传递给Server端,就要涉及将内存中的值序列化成二进制的值。

(D)Server收到后需要进行反序列化,然后进行本地调用,得到返回值。

(E)Server将返回值序列化成二进制序列传输给Client,Client进行反序列化即可。

4.框架

RPC只是一个概念,当然有很多组织和企业用自己的方法实现,实现出来的结果就是所谓的框架,搜索了一下,主要有CORBA(Common Object Request Broker Architecture,通用对象请求代理体系结构)、JAVA RMI(Remote Method Invocation,远程方法调用)和Thrift(FB开源框架)等等。

5.实现

在4.框架中提到了Java的RPC,即RMI,由于我也是Java新手,所以就大体找了个HelloWorld试了试,转自熔岩,代码如下:
首先定义接口:IHello

1
2
3
4
5
6
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface IHello extends Remote{
public String helloWorld() throws RemoteException;
public String sayHelloToSomeBody(String someBodyName) throws RemoteException;
}

然后是服务器端的实现HelloImpl

1
2
3
4
5
6
7
8
9
10
11
12
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class HelloImpl extends UnicastRemoteObject implements IHello{
public HelloImpl() throws RemoteException{}
public String helloWorld() throws RemoteException{
return "HelloWorld!";
}
public String sayHelloToSomeBody(String someBodyName) throws RemoteException{
return "Hello "+someBodyName+"!";
}
}

然后是服务器端的HelloServer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<pre><code>
import java.rmi.Remote;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.AlreadyBoundException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.net.MalformedURLException;
public class HelloServer{
public static void main(String[] args) {
try{
IHello rhello=new HelloImpl();
LocateRegistry.createRegistry(8888);
Naming.bind("rmi://localhost:8888/RHello",rhello);
System.out.println("INFO:Bingding Remote Object IHello Successfully!");
}
catch(RemoteException e){
System.out.println("Creating Remote Object Exception");
}
catch(AlreadyBoundException e){
System.out.println("AlreadyBoundException");
}
catch(MalformedURLException e){
System.out.println("MalformedURLException");
}
}
}

到此可以运行起来Server端,就不上图了,很简单。

最后是客户端的HelloClient

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import java.rmi.Remote;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.AlreadyBoundException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.net.MalformedURLException;
import java.rmi.NotBoundException;
public class HelloClient{
public static void main(String args[]){
try{
IHello rhello=(IHello)Naming.lookup("rmi://localhost:8888/RHello");
System.out.println(rhello.helloWorld());
System.out.println(rhello.sayHelloToSomeBody("LiuQiang"));
}
catch(NotBoundException e){
e.printStackTrace();
}
catch(MalformedURLException e){
e.printStackTrace();
}
catch(RemoteException e){
e.printStackTrace();
}
}
}

最后上一张图:
PicMissing
打算如果有时间,试试facebook的RPC:Thrift。