提问:什么是RPC?

  PRC是一种远程过程调用框架,相比远程调用,我们可以先理解本地调用,本地调用就是方法A和方法B都写在同一个工程中,然后A可以调用B。但是如果A方法和B方法是属于不同工程中,则需要进行远程调用。

  误解:如A工程中需要调用B工程中的方法,一般是将B工程打一个包,然后A中会引入这个包,然后就可以调用到B中的方法了,这种两个工程间没有网络通信则只能称为远程方法的引用,只有两个工程存在网络通信,A调用B的方法并且是B处理后返回给A,才能称为远程过程调用!!

  RPC远程调用原理

  一、RPC是怎么做到远程调用的,其原理是什么?

  追根究底,R客户端与服务端建立TCP链接,相比于HTTP通信协议少去应用层的许多东西。数据的传输就是通过这个TCP的链接。

  

RPC简述_第1张图片


  Client:服务消费方

  Server:服务提供方

  (1).Client以调用本地服务方式调用远程API

  (2).Client Stub负责接收参数,方法等,将其封装(编码)成能够进行网络传输的消息体

  (3).Client Stub负责网络寻址,将消息体发送对应的服务端

  (4).Server Stub负责接收消息,并解码成服务端能够识别的信息,调用对应的服务端方法

  (5).Server本地服务将调用结果发送给Server Stub

  (6).Server Stub将返回结果包装成消息体返回给Client Stub

  (7).Client Stub接收消息并进行解码

  (8).Client获取到最终调用结果

  二、实例运行

  举例:实现两个本地工程之间的远程调用,如下是RpcProvider工程的代码

  public interface BatterCakeService {

  public String sellBatterCake(String name);

  }

  public class BatterCakeServiceImpl implements BatterCakeService{

  public String sellBatterCake(String name) {

  return name+"味道很赞";

  }

  }

  public class RpcProvider {

  //存储注册的服务列表

  private static List serviceList;

  /**

  * 发布rpc服务

  * @param

  * @param port

  * @throws Exception

  */

  public static void export(int port,Object... services) throws Exception {

  serviceList= Arrays.asList(services);

  //创建本地服务,端口20006

  ServerSocket server = new ServerSocket(port);

  Socket client = null;

  while (true) {

  //阻塞等待输入,一直监听,如果有服务请求,则返回,否则一直等待

  client = server.accept();

  //每一个请求,启动一个线程处理

  new Thread(new ServerThread(client,serviceList)).start();

  }

  }

  }

  public class ServerThread implements Runnable {

  private Socket client=null;

  private List serviceList=null;

  public ServerThread(Socket client,List service)

  {

  this.client=client;

  this.serviceList=service;

  }

  @Override

  public void run() {

  ObjectInputStream input=null;

  ObjectOutputStream output=null;

  try {

  //创建请求服务的输入输出流

  input=new ObjectInputStream(client.getInputStream());

  output=new ObjectOutputStream(client.getOutputStream());

  // 读取客户端要访问那个service

  Class serviceClass = (Class)input.readObject();

  // 找到该服务类

  Object obj = findService(serviceClass);

  if(obj==null)

  {

  output.writeObject(serviceClass.getName() + "服务未发现");

  }else {

  String methodName = input.readUTF();

  Class[] parameterTypes = (Class[]) input.readObject();

  Object[] arguments = (Object[]) input.readObject();

  Method method = obj.getClass().getMethod(methodName, parameterTypes);

  Object result = method.invoke(obj, arguments);

  output.writeObject(result);

  }

  } catch (Exception e) {

  e.printStackTrace();

  } finally {

  try {

  client.close();

  input.close();

  output.close();

  } catch (IOException e) {

  e.printStackTrace();

  }

  }

  }

  private Object findService(Class serviceClass) {

  // TODO Auto-generated method stub

  for (Object obj : serviceList) {

  boolean isFather = serviceClass.isAssignableFrom(obj.getClass());

  if (isFather) {

  return obj;

  }

  }

  return null;

  }

  }

  主函数:

  public class RpcBootStrap {

  public static void main(String[] args) throws Exception {

  BatterCakeService batterCakeService =new BatterCakeServiceImpl();

  //发布卖煎饼的服务,注册在20006端口

  RpcProvider.export(20006,batterCakeService);

  }

  }

  运行主函数,保持服务提供方的监听

  服务消费方consumer代码:consumer中会调用provider中的sellBatterCake(String name)方法,可以从如下看出,consumer中并没有sellBatterCake(String name)方法的实现

  public interface BatterCakeService {

  public String sellBatterCake(String name);

  }

  public class ProxyHandler implements InvocationHandler {

  private String ip;

  private int port;

  public ProxyHandler(String ip, int port) {

  // TODO Auto-generated constructor stub

  this.ip = ip;

  this.port = port;

  }

  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

  Socket socket = new Socket(this.ip, this.port);

  ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());

  ObjectInputStream input = new ObjectInputStream(socket.getInputStream());

  try {

  output.writeObject(proxy.getClass().getInterfaces()[0]);

  output.writeUTF(method.getName());

  output.writeObject(method.getParameterTypes());

  output.writeObject(args);

  output.flush();

  Object result = input.readObject();

  if(result instanceof Throwable) {

  throw (Throwable) result;

  }

  return result;

  } finally {

  socket.shutdownOutput();

  }

  }

  }

  public class RpcConsumer {

  public staticT getService(Classclazz,String ip,int port) {

  ProxyHandler proxyHandler =new ProxyHandler(ip,port);

  return (T) Proxy.newProxyInstance(RpcConsumer.class.getClassLoader(), new Class[] {clazz}, proxyHandler);

  }

  }

  public class RpcTest {

  public static void main(String[] args) {

  BatterCakeService batterCakeService=RpcConsumer.getService(BatterCakeService.class, "127.0.0.1", 20006);

  String result=batterCakeService.sellBatterCake("双蛋");

  System.out.println(result);

  }郑州人流医院那家好:http://www.zztj120.com/

  }

  运行consumer中的主函数:

  


  上述可以看出是consumer远程调用了provider中的sellBatterCake()方法!!!