TCP協議的RPC使用範例

一. RPC調用過程

RPC 調用流程圖

  1. 服務客戶端(Client)調用以本地調用方式調用服務
  2. Client stub接收到調用後負責將方法、參數等組裝成能夠進行網路傳輸的消息,并將消息發送到服務伺服端(物件序列化)
  3. Server stub收到消息後進行解碼(物件反序列化)
  4. Server stub根據解碼結果調用本地的服務
  5. 本地服務執行並將結果返回給Server stub
  6. Server stub將返回結果打包成消息并發送至服務客戶端
  7. Client stub接收到消息,並進行解碼
  8. 服務客戶端得到最終結果

二. 範例代碼

基於Java的Socket API實現一個簡單的RPC調用範例。範例中包括服務的介面、介面的實作、服務的伺服端和服務的客戶端。

服務介面 SayHelloService.java

public interface SayHelloService {
    public String sayHello(String msg);
}

服務介面實作 SayHelloServiceImpl.java

public class SayHelloServiceImpl implements SayHelloService {
    @Override
    public String sayHello(String msg) {
        if("hello".equals(msg)) {
            return "hello client";
        } else {
            return "bye bye";
        }
    }
}

服務伺服端 Provider.java

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

public class Provider {
    public static void main(String[] args) throws Exception {
        ServerSocket serverSocket = new ServerSocket(1234);
        Map services = new HashMap();
        services.put(SayHelloService.class, new SayHelloServiceImpl());
        while(true){
            System.out.println("服務伺服端啟動,等待客戶端調用…………");
            Socket socket = serverSocket.accept();

            //收到消息後進行解碼
            ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
            String interfaceName = objectInputStream.readUTF();
            System.out.println("interfaceName:"+interfaceName);
            String methodName = objectInputStream.readUTF();
            System.out.println("methodName:"+methodName);
            Class[] paramterTypes = (Class[])objectInputStream.readObject();
            Object[] argments = (Object[])objectInputStream.readObject();
            System.out.println("客戶端調用服務端接口"+interfaceName+"的"+ methodName+"方法");

            //根據解碼結果調用本地的服務
            Class serviceClass = Class.forName(interfaceName);
            Object serivce = services.get(serviceClass);
            Method method = serviceClass.getMethod(methodName, paramterTypes);
            Object result = method.invoke(serivce, argments);

            //服務伺服端發送結果給服務客戶端
            ObjectOutputStream stream = new ObjectOutputStream(socket.getOutputStream());
            stream.writeObject(result);
            System.out.println("服務伺服端返回結果為"+result);
        }
    }
}

服務客戶端 Consumer.java 

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.net.Socket;

public class Consumer {
    public static void main(String[] args) throws Exception {
        String interfaceName = SayHelloService.class.getName();
        Method method = SayHelloService.class.getMethod("sayHello", java.lang.String.class);
        Object[] argments = {"hello"};

        Socket socket = new Socket("127.0.0.1", 1234);
        ObjectOutputStream outputStream = new ObjectOutputStream(socket.getOutputStream());
        outputStream.writeUTF(interfaceName);
        outputStream.writeUTF(method.getName());
        outputStream.writeObject(method.getParameterTypes());
        outputStream.writeObject(argments);
        System.out.println("發送信息到服務伺服端,發送的信息為:"+argments[0]);

        ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream());
        Object object = inputStream.readObject();
        System.out.println("服務伺服端返回的結果為" + object);
    }
}

程式碼放在Github卜,請到(https://github.com/vvtitana/RPCDemo)下載。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

*

驗證碼 * Time limit is exhausted. Please reload CAPTCHA.

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料