RPC簡述


  提問:什麼是RPC?

  PRC是一種遠程過程調用框架,相比遠程調用,我們可以先理解本地調用,本地調用就是方法A和方法B都寫在同一個工程中,然後A可以調用B。但是如果A方法和B方法是屬於不同工程中,則需要進行遠程調用。

  誤解:如A工程中需要調用B工程中的方法,一般是將B工程打一個包,然後A中會引入這個包,然後就可以調用到B中的方法了,這種兩個工程間沒有網絡通信則只能稱爲遠程方法的引用,只有兩個工程存在網絡通信,A調用B的方法並且是B處理後返回給A,才能稱爲遠程過程調用!!

  RPC遠程調用原理

  一、RPC是怎麼做到遠程調用的,其原理是什麼?

  追根究底,R客戶端與服務端建立TCP鏈接,相比於HTTP通信協議少去應用層的許多東西。數據的傳輸就是通過這個TCP的鏈接。

  


  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()方法!!!



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章